Andrew Geissler | c926e17 | 2021-05-07 16:11:35 -0500 | [diff] [blame^] | 1 | From 4b1988a29d67277d6c8ce1df52975f5616592913 Mon Sep 17 00:00:00 2001 |
| 2 | From: Jason Wang <jasowang@redhat.com> |
| 3 | Date: Wed, 24 Feb 2021 11:44:36 +0800 |
| 4 | Subject: [PATCH 01/10] net: introduce qemu_receive_packet() |
| 5 | MIME-Version: 1.0 |
| 6 | Content-Type: text/plain; charset=UTF-8 |
| 7 | Content-Transfer-Encoding: 8bit |
| 8 | |
| 9 | Some NIC supports loopback mode and this is done by calling |
| 10 | nc->info->receive() directly which in fact suppresses the effort of |
| 11 | reentrancy check that is done in qemu_net_queue_send(). |
| 12 | |
| 13 | Unfortunately we can't use qemu_net_queue_send() here since for |
| 14 | loopback there's no sender as peer, so this patch introduce a |
| 15 | qemu_receive_packet() which is used for implementing loopback mode |
| 16 | for a NIC with this check. |
| 17 | |
| 18 | NIC that supports loopback mode will be converted to this helper. |
| 19 | |
| 20 | This is intended to address CVE-2021-3416. |
| 21 | |
| 22 | Cc: Prasad J Pandit <ppandit@redhat.com> |
| 23 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> |
| 24 | Cc: qemu-stable@nongnu.org |
| 25 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
| 26 | |
| 27 | Upstream-Status: Backport [705df5466c98f3efdd2b68d3b31dad86858acad7] |
| 28 | CVE: CVE-2021-3416 |
| 29 | |
| 30 | Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> |
| 31 | --- |
| 32 | include/net/net.h | 5 +++++ |
| 33 | include/net/queue.h | 8 ++++++++ |
| 34 | net/net.c | 38 +++++++++++++++++++++++++++++++------- |
| 35 | net/queue.c | 22 ++++++++++++++++++++++ |
| 36 | 4 files changed, 66 insertions(+), 7 deletions(-) |
| 37 | |
| 38 | diff --git a/include/net/net.h b/include/net/net.h |
| 39 | index 778fc787c..03f058ecb 100644 |
| 40 | --- a/include/net/net.h |
| 41 | +++ b/include/net/net.h |
| 42 | @@ -143,12 +143,17 @@ void *qemu_get_nic_opaque(NetClientState *nc); |
| 43 | void qemu_del_net_client(NetClientState *nc); |
| 44 | typedef void (*qemu_nic_foreach)(NICState *nic, void *opaque); |
| 45 | void qemu_foreach_nic(qemu_nic_foreach func, void *opaque); |
| 46 | +int qemu_can_receive_packet(NetClientState *nc); |
| 47 | int qemu_can_send_packet(NetClientState *nc); |
| 48 | ssize_t qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, |
| 49 | int iovcnt); |
| 50 | ssize_t qemu_sendv_packet_async(NetClientState *nc, const struct iovec *iov, |
| 51 | int iovcnt, NetPacketSent *sent_cb); |
| 52 | ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size); |
| 53 | +ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size); |
| 54 | +ssize_t qemu_receive_packet_iov(NetClientState *nc, |
| 55 | + const struct iovec *iov, |
| 56 | + int iovcnt); |
| 57 | ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size); |
| 58 | ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf, |
| 59 | int size, NetPacketSent *sent_cb); |
| 60 | diff --git a/include/net/queue.h b/include/net/queue.h |
| 61 | index c0269bb1d..9f2f289d7 100644 |
| 62 | --- a/include/net/queue.h |
| 63 | +++ b/include/net/queue.h |
| 64 | @@ -55,6 +55,14 @@ void qemu_net_queue_append_iov(NetQueue *queue, |
| 65 | |
| 66 | void qemu_del_net_queue(NetQueue *queue); |
| 67 | |
| 68 | +ssize_t qemu_net_queue_receive(NetQueue *queue, |
| 69 | + const uint8_t *data, |
| 70 | + size_t size); |
| 71 | + |
| 72 | +ssize_t qemu_net_queue_receive_iov(NetQueue *queue, |
| 73 | + const struct iovec *iov, |
| 74 | + int iovcnt); |
| 75 | + |
| 76 | ssize_t qemu_net_queue_send(NetQueue *queue, |
| 77 | NetClientState *sender, |
| 78 | unsigned flags, |
| 79 | diff --git a/net/net.c b/net/net.c |
| 80 | index 6a2c3d956..5e15e5d27 100644 |
| 81 | --- a/net/net.c |
| 82 | +++ b/net/net.c |
| 83 | @@ -528,6 +528,17 @@ int qemu_set_vnet_be(NetClientState *nc, bool is_be) |
| 84 | #endif |
| 85 | } |
| 86 | |
| 87 | +int qemu_can_receive_packet(NetClientState *nc) |
| 88 | +{ |
| 89 | + if (nc->receive_disabled) { |
| 90 | + return 0; |
| 91 | + } else if (nc->info->can_receive && |
| 92 | + !nc->info->can_receive(nc)) { |
| 93 | + return 0; |
| 94 | + } |
| 95 | + return 1; |
| 96 | +} |
| 97 | + |
| 98 | int qemu_can_send_packet(NetClientState *sender) |
| 99 | { |
| 100 | int vm_running = runstate_is_running(); |
| 101 | @@ -540,13 +551,7 @@ int qemu_can_send_packet(NetClientState *sender) |
| 102 | return 1; |
| 103 | } |
| 104 | |
| 105 | - if (sender->peer->receive_disabled) { |
| 106 | - return 0; |
| 107 | - } else if (sender->peer->info->can_receive && |
| 108 | - !sender->peer->info->can_receive(sender->peer)) { |
| 109 | - return 0; |
| 110 | - } |
| 111 | - return 1; |
| 112 | + return qemu_can_receive_packet(sender->peer); |
| 113 | } |
| 114 | |
| 115 | static ssize_t filter_receive_iov(NetClientState *nc, |
| 116 | @@ -679,6 +684,25 @@ ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) |
| 117 | return qemu_send_packet_async(nc, buf, size, NULL); |
| 118 | } |
| 119 | |
| 120 | +ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size) |
| 121 | +{ |
| 122 | + if (!qemu_can_receive_packet(nc)) { |
| 123 | + return 0; |
| 124 | + } |
| 125 | + |
| 126 | + return qemu_net_queue_receive(nc->incoming_queue, buf, size); |
| 127 | +} |
| 128 | + |
| 129 | +ssize_t qemu_receive_packet_iov(NetClientState *nc, const struct iovec *iov, |
| 130 | + int iovcnt) |
| 131 | +{ |
| 132 | + if (!qemu_can_receive_packet(nc)) { |
| 133 | + return 0; |
| 134 | + } |
| 135 | + |
| 136 | + return qemu_net_queue_receive_iov(nc->incoming_queue, iov, iovcnt); |
| 137 | +} |
| 138 | + |
| 139 | ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) |
| 140 | { |
| 141 | return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW, |
| 142 | diff --git a/net/queue.c b/net/queue.c |
| 143 | index 19e32c80f..c872d51df 100644 |
| 144 | --- a/net/queue.c |
| 145 | +++ b/net/queue.c |
| 146 | @@ -182,6 +182,28 @@ static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue, |
| 147 | return ret; |
| 148 | } |
| 149 | |
| 150 | +ssize_t qemu_net_queue_receive(NetQueue *queue, |
| 151 | + const uint8_t *data, |
| 152 | + size_t size) |
| 153 | +{ |
| 154 | + if (queue->delivering) { |
| 155 | + return 0; |
| 156 | + } |
| 157 | + |
| 158 | + return qemu_net_queue_deliver(queue, NULL, 0, data, size); |
| 159 | +} |
| 160 | + |
| 161 | +ssize_t qemu_net_queue_receive_iov(NetQueue *queue, |
| 162 | + const struct iovec *iov, |
| 163 | + int iovcnt) |
| 164 | +{ |
| 165 | + if (queue->delivering) { |
| 166 | + return 0; |
| 167 | + } |
| 168 | + |
| 169 | + return qemu_net_queue_deliver_iov(queue, NULL, 0, iov, iovcnt); |
| 170 | +} |
| 171 | + |
| 172 | ssize_t qemu_net_queue_send(NetQueue *queue, |
| 173 | NetClientState *sender, |
| 174 | unsigned flags, |
| 175 | -- |
| 176 | 2.29.2 |
| 177 | |