Skip to content

Commit

Permalink
net: introduce qemu_receive_packet()
Browse files Browse the repository at this point in the history
Some NIC supports loopback mode and this is done by calling
nc->info->receive() directly which in fact suppresses the effort of
reentrancy check that is done in qemu_net_queue_send().

Unfortunately we can't use qemu_net_queue_send() here since for
loopback there's no sender as peer, so this patch introduce a
qemu_receive_packet() which is used for implementing loopback mode
for a NIC with this check.

NIC that supports loopback mode will be converted to this helper.

This is intended to address CVE-2021-3416.

Cc: Prasad J Pandit <[email protected]>
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
Cc: [email protected]
Signed-off-by: Jason Wang <[email protected]>
  • Loading branch information
jasowang committed Mar 15, 2021
1 parent 3de46e6 commit 705df54
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 7 deletions.
5 changes: 5 additions & 0 deletions include/net/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,17 @@ void *qemu_get_nic_opaque(NetClientState *nc);
void qemu_del_net_client(NetClientState *nc);
typedef void (*qemu_nic_foreach)(NICState *nic, void *opaque);
void qemu_foreach_nic(qemu_nic_foreach func, void *opaque);
int qemu_can_receive_packet(NetClientState *nc);
int qemu_can_send_packet(NetClientState *nc);
ssize_t qemu_sendv_packet(NetClientState *nc, const struct iovec *iov,
int iovcnt);
ssize_t qemu_sendv_packet_async(NetClientState *nc, const struct iovec *iov,
int iovcnt, NetPacketSent *sent_cb);
ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size);
ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size);
ssize_t qemu_receive_packet_iov(NetClientState *nc,
const struct iovec *iov,
int iovcnt);
ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size);
ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf,
int size, NetPacketSent *sent_cb);
Expand Down
8 changes: 8 additions & 0 deletions include/net/queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ void qemu_net_queue_append_iov(NetQueue *queue,

void qemu_del_net_queue(NetQueue *queue);

ssize_t qemu_net_queue_receive(NetQueue *queue,
const uint8_t *data,
size_t size);

ssize_t qemu_net_queue_receive_iov(NetQueue *queue,
const struct iovec *iov,
int iovcnt);

ssize_t qemu_net_queue_send(NetQueue *queue,
NetClientState *sender,
unsigned flags,
Expand Down
38 changes: 31 additions & 7 deletions net/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,17 @@ int qemu_set_vnet_be(NetClientState *nc, bool is_be)
#endif
}

int qemu_can_receive_packet(NetClientState *nc)
{
if (nc->receive_disabled) {
return 0;
} else if (nc->info->can_receive &&
!nc->info->can_receive(nc)) {
return 0;
}
return 1;
}

int qemu_can_send_packet(NetClientState *sender)
{
int vm_running = runstate_is_running();
Expand All @@ -541,13 +552,7 @@ int qemu_can_send_packet(NetClientState *sender)
return 1;
}

if (sender->peer->receive_disabled) {
return 0;
} else if (sender->peer->info->can_receive &&
!sender->peer->info->can_receive(sender->peer)) {
return 0;
}
return 1;
return qemu_can_receive_packet(sender->peer);
}

static ssize_t filter_receive_iov(NetClientState *nc,
Expand Down Expand Up @@ -680,6 +685,25 @@ ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size)
return qemu_send_packet_async(nc, buf, size, NULL);
}

ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size)
{
if (!qemu_can_receive_packet(nc)) {
return 0;
}

return qemu_net_queue_receive(nc->incoming_queue, buf, size);
}

ssize_t qemu_receive_packet_iov(NetClientState *nc, const struct iovec *iov,
int iovcnt)
{
if (!qemu_can_receive_packet(nc)) {
return 0;
}

return qemu_net_queue_receive_iov(nc->incoming_queue, iov, iovcnt);
}

ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size)
{
return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW,
Expand Down
22 changes: 22 additions & 0 deletions net/queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,28 @@ static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue,
return ret;
}

ssize_t qemu_net_queue_receive(NetQueue *queue,
const uint8_t *data,
size_t size)
{
if (queue->delivering) {
return 0;
}

return qemu_net_queue_deliver(queue, NULL, 0, data, size);
}

ssize_t qemu_net_queue_receive_iov(NetQueue *queue,
const struct iovec *iov,
int iovcnt)
{
if (queue->delivering) {
return 0;
}

return qemu_net_queue_deliver_iov(queue, NULL, 0, iov, iovcnt);
}

ssize_t qemu_net_queue_send(NetQueue *queue,
NetClientState *sender,
unsigned flags,
Expand Down

0 comments on commit 705df54

Please sign in to comment.