From 84164b2b3a63a2b676cef14110df058f3b7d8d45 Mon Sep 17 00:00:00 2001
From: Larry Dewey <ldewey@suse.com>
Date: Thu, 1 Nov 2018 10:51:07 -0600
Subject: [PATCH] chardev: Converting public IO impls to size_t

Due to an integer overflow issue found in ccid_card_vscard_read
(CVE-2018-18438), memory was previously susceptible to corruption. To
mitigate this issue, a number of components, including the
ccid-card-passthrough device are now utilizing size_t in place of int to
prevent an the overflow from occuring when values larger than
available space are passed to corresponding functions.

While CCID smart card readers were the primary target of the
vulnerability, a number of other subsystems have also been modified in the
same manner to prevent them from being exploited in the same way; specifically
functions which are modeled after the IOCanReadHandler and IOReadHandler
typedefs.

Subsystems affected include, but are not limited to:
CCID Smart Cards
Spice consoles
Monitors
Network Sockets
Network Tap Devices
Serial IO
Emulated Shell Serial IO
USB Redirection and Passthrough
Consoles
SLiRP IO
Mouse Emulation
Xen Consoles
SLCP IO
Network Block Devices

(cherry picked from commit 4792016a6119a4d5768bd8f989ae90b52dfef789)
[LD: BSC#1112185 CVE-2018-18438]
Signed-off-by: Larry Dewey <ldewey@suse.com>
---
 backends/rng-egd.c       |  6 ++---
 gdbstub.c                |  6 ++---
 hw/baum.c                |  2 +-
 hw/bt-hci-csr.c          |  4 +--
 hw/cadence_uart.c        |  2 +-
 hw/ccid-card-passthru.c  |  6 ++---
 hw/escc.c                |  6 ++---
 hw/etraxfs_ser.c         |  6 ++---
 hw/exynos4210_uart.c     |  2 +-
 hw/grlib_apbuart.c       |  4 +--
 hw/imx_serial.c          |  2 +-
 hw/ipoctal232.c          |  6 ++---
 hw/ivshmem.c             |  8 +++---
 hw/lm32_juart.c          |  4 +--
 hw/lm32_uart.c           |  4 +--
 hw/mcf_uart.c            |  2 +-
 hw/milkymist-uart.c      |  4 +--
 hw/msmouse.c             |  2 +-
 hw/pl011.c               |  2 +-
 hw/pxa2xx.c              |  2 +-
 hw/s390x/sclpconsole.c   |  4 +--
 hw/serial.c              |  8 +++---
 hw/sh_serial.c           |  4 +--
 hw/spapr_vty.c           |  2 +-
 hw/strongarm.c           |  2 +-
 hw/usb/dev-serial.c      |  4 +--
 hw/usb/redirect.c        |  4 +--
 hw/virtio-console.c      |  4 +--
 hw/xen_console.c         |  2 +-
 hw/xilinx_uartlite.c     |  4 +--
 include/char/char.h      |  8 +++---
 include/qemu/main-loop.h |  4 +--
 monitor.c                |  6 ++---
 nbd.c                    |  4 +--
 net/slirp.c              |  4 +--
 net/socket.c             |  2 +-
 net/tap.c                |  4 +--
 qemu-char.c              | 54 ++++++++++++++++++++++------------------
 qemu-nbd.c               |  2 +-
 qtest.c                  |  4 +--
 spice-qemu-char.c        |  4 +--
 ui/console.c             |  2 +-
 42 files changed, 111 insertions(+), 105 deletions(-)

diff --git a/backends/rng-egd.c b/backends/rng-egd.c
index 5f016beaa9..152cae1144 100644
--- a/backends/rng-egd.c
+++ b/backends/rng-egd.c
@@ -45,11 +45,11 @@ static void rng_egd_request_entropy(RngBackend *b, RngRequest *req)
     }
 }
 
-static int rng_egd_chr_can_read(void *opaque)
+static size_t rng_egd_chr_can_read(void *opaque)
 {
     RngEgd *s = RNG_EGD(opaque);
     GSList *i;
-    int size = 0;
+    size_t size = 0;
 
     for (i = s->parent.requests; i; i = i->next) {
         RngRequest *req = i->data;
@@ -59,7 +59,7 @@ static int rng_egd_chr_can_read(void *opaque)
     return size;
 }
 
-static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
+static void rng_egd_chr_read(void *opaque, const uint8_t *buf, size_t size)
 {
     RngEgd *s = RNG_EGD(opaque);
 
diff --git a/gdbstub.c b/gdbstub.c
index 6cd26f1619..31806ec81f 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2926,14 +2926,14 @@ void gdbserver_fork(CPUArchState *env)
     cpu_watchpoint_remove_all(env, BP_GDB);
 }
 #else
-static int gdb_chr_can_receive(void *opaque)
+static size_t gdb_chr_can_receive(void *opaque)
 {
   /* We can handle an arbitrarily large amount of data.
    Pick the maximum packet size, which is as good as anything.  */
   return MAX_PACKET_LENGTH;
 }
 
-static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size)
+static void gdb_chr_receive(void *opaque, const uint8_t *buf, size_t size)
 {
     int i;
 
@@ -2965,7 +2965,7 @@ static void gdb_monitor_output(GDBState *s, const char *msg, int len)
     put_packet(s, buf);
 }
 
-static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
+static size_t gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, size_t len)
 {
     const char *p = (const char *)buf;
     int max_sz;
diff --git a/hw/baum.c b/hw/baum.c
index 09dcb9cc74..4d8d5c2812 100644
--- a/hw/baum.c
+++ b/hw/baum.c
@@ -430,7 +430,7 @@ static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len)
 }
 
 /* The other end is writing some data.  Store it and try to interpret */
-static int baum_write(CharDriverState *chr, const uint8_t *buf, int len)
+static size_t baum_write(CharDriverState *chr, const uint8_t *buf, size_t len)
 {
     BaumDriverState *baum = chr->opaque;
     int tocopy, cur, eaten, orig_len = len;
diff --git a/hw/bt-hci-csr.c b/hw/bt-hci-csr.c
index 2070bb940c..b126a01040 100644
--- a/hw/bt-hci-csr.c
+++ b/hw/bt-hci-csr.c
@@ -294,8 +294,8 @@ static int csrhci_data_len(const uint8_t *pkt)
     exit(-1);
 }
 
-static int csrhci_write(struct CharDriverState *chr,
-                const uint8_t *buf, int len)
+static size_t csrhci_write(struct CharDriverState *chr,
+                const uint8_t *buf, size_t len)
 {
     struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
     int plen = s->in_len;
diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c
index 5766d38f13..78acb8d328 100644
--- a/hw/cadence_uart.c
+++ b/hw/cadence_uart.c
@@ -227,7 +227,7 @@ static void uart_parameters_setup(UartState *s)
     qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 }
 
-static int uart_can_receive(void *opaque)
+static size_t uart_can_receive(void *opaque)
 {
     UartState *s = (UartState *)opaque;
 
diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c
index 984bd0bf4c..3a033277c3 100644
--- a/hw/ccid-card-passthru.c
+++ b/hw/ccid-card-passthru.c
@@ -104,7 +104,7 @@ static void ccid_card_vscard_send_init(PassthruState *s)
                          (uint8_t *)&msg, sizeof(msg));
 }
 
-static int ccid_card_vscard_can_read(void *opaque)
+static size_t ccid_card_vscard_can_read(void * opaque)
 {
     PassthruState *card = opaque;
 
@@ -203,14 +203,14 @@ static void ccid_card_vscard_drop_connection(PassthruState *card)
     card->vscard_in_pos = card->vscard_in_hdr = 0;
 }
 
-static void ccid_card_vscard_read(void *opaque, const uint8_t *buf, int size)
+static void ccid_card_vscard_read(void *opaque, const uint8_t *buf, size_t size)
 {
     PassthruState *card = opaque;
     VSCMsgHeader *hdr;
 
     if (card->vscard_in_pos + size > VSCARD_IN_SIZE) {
         error_report(
-            "no room for data: pos %d +  size %d > %d. dropping connection.",
+            "no room for data: pos %d +  size %zu > %d. dropping connection.",
             card->vscard_in_pos, size, VSCARD_IN_SIZE);
         ccid_card_vscard_drop_connection(card);
         return;
diff --git a/hw/escc.c b/hw/escc.c
index 18c02921e3..c7d530ba41 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -208,7 +208,7 @@ struct SerialState {
 #define R_EXTINT 15
 
 static void handle_kbd_command(ChannelState *s, int val);
-static int serial_can_receive(void *opaque);
+static size_t serial_can_receive(void *opaque);
 static void serial_receive_byte(ChannelState *s, int ch);
 
 static void clear_queue(void *opaque)
@@ -610,10 +610,10 @@ static const MemoryRegionOps escc_mem_ops = {
     },
 };
 
-static int serial_can_receive(void *opaque)
+static size_t serial_can_receive(void *opaque)
 {
     ChannelState *s = opaque;
-    int ret;
+    size_t ret;
 
     if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) // Rx not enabled
         || ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV))
diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
index 72c8868639..958ac407a2 100644
--- a/hw/etraxfs_ser.c
+++ b/hw/etraxfs_ser.c
@@ -156,7 +156,7 @@ static const MemoryRegionOps ser_ops = {
     }
 };
 
-static void serial_receive(void *opaque, const uint8_t *buf, int size)
+static void serial_receive(void *opaque, const uint8_t *buf, size_t size)
 {
     struct etrax_serial *s = opaque;
     int i;
@@ -177,10 +177,10 @@ static void serial_receive(void *opaque, const uint8_t *buf, int size)
     ser_update_irq(s);
 }
 
-static int serial_can_receive(void *opaque)
+static size_t serial_can_receive(void *opaque)
 {
     struct etrax_serial *s = opaque;
-    int r;
+    size_t r;
 
     /* Is the receiver enabled?  */
     if (!(s->regs[RW_REC_CTRL] & (1 << 3))) {
diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c
index bdf797a029..154966a237 100644
--- a/hw/exynos4210_uart.c
+++ b/hw/exynos4210_uart.c
@@ -484,7 +484,7 @@ static const MemoryRegionOps exynos4210_uart_ops = {
     },
 };
 
-static int exynos4210_uart_can_receive(void *opaque)
+static size_t exynos4210_uart_can_receive(void *opaque)
 {
     Exynos4210UartState *s = (Exynos4210UartState *)opaque;
 
diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
index 760bed0b72..dd4c780fed 100644
--- a/hw/grlib_apbuart.c
+++ b/hw/grlib_apbuart.c
@@ -125,14 +125,14 @@ static void uart_add_to_fifo(UART          *uart,
     uart->len += length;
 }
 
-static int grlib_apbuart_can_receive(void *opaque)
+static size_t grlib_apbuart_can_receive(void *opaque)
 {
     UART *uart = opaque;
 
     return FIFO_LENGTH - uart->len;
 }
 
-static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
+static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, size_t size)
 {
     UART *uart = opaque;
 
diff --git a/hw/imx_serial.c b/hw/imx_serial.c
index 2d8253e0ee..edb50df365 100644
--- a/hw/imx_serial.c
+++ b/hw/imx_serial.c
@@ -345,7 +345,7 @@ static void imx_serial_write(void *opaque, hwaddr offset,
     }
 }
 
-static int imx_can_receive(void *opaque)
+static size_t imx_can_receive(void *opaque)
 {
     IMXSerialState *s = (IMXSerialState *)opaque;
     return !(s->usr1 & USR1_RRDY);
diff --git a/hw/ipoctal232.c b/hw/ipoctal232.c
index c1e3b197b5..66014966d5 100644
--- a/hw/ipoctal232.c
+++ b/hw/ipoctal232.c
@@ -464,14 +464,14 @@ static void mem_write8(IPackDevice *ip, uint32_t addr, uint8_t val)
     }
 }
 
-static int hostdev_can_receive(void *opaque)
+static size_t hostdev_can_receive(void *opaque)
 {
     SCC2698Channel *ch = opaque;
-    int available_bytes = RX_FIFO_SIZE - ch->rx_pending;
+    size_t available_bytes = RX_FIFO_SIZE - ch->rx_pending;
     return ch->rx_enabled ? available_bytes : 0;
 }
 
-static void hostdev_receive(void *opaque, const uint8_t *buf, int size)
+static void hostdev_receive(void *opaque, const uint8_t *buf, size_t size)
 {
     SCC2698Channel *ch = opaque;
     IPOctalState *dev = ch->ipoctal;
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index afaf9b3bbf..912921180d 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -250,7 +250,7 @@ static const MemoryRegionOps ivshmem_mmio_ops = {
     },
 };
 
-static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
+static void ivshmem_receive(void *opaque, const uint8_t *buf, size_t size)
 {
     IVShmemState *s = opaque;
 
@@ -259,7 +259,7 @@ static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
     IVSHMEM_DPRINTF("ivshmem_receive 0x%02x\n", *buf);
 }
 
-static int ivshmem_can_receive(void * opaque)
+static size_t ivshmem_can_receive(void * opaque)
 {
     return 8;
 }
@@ -269,7 +269,7 @@ static void ivshmem_event(void *opaque, int event)
     IVSHMEM_DPRINTF("ivshmem_event %d\n", event);
 }
 
-static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
+static void fake_irqfd(void *opaque, const uint8_t *buf, size_t size) {
 
     EventfdEntry *entry = opaque;
     PCIDevice *pdev = entry->pdev;
@@ -411,7 +411,7 @@ static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
     }
 }
 
-static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
+static void ivshmem_read(void *opaque, const uint8_t * buf, size_t flags)
 {
     IVShmemState *s = opaque;
     int incoming_fd, tmp_fd;
diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c
index 8c82c85f6d..9d96eda895 100644
--- a/hw/lm32_juart.c
+++ b/hw/lm32_juart.c
@@ -84,14 +84,14 @@ void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx)
     s->jrx &= ~JRX_FULL;
 }
 
-static void juart_rx(void *opaque, const uint8_t *buf, int size)
+static void juart_rx(void *opaque, const uint8_t *buf, size_t size)
 {
     LM32JuartState *s = opaque;
 
     s->jrx = *buf | JRX_FULL;
 }
 
-static int juart_can_rx(void *opaque)
+static size_t juart_can_rx(void *opaque)
 {
     LM32JuartState *s = opaque;
 
diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c
index 9c89cca49b..312319d0c8 100644
--- a/hw/lm32_uart.c
+++ b/hw/lm32_uart.c
@@ -205,7 +205,7 @@ static const MemoryRegionOps uart_ops = {
     },
 };
 
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
+static void uart_rx(void *opaque, const uint8_t *buf, size_t size)
 {
     LM32UartState *s = opaque;
 
@@ -219,7 +219,7 @@ static void uart_rx(void *opaque, const uint8_t *buf, int size)
     uart_update_irq(s);
 }
 
-static int uart_can_rx(void *opaque)
+static size_t uart_can_rx(void *opaque)
 {
     LM32UartState *s = opaque;
 
diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c
index c44344317a..6edd4ae216 100644
--- a/hw/mcf_uart.c
+++ b/hw/mcf_uart.c
@@ -258,7 +258,7 @@ static void mcf_uart_event(void *opaque, int event)
     }
 }
 
-static int mcf_uart_can_receive(void *opaque)
+static size_t mcf_uart_can_receive(void *opaque)
 {
     mcf_uart_state *s = (mcf_uart_state *)opaque;
 
diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
index e73eb8476c..b2d1a4ff1b 100644
--- a/hw/milkymist-uart.c
+++ b/hw/milkymist-uart.c
@@ -153,7 +153,7 @@ static const MemoryRegionOps uart_mmio_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
+static void uart_rx(void *opaque, const uint8_t *buf, size_t size)
 {
     MilkymistUartState *s = opaque;
 
@@ -165,7 +165,7 @@ static void uart_rx(void *opaque, const uint8_t *buf, int size)
     uart_update_irq(s);
 }
 
-static int uart_can_rx(void *opaque)
+static size_t uart_can_rx(void *opaque)
 {
     MilkymistUartState *s = opaque;
 
diff --git a/hw/msmouse.c b/hw/msmouse.c
index ef47aed4e9..38351178b7 100644
--- a/hw/msmouse.c
+++ b/hw/msmouse.c
@@ -53,7 +53,7 @@ static void msmouse_event(void *opaque,
     qemu_chr_be_write(chr, bytes, 4);
 }
 
-static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int len)
+static size_t msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, size_t len)
 {
     /* Ignore writes to mouse port */
     return len;
diff --git a/hw/pl011.c b/hw/pl011.c
index 002a50e16a..6b4180139d 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -189,7 +189,7 @@ static void pl011_write(void *opaque, hwaddr offset,
     }
 }
 
-static int pl011_can_receive(void *opaque)
+static size_t pl011_can_receive(void *opaque)
 {
     pl011_state *s = (pl011_state *)opaque;
 
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 2ac9ead7aa..d9090f8d58 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -1895,7 +1895,7 @@ static const MemoryRegionOps pxa2xx_fir_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int pxa2xx_fir_is_empty(void *opaque)
+static size_t pxa2xx_fir_is_empty(void *opaque)
 {
     PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
     return (s->rx_len < 64);
diff --git a/hw/s390x/sclpconsole.c b/hw/s390x/sclpconsole.c
index effe51110f..9d986e8109 100644
--- a/hw/s390x/sclpconsole.c
+++ b/hw/s390x/sclpconsole.c
@@ -42,7 +42,7 @@ typedef struct SCLPConsole {
 /* character layer call-back functions */
 
 /* Return number of bytes that fit into iov buffer */
-static int chr_can_read(void *opaque)
+static size_t chr_can_read(void *opaque)
 {
     SCLPConsole *scon = opaque;
 
@@ -68,7 +68,7 @@ static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf,
 }
 
 /* Send data from a char device over to the guest */
-static void chr_read(void *opaque, const uint8_t *buf, int size)
+static void chr_read(void *opaque, const uint8_t *buf, size_t size)
 {
     SCLPConsole *scon = opaque;
 
diff --git a/hw/serial.c b/hw/serial.c
index 5007caf03b..2fa6210548 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -104,7 +104,7 @@ do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0)
 do {} while (0)
 #endif
 
-static void serial_receive1(void *opaque, const uint8_t *buf, int size);
+static void serial_receive1(void *opaque, const uint8_t *buf, size_t size);
 
 static void fifo_clear(SerialState *s, int fifo)
 {
@@ -536,7 +536,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size)
     return ret;
 }
 
-static int serial_can_receive(SerialState *s)
+static size_t serial_can_receive(SerialState *s)
 {
     if(s->fcr & UART_FCR_FE) {
         if(s->recv_fifo.count < UART_FIFO_LENGTH)
@@ -569,13 +569,13 @@ static void fifo_timeout_int (void *opaque) {
     }
 }
 
-static int serial_can_receive1(void *opaque)
+static size_t serial_can_receive1(void *opaque)
 {
     SerialState *s = opaque;
     return serial_can_receive(s);
 }
 
-static void serial_receive1(void *opaque, const uint8_t *buf, int size)
+static void serial_receive1(void *opaque, const uint8_t *buf, size_t size)
 {
     SerialState *s = opaque;
 
diff --git a/hw/sh_serial.c b/hw/sh_serial.c
index 21c5b1362d..fe623be9d9 100644
--- a/hw/sh_serial.c
+++ b/hw/sh_serial.c
@@ -296,7 +296,7 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs,
     return ret;
 }
 
-static int sh_serial_can_receive(sh_serial_state *s)
+static size_t sh_serial_can_receive(sh_serial_state *s)
 {
     return s->scr & (1 << 4);
 }
@@ -307,7 +307,7 @@ static void sh_serial_receive_break(sh_serial_state *s)
         s->sr |= (1 << 4);
 }
 
-static int sh_serial_can_receive1(void *opaque)
+static size_t sh_serial_can_receive1(void *opaque)
 {
     sh_serial_state *s = opaque;
     return sh_serial_can_receive(s);
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index 5c63eaafa9..b4e9ef91c2 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -12,7 +12,7 @@ typedef struct VIOsPAPRVTYDevice {
     uint8_t buf[VTERM_BUFSIZE];
 } VIOsPAPRVTYDevice;
 
-static int vty_can_receive(void *opaque)
+static size_t vty_can_receive(void *opaque)
 {
     VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
 
diff --git a/hw/strongarm.c b/hw/strongarm.c
index ab736e300e..058a3798ca 100644
--- a/hw/strongarm.c
+++ b/hw/strongarm.c
@@ -1033,7 +1033,7 @@ static void strongarm_uart_rx_push(StrongARMUARTState *s, uint16_t c)
         s->rx_fifo[(s->rx_start + 11) % 12] |= RX_FIFO_ROR;
 }
 
-static int strongarm_uart_can_receive(void *opaque)
+static size_t strongarm_uart_can_receive(void *opaque)
 {
     StrongARMUARTState *s = opaque;
 
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index 47ac8c9b69..256d214eaf 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -417,7 +417,7 @@ static void usb_serial_handle_destroy(USBDevice *dev)
     qemu_chr_add_handlers(s->cs, NULL, NULL, NULL, NULL);
 }
 
-static int usb_serial_can_read(void *opaque)
+static size_t usb_serial_can_read(void *opaque)
 {
     USBSerialState *s = opaque;
 
@@ -427,7 +427,7 @@ static int usb_serial_can_read(void *opaque)
     return RECV_BUF - s->recv_used;
 }
 
-static void usb_serial_read(void *opaque, const uint8_t *buf, int size)
+static void usb_serial_read(void *opaque, const uint8_t *buf, size_t size)
 {
     USBSerialState *s = opaque;
     int first_size, start;
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index e9bfd8fc7e..aeb021ecf8 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -1165,7 +1165,7 @@ static void usbredir_do_attach(void *opaque)
  * chardev callbacks
  */
 
-static int usbredir_chardev_can_read(void *opaque)
+static size_t usbredir_chardev_can_read(void *opaque)
 {
     USBRedirDevice *dev = opaque;
 
@@ -1183,7 +1183,7 @@ static int usbredir_chardev_can_read(void *opaque)
     return 1024 * 1024;
 }
 
-static void usbredir_chardev_read(void *opaque, const uint8_t *buf, int size)
+static void usbredir_chardev_read(void *opaque, const uint8_t *buf, size_t size)
 {
     USBRedirDevice *dev = opaque;
 
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index eec0ef9888..e70f9f7c83 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -83,7 +83,7 @@ static void guest_close(VirtIOSerialPort *port)
 }
 
 /* Readiness of the guest to accept data on a port */
-static int chr_can_read(void *opaque)
+static size_t chr_can_read(void *opaque)
 {
     VirtConsole *vcon = opaque;
 
@@ -91,7 +91,7 @@ static int chr_can_read(void *opaque)
 }
 
 /* Send data from a char device over to the guest */
-static void chr_read(void *opaque, const uint8_t *buf, int size)
+static void chr_read(void *opaque, const uint8_t *buf, size_t size)
 {
     VirtConsole *vcon = opaque;
 
diff --git a/hw/xen_console.c b/hw/xen_console.c
index 44141f8692..5709126798 100644
--- a/hw/xen_console.c
+++ b/hw/xen_console.c
@@ -121,7 +121,7 @@ static int ring_free_bytes(struct XenConsole *con)
     return (sizeof(intf->in) - space);
 }
 
-static int xencons_can_receive(void *opaque)
+static size_t xencons_can_receive(void *opaque)
 {
     struct XenConsole *con = opaque;
     return ring_free_bytes(con);
diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
index 9963982ef6..901066e776 100644
--- a/hw/xilinx_uartlite.c
+++ b/hw/xilinx_uartlite.c
@@ -162,7 +162,7 @@ static const MemoryRegionOps uart_ops = {
     }
 };
 
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
+static void uart_rx(void *opaque, const uint8_t *buf, size_t size)
 {
     struct xlx_uartlite *s = opaque;
 
@@ -180,7 +180,7 @@ static void uart_rx(void *opaque, const uint8_t *buf, int size)
     uart_update_irq(s);
 }
 
-static int uart_can_rx(void *opaque)
+static size_t uart_can_rx(void *opaque)
 {
     struct xlx_uartlite *s = opaque;
 
diff --git a/include/char/char.h b/include/char/char.h
index c91ce3c98a..320021fe36 100644
--- a/include/char/char.h
+++ b/include/char/char.h
@@ -55,7 +55,7 @@ typedef void IOEventHandler(void *opaque, int event);
 
 struct CharDriverState {
     void (*init)(struct CharDriverState *s);
-    int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len);
+    size_t (*chr_write)(struct CharDriverState *s, const uint8_t *buf, size_t len);
     void (*chr_update_read_handler)(struct CharDriverState *s);
     int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
     int (*get_msgfd)(struct CharDriverState *s);
@@ -163,7 +163,7 @@ void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
  *
  * Returns: the number of bytes consumed
  */
-int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len);
+size_t qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, size_t len);
 
 /**
  * @qemu_chr_fe_ioctl:
@@ -201,7 +201,7 @@ int qemu_chr_fe_get_msgfd(CharDriverState *s);
  *
  * Returns: the number of bytes the front end can receive via @qemu_chr_be_write
  */
-int qemu_chr_be_can_write(CharDriverState *s);
+size_t qemu_chr_be_can_write(CharDriverState *s);
 
 /**
  * @qemu_chr_be_write:
@@ -213,7 +213,7 @@ int qemu_chr_be_can_write(CharDriverState *s);
  * @buf a buffer to receive data from the front end
  * @len the number of bytes to receive from the front end
  */
-void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len);
+void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, size_t len);
 
 
 /**
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index 5e9c509421..6faa361876 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -168,8 +168,8 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
 
 /* async I/O support */
 
-typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
-typedef int IOCanReadHandler(void *opaque);
+typedef void IOReadHandler(void *opaque, const uint8_t *buf, size_t size);
+typedef size_t IOCanReadHandler(void *opaque);
 
 /**
  * qemu_set_fd_handler2: Register a file descriptor with the main loop
diff --git a/monitor.c b/monitor.c
index 20bd19b05f..de7a8231a7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4191,7 +4191,7 @@ cleanup:
     }
 }
 
-static int monitor_can_read(void *opaque)
+static size_t monitor_can_read(void *opaque)
 {
     Monitor *mon = opaque;
 
@@ -4540,7 +4540,7 @@ out:
 /**
  * monitor_control_read(): Read and handle QMP input
  */
-static void monitor_control_read(void *opaque, const uint8_t *buf, int size)
+static void monitor_control_read(void *opaque, const uint8_t *buf, size_t size)
 {
     Monitor *old_mon = cur_mon;
 
@@ -4551,7 +4551,7 @@ static void monitor_control_read(void *opaque, const uint8_t *buf, int size)
     cur_mon = old_mon;
 }
 
-static void monitor_read(void *opaque, const uint8_t *buf, int size)
+static void monitor_read(void *opaque, const uint8_t *buf, size_t size)
 {
     Monitor *old_mon = cur_mon;
     int i;
diff --git a/nbd.c b/nbd.c
index 2eff5a249e..6be3ebf868 100644
--- a/nbd.c
+++ b/nbd.c
@@ -985,7 +985,7 @@ void nbd_export_close_all(void)
     }
 }
 
-static int nbd_can_read(void *opaque);
+static size_t nbd_can_read(void *opaque);
 static void nbd_read(void *opaque);
 static void nbd_restart_write(void *opaque);
 
@@ -1215,7 +1215,7 @@ out:
     nbd_client_close(client);
 }
 
-static int nbd_can_read(void *opaque)
+static size_t nbd_can_read(void *opaque)
 {
     NBDClient *client = opaque;
 
diff --git a/net/slirp.c b/net/slirp.c
index c1227cbba2..ddbf570abe 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -582,13 +582,13 @@ struct GuestFwd {
     Slirp *slirp;
 };
 
-static int guestfwd_can_read(void *opaque)
+static size_t guestfwd_can_read(void *opaque)
 {
     struct GuestFwd *fwd = opaque;
     return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port);
 }
 
-static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
+static void guestfwd_read(void *opaque, const uint8_t *buf, size_t size)
 {
     struct GuestFwd *fwd = opaque;
     slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size);
diff --git a/net/socket.c b/net/socket.c
index a2b94f44cb..bfe75039ee 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -51,7 +51,7 @@ static void net_socket_accept(void *opaque);
 static void net_socket_writable(void *opaque);
 
 /* Only read packets from socket when peer can receive them */
-static int net_socket_can_send(void *opaque)
+static size_t net_socket_can_send(void *opaque)
 {
     NetSocketState *s = opaque;
 
diff --git a/net/tap.c b/net/tap.c
index 0da48b16fb..a206717375 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -66,7 +66,7 @@ typedef struct TAPState {
 
 static int launch_script(const char *setup_script, const char *ifname, int fd);
 
-static int tap_can_send(void *opaque);
+static size_t tap_can_send(void *opaque);
 static void tap_send(void *opaque);
 static void tap_writable(void *opaque);
 
@@ -170,7 +170,7 @@ static ssize_t tap_receive(NetClientState *nc, const uint8_t *buf, size_t size)
     return tap_write_packet(s, iov, 1);
 }
 
-static int tap_can_send(void *opaque)
+static size_t tap_can_send(void *opaque)
 {
     TAPState *s = opaque;
 
diff --git a/qemu-char.c b/qemu-char.c
index c7c4375942..7a9694e99f 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -139,7 +139,7 @@ void qemu_chr_generic_open(CharDriverState *s)
     }
 }
 
-int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len)
+size_t qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, size_t len)
 {
     return s->chr_write(s, buf, len);
 }
@@ -151,14 +151,19 @@ int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg)
     return s->chr_ioctl(s, cmd, arg);
 }
 
-int qemu_chr_be_can_write(CharDriverState *s)
+size_t qemu_chr_be_can_write(CharDriverState *s)
 {
+    int res;
+
     if (!s->chr_can_read)
         return 0;
-    return s->chr_can_read(s->handler_opaque);
+
+    res = s->chr_can_read(s->handler_opaque);
+    assert(res >= 0);
+    return res;
 }
 
-void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
+void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, size_t len)
 {
     if (s->chr_read) {
         s->chr_read(s->handler_opaque, buf, len);
@@ -216,7 +221,7 @@ void qemu_chr_add_handlers(CharDriverState *s,
     }
 }
 
-static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static size_t null_chr_write(CharDriverState *chr, const uint8_t *buf, size_t len)
 {
     return len;
 }
@@ -259,7 +264,7 @@ typedef struct {
 } MuxDriver;
 
 
-static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static size_t mux_chr_write(CharDriverState *chr, const uint8_t *buf, size_t len)
 {
     MuxDriver *d = chr->opaque;
     int ret;
@@ -410,7 +415,7 @@ static void mux_chr_accept_input(CharDriverState *chr)
 #endif
 }
 
-static int mux_chr_can_read(void *opaque)
+static size_t mux_chr_can_read(void *opaque)
 {
     CharDriverState *chr = opaque;
     MuxDriver *d = chr->opaque;
@@ -423,7 +428,7 @@ static int mux_chr_can_read(void *opaque)
     return 0;
 }
 
-static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
+static void mux_chr_read(void *opaque, const uint8_t *buf, size_t size)
 {
     CharDriverState *chr = opaque;
     MuxDriver *d = chr->opaque;
@@ -562,17 +567,17 @@ static int stdio_nb_clients;
 
 typedef struct {
     int fd_in, fd_out;
-    int max_size;
+    size_t max_size;
 } FDCharDriver;
 
 
-static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static size_t fd_chr_write(CharDriverState *chr, const uint8_t *buf, size_t len)
 {
     FDCharDriver *s = chr->opaque;
     return send_all(s->fd_out, buf, len);
 }
 
-static int fd_chr_read_poll(void *opaque)
+static size_t fd_chr_read_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
     FDCharDriver *s = chr->opaque;
@@ -585,7 +590,8 @@ static void fd_chr_read(void *opaque)
 {
     CharDriverState *chr = opaque;
     FDCharDriver *s = chr->opaque;
-    int size, len;
+    int size;
+    size_t len;
     uint8_t buf[READ_BUF_LEN];
 
     len = sizeof(buf);
@@ -702,7 +708,7 @@ static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts)
 static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
 static int term_fifo_size;
 
-static int stdio_read_poll(void *opaque)
+static size_t stdio_read_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
 
@@ -885,7 +891,7 @@ typedef struct {
 static void pty_chr_update_read_handler(CharDriverState *chr);
 static void pty_chr_state(CharDriverState *chr, int connected);
 
-static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static size_t pty_chr_write(CharDriverState *chr, const uint8_t *buf, size_t len)
 {
     PtyCharDriver *s = chr->opaque;
 
@@ -897,7 +903,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     return send_all(s->fd, buf, len);
 }
 
-static int pty_chr_read_poll(void *opaque)
+static size_t pty_chr_read_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
     PtyCharDriver *s = chr->opaque;
@@ -1581,7 +1587,7 @@ static int win_chr_init(CharDriverState *chr, const char *filename)
     return -1;
 }
 
-static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
+static size_t win_chr_write(CharDriverState *chr, const uint8_t *buf, size_t len1)
 {
     WinCharState *s = chr->opaque;
     DWORD len, ret, size, err;
@@ -1832,7 +1838,7 @@ static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts)
     return qemu_chr_open_win_file(fd_out);
 }
 
-static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
+static size_t win_stdio_write(CharDriverState *chr, const uint8_t *buf, size_t len)
 {
     HANDLE  hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
     DWORD   dwSize;
@@ -2053,14 +2059,14 @@ typedef struct {
     int max_size;
 } NetCharDriver;
 
-static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static size_t udp_chr_write(CharDriverState *chr, const uint8_t *buf, size_t len)
 {
     NetCharDriver *s = chr->opaque;
 
     return send(s->fd, (const void *)buf, len, 0);
 }
 
-static int udp_chr_read_poll(void *opaque)
+static size_t udp_chr_read_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
     NetCharDriver *s = chr->opaque;
@@ -2171,7 +2177,7 @@ typedef struct {
 
 static void tcp_chr_accept(void *opaque);
 
-static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static size_t tcp_chr_write(CharDriverState *chr, const uint8_t *buf, size_t len)
 {
     TCPCharDriver *s = chr->opaque;
     if (s->connected) {
@@ -2182,7 +2188,7 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     }
 }
 
-static int tcp_chr_read_poll(void *opaque)
+static size_t tcp_chr_read_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
     TCPCharDriver *s = chr->opaque;
@@ -2606,7 +2612,7 @@ typedef struct {
     uint8_t *outbuf;
 } MemoryDriver;
 
-static int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static size_t mem_chr_write(CharDriverState *chr, const uint8_t *buf, size_t len)
 {
     MemoryDriver *d = chr->opaque;
 
@@ -2679,12 +2685,12 @@ static size_t ringbuf_count(const CharDriverState *chr)
     return d->prod - d->cons;
 }
 
-static int ringbuf_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static size_t ringbuf_chr_write(CharDriverState *chr, const uint8_t *buf, size_t len)
 {
     RingBufCharDriver *d = chr->opaque;
     int i;
 
-    if (!buf || (len < 0)) {
+    if (!buf) {
         return -1;
     }
 
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 5903f1e1d1..f7c6d7bd15 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -273,7 +273,7 @@ out:
     return (void *) EXIT_FAILURE;
 }
 
-static int nbd_can_accept(void *opaque)
+static size_t nbd_can_accept(void *opaque)
 {
     return nb_fds < shared;
 }
diff --git a/qtest.c b/qtest.c
index 4663a38e11..f4240c9011 100644
--- a/qtest.c
+++ b/qtest.c
@@ -372,7 +372,7 @@ static void qtest_process_inbuf(CharDriverState *chr, GString *inbuf)
     }
 }
 
-static void qtest_read(void *opaque, const uint8_t *buf, int size)
+static void qtest_read(void *opaque, const uint8_t *buf, size_t size)
 {
     CharDriverState *chr = opaque;
 
@@ -380,7 +380,7 @@ static void qtest_read(void *opaque, const uint8_t *buf, int size)
     qtest_process_inbuf(chr, inbuf);
 }
 
-static int qtest_can_read(void *opaque)
+static size_t qtest_can_read(void *opaque)
 {
     return 1024;
 }
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index a4d7de8c4f..7bb9764373 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -160,11 +160,11 @@ static void vmc_unregister_interface(SpiceCharDriver *scd)
 }
 
 
-static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static size_t spice_chr_write(CharDriverState *chr, const uint8_t *buf, size_t len)
 {
     SpiceCharDriver *s = chr->opaque;
 
-    dprintf(s, 2, "%s: %d\n", __func__, len);
+    dprintf(s, 2, "%s: %zu\n", __func__, len);
     vmc_register_interface(s);
     assert(s->datalen == 0);
     if (s->bufsize < len) {
diff --git a/ui/console.c b/ui/console.c
index 7f2118771e..18482dcbc6 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1114,7 +1114,7 @@ void console_select(unsigned int index)
     }
 }
 
-static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
+static size_t console_puts(CharDriverState *chr, const uint8_t *buf, size_t len)
 {
     QemuConsole *s = chr->opaque;
     int i;
