Commit message: hw/net: Fix a heap overflow in xlnx.xps-ethernetlite

The .receive callback of xlnx.xps-ethernetlite doesn't check the length
of data before calling memcpy. As a result, the NetClientState object in
heap will be overflowed. All versions of qemu with xlnx.xps-ethernetlite
will be affected.

Reported-by: chaojianhu <chaojianhu@hotmail.com>
Signed-off-by: chaojianhu <chaojianhu@hotmail.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
CVE: CVE-2016-7161
CWE: CWE-119
Vulnerability description: Heap-based buffer overflow in the .receive callback of xlnx.xps-ethernetlite in QEMU (aka Quick Emulator) allows attackers to execute arbitrary code on the QEMU host via a large ethlite packet.

Project: qemu
File: xilinx_ethlite.c

static int eth_can_rx(NetClientState *nc)
{
    struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
    unsigned int rxbase = s->rxbuf * (0x800 / 4);

    return !(s->regs[rxbase + R_RX_CTRL0] & CTRL_S);
}

Project: qemu
File: xilinx_ethlite.c

static inline void eth_pulse_irq(struct xlx_ethlite *s)
{
    /* Only the first gie reg is active.  */
    if (s->regs[R_TX_GIE0] & GIE_GIE) {
        qemu_irq_pulse(s->irq);
    }
}

Project: qemu
File: xilinx_ethlite.c

eth_read(void *opaque, hwaddr addr, unsigned int size)
{
    struct xlx_ethlite *s = opaque;
    uint32_t r = 0;

    addr >>= 2;

    switch (addr)
    {
        case R_TX_GIE0:
        case R_TX_LEN0:
        case R_TX_LEN1:
        case R_TX_CTRL1:
        case R_TX_CTRL0:
        case R_RX_CTRL1:
        case R_RX_CTRL0:
            r = s->regs[addr];
            D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr * 4, r));
            break;

        default:
            r = tswap32(s->regs[addr]);
            break;
    }
    return r;
}

Project: qemu
File: xilinx_ethlite.c

eth_write(void *opaque, hwaddr addr,
          uint64_t val64, unsigned int size)
{
    struct xlx_ethlite *s = opaque;
    unsigned int base = 0;
    uint32_t value = val64;

    addr >>= 2;
    switch (addr) 
    {
        case R_TX_CTRL0:
        case R_TX_CTRL1:
            if (addr == R_TX_CTRL1)
                base = 0x800 / 4;

            D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n",
                       __func__, addr * 4, value));
            if ((value & (CTRL_P | CTRL_S)) == CTRL_S) {
                qemu_send_packet(qemu_get_queue(s->nic),
                                 (void *) &s->regs[base],
                                 s->regs[base + R_TX_LEN0]);
                D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0]));
                if (s->regs[base + R_TX_CTRL0] & CTRL_I)
                    eth_pulse_irq(s);
            } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
                memcpy(&s->conf.macaddr.a[0], &s->regs[base], 6);
                if (s->regs[base + R_TX_CTRL0] & CTRL_I)
                    eth_pulse_irq(s);
            }

            /* We are fast and get ready pretty much immediately so
               we actually never flip the S nor P bits to one.  */
            s->regs[addr] = value & ~(CTRL_P | CTRL_S);
            break;

        /* Keep these native.  */
        case R_RX_CTRL0:
        case R_RX_CTRL1:
            if (!(value & CTRL_S)) {
                qemu_flush_queued_packets(qemu_get_queue(s->nic));
            }
            /* fall through */
        case R_TX_LEN0:
        case R_TX_LEN1:
        case R_TX_GIE0:
            D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n",
                       __func__, addr * 4, value));
            s->regs[addr] = value;
            break;

        default:
            s->regs[addr] = tswap32(value);
            break;
    }
}

Project: qemu
File: xilinx_ethlite.c

static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);

    dc->realize = xilinx_ethlite_realize;
    dc->reset = xilinx_ethlite_reset;
    dc->props = xilinx_ethlite_properties;
}

Project: qemu
File: xilinx_ethlite.c

static void xilinx_ethlite_init(Object *obj)
{
    struct xlx_ethlite *s = XILINX_ETHLITE(obj);

    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);

    memory_region_init_io(&s->mmio, obj, &eth_ops, s,
                          "xlnx.xps-ethernetlite", R_MAX * 4);
    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
}

Project: qemu
File: xilinx_ethlite.c

static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
{
    struct xlx_ethlite *s = XILINX_ETHLITE(dev);

    qemu_macaddr_default_if_unset(&s->conf.macaddr);
    s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
                          object_get_typename(OBJECT(dev)), dev->id, s);
    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
}

Project: qemu
File: xilinx_ethlite.c

static void xilinx_ethlite_register_types(void)
{
    type_register_static(&xilinx_ethlite_info);
}

Project: qemu
File: xilinx_ethlite.c

static void xilinx_ethlite_reset(DeviceState *dev)
{
    struct xlx_ethlite *s = XILINX_ETHLITE(dev);

    s->rxbuf = 0;
}