qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Jason Wang <jasowang@redhat.com>
To: Li Qiang <liq3ea@gmail.com>, Paolo Bonzini <pbonzini@redhat.com>
Cc: "Prasad J Pandit" <pjp@fedoraproject.org>,
	"Stefan Hajnoczi" <stefanha@gmail.com>,
	"Sven Schnelle" <svens@stackframe.org>,
	"Qemu Developers" <qemu-devel@nongnu.org>,
	"P J P" <ppandit@redhat.com>, "Li Qiang" <pangpei.lq@antfin.com>,
	"Philippe Mathieu-Daudé" <philmd@redhat.com>,
	"Ziming Zhang" <ezrakiez@gmail.com>
Subject: Re: [PATCH v6 1/2] net: tulip: check frame size and r/w data length
Date: Fri, 27 Mar 2020 10:09:01 +0800	[thread overview]
Message-ID: <9f126c07-91f0-47b8-81c4-aafb9aee66ca@redhat.com> (raw)
In-Reply-To: <CAKXe6SJMc0jinC-aWqhSp=ZH3Es0rHLbV-nwq1p0_hPY_vBTDA@mail.gmail.com>


On 2020/3/24 下午10:54, Li Qiang wrote:
>
>
> Jason Wang <jasowang@redhat.com <mailto:jasowang@redhat.com>> 
> 于2020年3月24日周二 下午1:45写道:
>
>
>     On 2020/3/24 上午9:29, Li Qiang wrote:
>     >
>     >
>     > P J P <ppandit@redhat.com <mailto:ppandit@redhat.com>
>     <mailto:ppandit@redhat.com <mailto:ppandit@redhat.com>>>
>     于2020年3月23日周一
>     > 下午8:24写道:
>     >
>     >     From: Prasad J Pandit <pjp@fedoraproject.org
>     <mailto:pjp@fedoraproject.org>
>     >     <mailto:pjp@fedoraproject.org <mailto:pjp@fedoraproject.org>>>
>     >
>     >     Tulip network driver while copying tx/rx buffers does not check
>     >     frame size against r/w data length. This may lead to OOB buffer
>     >     access. Add check to avoid it.
>     >
>     >     Limit iterations over descriptors to avoid potential infinite
>     >     loop issue in tulip_xmit_list_update.
>     >
>     >     Reported-by: Li Qiang <pangpei.lq@antfin.com
>     <mailto:pangpei.lq@antfin.com>
>     >     <mailto:pangpei.lq@antfin.com <mailto:pangpei.lq@antfin.com>>>
>     >     Reported-by: Ziming Zhang <ezrakiez@gmail.com
>     <mailto:ezrakiez@gmail.com>
>     >     <mailto:ezrakiez@gmail.com <mailto:ezrakiez@gmail.com>>>
>     >     Reported-by: Jason Wang <jasowang@redhat.com
>     <mailto:jasowang@redhat.com>
>     >     <mailto:jasowang@redhat.com <mailto:jasowang@redhat.com>>>
>     >     Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org
>     <mailto:pjp@fedoraproject.org>
>     >     <mailto:pjp@fedoraproject.org <mailto:pjp@fedoraproject.org>>>
>     >
>     >
>     >
>     > Tested-by: Li Qiang <liq3ea@gmail.com <mailto:liq3ea@gmail.com>
>     <mailto:liq3ea@gmail.com <mailto:liq3ea@gmail.com>>>
>     > But I have a minor question....
>     >
>     >     ---
>     >      hw/net/tulip.c | 36 +++++++++++++++++++++++++++---------
>     >      1 file changed, 27 insertions(+), 9 deletions(-)
>     >
>     >     Update v3: return a value from tulip_copy_tx_buffers() and avoid
>     >     infinite loop
>     >       ->
>     > https://lists.gnu.org/archive/html/qemu-devel/2020-02/msg06275.html
>     >
>     >     diff --git a/hw/net/tulip.c b/hw/net/tulip.c
>     >     index cfac2719d3..fbe40095da 100644
>     >     --- a/hw/net/tulip.c
>     >     +++ b/hw/net/tulip.c
>     >     @@ -170,6 +170,10 @@ static void tulip_copy_rx_bytes(TULIPState
>     >     *s, struct tulip_descriptor *desc)
>     >              } else {
>     >                  len = s->rx_frame_len;
>     >              }
>     >     +
>     >     +        if (s->rx_frame_len + len >= sizeof(s->rx_frame)) {
>     >     +            return;
>     >     +        }
>     >
>     >
>     >
>     > Why here is '>=' instead of '>'.
>     > IIUC the total sending length can reach to sizeof(s->rx_frame).
>     > Same in the other place in this patch.
>
>
>     Yes, this need to be fixed.
>
>
>     >
>     > PS: I have planned to write a qtest case. But my personal qemu dev
>     > environment is broken.
>     > I will try to write it tonight or tomorrow night.
>
>
>     Cool, good to know this.
>
>
> Hi all,
> I have countered an interesting issue. Let's look at the definition of 
> TULIPState.
>
>   21 typedef struct TULIPState {
>   22     PCIDevice dev;
>   23     MemoryRegion io;
>   24     MemoryRegion memory;
>   25     NICConf c;
>   26     qemu_irq irq;
>   27     NICState *nic;
>   28     eeprom_t *eeprom;
>   29     uint32_t csr[16];
>   30
>   31     /* state for MII */
>   32     uint32_t old_csr9;
>   33     uint32_t mii_word;
>   34     uint32_t mii_bitcnt;
>   35
>   36     hwaddr current_rx_desc;
>   37     hwaddr current_tx_desc;
>   38
>   39     uint8_t rx_frame[2048];
>   40     uint8_t tx_frame[2048];
>   41     uint16_t tx_frame_len;
>   42     uint16_t rx_frame_len;
>   43     uint16_t rx_frame_size;
>   44
>   45     uint32_t rx_status;
>   46     uint8_t filter[16][6];
>   47 } TULIPState;
>
> Here we can see the overflow is occured after 'tx_frame'.
> In my quest, I have see the overflow(the s->tx_frame_len is big).
> However here doesn't cause SEGV in qtest.
> In real case, the qemu process will access the data after TULIPState 
> in heap and trigger segv.
> However in qtest mode I don't know how to trigger this.


If it's just the mangling of tx_frame_len, it won't hit SIGSEV.

I wonder maybe, somehow that large tx_frame_len is used for buffer 
copying or other stuffs that can lead the crash.

Thanks


>
> The core code like this:
>
>  qpci_device_enable(dev);
> bar = qpci_iomap(dev, 0, NULL);
>     context_pa = guest_alloc(alloc, sizeof(context));
>     guest_pa = guest_alloc(alloc, 4096);
> memset(guest_data, 'A', sizeof(guest_data));
>     context[0].status = 1 << 31;
> context[0].control = 0x7ff << 11 | 0x7ff;
> context[0].buf_addr2 = context_pa + sizeof(struct tulip_descriptor);
> context[0].buf_addr1 = guest_pa;
>     for (i = 1; i < ARRAY_SIZE(context); ++i) {
>         context_pa += sizeof(struct tulip_descriptor);
>         context[i].status = 1 << 31;
> context[i].control = 0x7ff << 11 | 0x7ff;
> context[i].buf_addr2 = context_pa + sizeof(struct tulip_descriptor);
> context[i].buf_addr1 = guest_pa;
> }
>
> qtest_memwrite(dev->bus->qts, context_pa, context, sizeof(context));
> qtest_memwrite(dev->bus->qts, guest_pa, guest_data, sizeof(guest_data));
> qpci_io_writel(dev, bar, 0x20, context_pa);
> qpci_io_writel(dev, bar, 0x30, 1 << 13);
>
> Paolo may give some hints?
>
> Thanks,
> Li Qiang
>
>     Thanks
>
>
>     >
>     > Thanks,
>     > Li Qiang
>     >
>     >
>     >
>     >
>     >              pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame +
>     >                  (s->rx_frame_size - s->rx_frame_len), len);
>     >              s->rx_frame_len -= len;
>     >     @@ -181,6 +185,10 @@ static void tulip_copy_rx_bytes(TULIPState
>     >     *s, struct tulip_descriptor *desc)
>     >              } else {
>     >                  len = s->rx_frame_len;
>     >              }
>     >     +
>     >     +        if (s->rx_frame_len + len >= sizeof(s->rx_frame)) {
>     >     +            return;
>     >     +        }
>     >              pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame +
>     >                  (s->rx_frame_size - s->rx_frame_len), len);
>     >              s->rx_frame_len -= len;
>     >     @@ -227,7 +235,8 @@ static ssize_t tulip_receive(TULIPState *s,
>     >     const uint8_t *buf, size_t size)
>     >
>     >          trace_tulip_receive(buf, size);
>     >
>     >     -    if (size < 14 || size > 2048 || s->rx_frame_len ||
>     >     tulip_rx_stopped(s)) {
>     >     +    if (size < 14 || size > sizeof(s->rx_frame) - 4
>     >     +        || s->rx_frame_len || tulip_rx_stopped(s)) {
>     >              return 0;
>     >          }
>     >
>     >     @@ -275,7 +284,6 @@ static ssize_t
>     tulip_receive_nc(NetClientState
>     >     *nc,
>     >          return tulip_receive(qemu_get_nic_opaque(nc), buf, size);
>     >      }
>     >
>     >     -
>     >      static NetClientInfo net_tulip_info = {
>     >          .type = NET_CLIENT_DRIVER_NIC,
>     >          .size = sizeof(NICState),
>     >     @@ -558,7 +566,7 @@ static void tulip_tx(TULIPState *s, struct
>     >     tulip_descriptor *desc)
>     >              if ((s->csr[6] >> CSR6_OM_SHIFT) & CSR6_OM_MASK) {
>     >                  /* Internal or external Loopback */
>     >                  tulip_receive(s, s->tx_frame, s->tx_frame_len);
>     >     -        } else {
>     >     +        } else if (s->tx_frame_len <= sizeof(s->tx_frame)) {
>     >  qemu_send_packet(qemu_get_queue(s->nic),
>     >                      s->tx_frame, s->tx_frame_len);
>     >              }
>     >     @@ -570,23 +578,31 @@ static void tulip_tx(TULIPState *s, struct
>     >     tulip_descriptor *desc)
>     >          }
>     >      }
>     >
>     >     -static void tulip_copy_tx_buffers(TULIPState *s, struct
>     >     tulip_descriptor *desc)
>     >     +static int tulip_copy_tx_buffers(TULIPState *s, struct
>     >     tulip_descriptor *desc)
>     >      {
>     >          int len1 = (desc->control >> TDES1_BUF1_SIZE_SHIFT) &
>     >     TDES1_BUF1_SIZE_MASK;
>     >          int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) &
>     >     TDES1_BUF2_SIZE_MASK;
>     >
>     >     +    if (s->tx_frame_len + len1 >= sizeof(s->tx_frame)) {
>     >     +        return -1;
>     >     +    }
>     >          if (len1) {
>     >              pci_dma_read(&s->dev, desc->buf_addr1,
>     >                  s->tx_frame + s->tx_frame_len, len1);
>     >              s->tx_frame_len += len1;
>     >          }
>     >
>     >     +    if (s->tx_frame_len + len2 >= sizeof(s->tx_frame)) {
>     >     +        return -1;
>     >     +    }
>     >          if (len2) {
>     >              pci_dma_read(&s->dev, desc->buf_addr2,
>     >                  s->tx_frame + s->tx_frame_len, len2);
>     >              s->tx_frame_len += len2;
>     >          }
>     >          desc->status = (len1 + len2) ? 0 : 0x7fffffff;
>     >     +
>     >     +    return 0;
>     >      }
>     >
>     >      static void tulip_setup_filter_addr(TULIPState *s, uint8_t
>     *buf,
>     >     int n)
>     >     @@ -651,13 +667,15 @@ static uint32_t tulip_ts(TULIPState *s)
>     >
>     >      static void tulip_xmit_list_update(TULIPState *s)
>     >      {
>     >     +#define TULIP_DESC_MAX 128
>     >     +    uint8_t i = 0;
>     >          struct tulip_descriptor desc;
>     >
>     >          if (tulip_ts(s) != CSR5_TS_SUSPENDED) {
>     >              return;
>     >          }
>     >
>     >     -    for (;;) {
>     >     +    for (i = 0; i < TULIP_DESC_MAX; i++) {
>     >              tulip_desc_read(s, s->current_tx_desc, &desc);
>     >              tulip_dump_tx_descriptor(s, &desc);
>     >
>     >     @@ -675,10 +693,10 @@ static void
>     >     tulip_xmit_list_update(TULIPState *s)
>     >                      s->tx_frame_len = 0;
>     >                  }
>     >
>     >     -            tulip_copy_tx_buffers(s, &desc);
>     >     -
>     >     -            if (desc.control & TDES1_LS) {
>     >     -                tulip_tx(s, &desc);
>     >     +            if (!tulip_copy_tx_buffers(s, &desc)) {
>     >     +                if (desc.control & TDES1_LS) {
>     >     +                    tulip_tx(s, &desc);
>     >     +                }
>     >                  }
>     >              }
>     >              tulip_desc_write(s, s->current_tx_desc, &desc);
>     >     --
>     >     2.25.1
>     >
>     >
>



  reply	other threads:[~2020-03-27  2:09 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-23 12:20 [PATCH v6 0/2] net: tulip: add checks to avoid OOB access P J P
2020-03-23 12:20 ` [PATCH v6 1/2] net: tulip: check frame size and r/w data length P J P
2020-03-24  1:29   ` Li Qiang
2020-03-24  5:45     ` Jason Wang
2020-03-24 13:19       ` P J P
2020-03-24 14:54       ` Li Qiang
2020-03-27  2:09         ` Jason Wang [this message]
2020-03-27  2:35           ` Li Qiang
2020-03-27  2:53             ` Jason Wang
2020-03-27  3:43               ` Li Qiang
2020-03-26  4:34       ` P J P
2020-03-23 12:21 ` [PATCH v6 2/2] net: tulip: add .can_receive routine P J P
2020-03-24  2:04   ` Li Qiang
2020-03-24  5:44     ` Jason Wang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9f126c07-91f0-47b8-81c4-aafb9aee66ca@redhat.com \
    --to=jasowang@redhat.com \
    --cc=ezrakiez@gmail.com \
    --cc=liq3ea@gmail.com \
    --cc=pangpei.lq@antfin.com \
    --cc=pbonzini@redhat.com \
    --cc=philmd@redhat.com \
    --cc=pjp@fedoraproject.org \
    --cc=ppandit@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@gmail.com \
    --cc=svens@stackframe.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).