diff mbox series

e1000: fix tx re-entrancy problem

Message ID 20211021161047.578751-1-jmaloy@redhat.com (mailing list archive)
State New, archived
Headers show
Series e1000: fix tx re-entrancy problem | expand

Commit Message

Jon Maloy Oct. 21, 2021, 4:10 p.m. UTC
The fact that the MMIO handler is not re-entrant causes an infinite
loop under certain conditions:

Guest write to TDT ->  Loopback -> RX (DMA to TDT) -> TX

We now eliminate the effect of this problem locally in e1000, by adding
a boolean in struct E1000State indicating when the TX side is busy. This
will cause any entering new call to return early instead of interfering
with the ongoing work, and eliminates any risk of looping.

This is intended to address CVE-2021-20257.

Signed-off-by: Jon Maloy <jmaloy@redhat.com>
---
 hw/net/e1000.c | 7 +++++++
 1 file changed, 7 insertions(+)

Comments

Jason Wang Oct. 27, 2021, 4:40 a.m. UTC | #1
在 2021/10/22 上午12:10, Jon Maloy 写道:
> The fact that the MMIO handler is not re-entrant causes an infinite
> loop under certain conditions:
>
> Guest write to TDT ->  Loopback -> RX (DMA to TDT) -> TX
>
> We now eliminate the effect of this problem locally in e1000, by adding
> a boolean in struct E1000State indicating when the TX side is busy. This
> will cause any entering new call to return early instead of interfering
> with the ongoing work, and eliminates any risk of looping.
>
> This is intended to address CVE-2021-20257.
>
> Signed-off-by: Jon Maloy <jmaloy@redhat.com>


Applied.

Thanks


> ---
>   hw/net/e1000.c | 7 +++++++
>   1 file changed, 7 insertions(+)
>
> diff --git a/hw/net/e1000.c b/hw/net/e1000.c
> index a30546c5d5..f5bc81296d 100644
> --- a/hw/net/e1000.c
> +++ b/hw/net/e1000.c
> @@ -107,6 +107,7 @@ struct E1000State_st {
>           e1000x_txd_props props;
>           e1000x_txd_props tso_props;
>           uint16_t tso_frames;
> +        bool busy;
>       } tx;
>   
>       struct {
> @@ -763,6 +764,11 @@ start_xmit(E1000State *s)
>           return;
>       }
>   
> +    if (s->tx.busy) {
> +        return;
> +    }
> +    s->tx.busy = true;
> +
>       while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
>           base = tx_desc_base(s) +
>                  sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
> @@ -789,6 +795,7 @@ start_xmit(E1000State *s)
>               break;
>           }
>       }
> +    s->tx.busy = false;
>       set_ics(s, 0, cause);
>   }
>
Philippe Mathieu-Daudé Dec. 16, 2021, 9:36 a.m. UTC | #2
Hi Jon,

On 10/21/21 18:10, Jon Maloy wrote:
> The fact that the MMIO handler is not re-entrant causes an infinite
> loop under certain conditions:
> 
> Guest write to TDT ->  Loopback -> RX (DMA to TDT) -> TX
> 
> We now eliminate the effect of this problem locally in e1000, by adding
> a boolean in struct E1000State indicating when the TX side is busy. This
> will cause any entering new call to return early instead of interfering
> with the ongoing work, and eliminates any risk of looping.
> 
> This is intended to address CVE-2021-20257.
> 
> Signed-off-by: Jon Maloy <jmaloy@redhat.com>
> ---
>  hw/net/e1000.c | 7 +++++++
>  1 file changed, 7 insertions(+)

I can not find the reproducer in the repository, have you sent one?
Jon Maloy Dec. 16, 2021, 3:51 p.m. UTC | #3
On 12/16/21 04:36, Philippe Mathieu-Daudé wrote:
> Hi Jon,
>
> On 10/21/21 18:10, Jon Maloy wrote:
>> The fact that the MMIO handler is not re-entrant causes an infinite
>> loop under certain conditions:
>>
>> Guest write to TDT ->  Loopback -> RX (DMA to TDT) -> TX
>>
>> We now eliminate the effect of this problem locally in e1000, by adding
>> a boolean in struct E1000State indicating when the TX side is busy. This
>> will cause any entering new call to return early instead of interfering
>> with the ongoing work, and eliminates any risk of looping.
>>
>> This is intended to address CVE-2021-20257.
>>
>> Signed-off-by: Jon Maloy <jmaloy@redhat.com>
>> ---
>>   hw/net/e1000.c | 7 +++++++
>>   1 file changed, 7 insertions(+)
> I can not find the reproducer in the repository, have you sent one?
>
No, I did not add it to the repo.
It was referenced from the tracker BZ, but I was unable to get access 
back then.
It ended up with that I had it sent by mail to me directly.

What is your question? Is it that it should be in the repo, or that you 
cannot find it?

///jon
Philippe Mathieu-Daudé Dec. 16, 2021, 6:35 p.m. UTC | #4
On 12/16/21 16:51, Jon Maloy wrote:
> On 12/16/21 04:36, Philippe Mathieu-Daudé wrote:
>> Hi Jon,
>>
>> On 10/21/21 18:10, Jon Maloy wrote:
>>> The fact that the MMIO handler is not re-entrant causes an infinite
>>> loop under certain conditions:
>>>
>>> Guest write to TDT ->  Loopback -> RX (DMA to TDT) -> TX
>>>
>>> We now eliminate the effect of this problem locally in e1000, by adding
>>> a boolean in struct E1000State indicating when the TX side is busy. This
>>> will cause any entering new call to return early instead of interfering
>>> with the ongoing work, and eliminates any risk of looping.
>>>
>>> This is intended to address CVE-2021-20257.
>>>
>>> Signed-off-by: Jon Maloy <jmaloy@redhat.com>
>>> ---
>>>   hw/net/e1000.c | 7 +++++++
>>>   1 file changed, 7 insertions(+)
>> I can not find the reproducer in the repository, have you sent one?
>>
> No, I did not add it to the repo.
> It was referenced from the tracker BZ, but I was unable to get access
> back then.
> It ended up with that I had it sent by mail to me directly.
> 
> What is your question? Is it that it should be in the repo, or that you
> cannot find it?

Well I'd like to reproduce the bug, but first I can not find it ;)
Having such reproducer committed along with the fix help catching
future regressions if we refactor code elsewhere.
Alexander Bulekov Dec. 16, 2021, 7:01 p.m. UTC | #5
On 211216 1935, Philippe Mathieu-Daudé wrote:
> On 12/16/21 16:51, Jon Maloy wrote:
> > On 12/16/21 04:36, Philippe Mathieu-Daudé wrote:
> >> Hi Jon,
> >>
> >> On 10/21/21 18:10, Jon Maloy wrote:
> >>> The fact that the MMIO handler is not re-entrant causes an infinite
> >>> loop under certain conditions:
> >>>
> >>> Guest write to TDT ->  Loopback -> RX (DMA to TDT) -> TX
> >>>
> >>> We now eliminate the effect of this problem locally in e1000, by adding
> >>> a boolean in struct E1000State indicating when the TX side is busy. This
> >>> will cause any entering new call to return early instead of interfering
> >>> with the ongoing work, and eliminates any risk of looping.
> >>>
> >>> This is intended to address CVE-2021-20257.
> >>>
> >>> Signed-off-by: Jon Maloy <jmaloy@redhat.com>
> >>> ---
> >>>   hw/net/e1000.c | 7 +++++++
> >>>   1 file changed, 7 insertions(+)
> >> I can not find the reproducer in the repository, have you sent one?
> >>
> > No, I did not add it to the repo.
> > It was referenced from the tracker BZ, but I was unable to get access
> > back then.
> > It ended up with that I had it sent by mail to me directly.
> > 
> > What is your question? Is it that it should be in the repo, or that you
> > cannot find it?
> 
> Well I'd like to reproduce the bug, but first I can not find it ;)
> Having such reproducer committed along with the fix help catching
> future regressions if we refactor code elsewhere.
> 

Blind guess, but assuming write to TDT == set_tctl, maybe this one?
https://bugs.launchpad.net/qemu/+bug/1917082
Jon Maloy Dec. 16, 2021, 8:22 p.m. UTC | #6
This was the one I received.

///jon


On 12/16/21 14:01, Alexander Bulekov wrote:
> On 211216 1935, Philippe Mathieu-Daudé wrote:
>> On 12/16/21 16:51, Jon Maloy wrote:
>>> On 12/16/21 04:36, Philippe Mathieu-Daudé wrote:
>>>> Hi Jon,
>>>>
>>>> On 10/21/21 18:10, Jon Maloy wrote:
>>>>> The fact that the MMIO handler is not re-entrant causes an infinite
>>>>> loop under certain conditions:
>>>>>
>>>>> Guest write to TDT ->  Loopback -> RX (DMA to TDT) -> TX
>>>>>
>>>>> We now eliminate the effect of this problem locally in e1000, by adding
>>>>> a boolean in struct E1000State indicating when the TX side is busy. This
>>>>> will cause any entering new call to return early instead of interfering
>>>>> with the ongoing work, and eliminates any risk of looping.
>>>>>
>>>>> This is intended to address CVE-2021-20257.
>>>>>
>>>>> Signed-off-by: Jon Maloy <jmaloy@redhat.com>
>>>>> ---
>>>>>    hw/net/e1000.c | 7 +++++++
>>>>>    1 file changed, 7 insertions(+)
>>>> I can not find the reproducer in the repository, have you sent one?
>>>>
>>> No, I did not add it to the repo.
>>> It was referenced from the tracker BZ, but I was unable to get access
>>> back then.
>>> It ended up with that I had it sent by mail to me directly.
>>>
>>> What is your question? Is it that it should be in the repo, or that you
>>> cannot find it?
>> Well I'd like to reproduce the bug, but first I can not find it ;)
>> Having such reproducer committed along with the fix help catching
>> future regressions if we refactor code elsewhere.
>>
> Blind guess, but assuming write to TDT == set_tctl, maybe this one?
> https://bugs.launchpad.net/qemu/+bug/1917082
>
#!/bin/sh

cat << EOF > inp
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
outl 0xcf8 0x80000813
outl 0xcfc 0xfffffffe
outl 0xcf8 0x80000803
outw 0xcfc 0x66e2
write 0xfe000102 0x1 0xff
clock_step
writel 0xfe000020 0x420ff00
write 0xfe00280a 0x3 0x2828ff
clock_step
clock_step
clock_step
write 0xfe002815 0x4 0x0300ff46
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
clock_step
write 0xf27 0x1 0xff
write 0xf98 0x1 0xd5
write 0xf99 0x1 0xd5
write 0xf9b 0x1 0xd5
write 0x1060 0x1 0x17
write 0x1061 0x1 0x38
write 0x1062 0x3 0x00fe00
writel 0xfe0003ff 0x8e8e8e8e
write 0xfe00380a 0x3 0x525e03
write 0xfe003818 0x1 0xff
EOF

./x86_64-softmmu/qemu-system-x86_64 -display none -machine accel=qtest \
	-m 512M -M q35 -nodefaults -device e1000,netdev=net0 \
	-netdev user,id=net0 -qtest-log none -qtest stdio < inp
diff mbox series

Patch

diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index a30546c5d5..f5bc81296d 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -107,6 +107,7 @@  struct E1000State_st {
         e1000x_txd_props props;
         e1000x_txd_props tso_props;
         uint16_t tso_frames;
+        bool busy;
     } tx;
 
     struct {
@@ -763,6 +764,11 @@  start_xmit(E1000State *s)
         return;
     }
 
+    if (s->tx.busy) {
+        return;
+    }
+    s->tx.busy = true;
+
     while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
         base = tx_desc_base(s) +
                sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
@@ -789,6 +795,7 @@  start_xmit(E1000State *s)
             break;
         }
     }
+    s->tx.busy = false;
     set_ics(s, 0, cause);
 }