From: Patrick Wildt <patrick@blueri.se>
To: u-boot@lists.denx.de
Subject: efi_loader: fix free() before use in RX path
Date: Tue, 6 Oct 2020 16:56:31 +0200 [thread overview]
Message-ID: <20201006145631.GA2844@jump> (raw)
Hi,
I have an EFI application doing TFTP on an i.MX8MM board. The EFI
application uses the Simple Network Protocol and does ARP itself.
ARP didn't work, and I saw that the replies that were received on
the board were broken.
Good, as seen from the sending host:
2acbc7b16422001999ed548808060001080006040002001999ed5488ac1f00012acbc7b16422ac1f007f000000000000000000000000000000000000
Bad, as seen on the i.MX8MM board:
60a7fc7f0000000060a7fc7f00000000080006040002001999ed5488ac1f00012acbc7b16422ac1f007f000000000000000000000000000000000000
As you can see, in the received packet, it looks like the the first
16 bytes were overwritten, and those look like two 64-bit pointer.
Looking through the stack, with uclass enabled, the code does:
eth_rx():
[..]
ret = eth_get_ops(current)->recv(current, flags, &packet);
flags = 0;
if (ret > 0)
net_process_received_packet(packet, ret);
if (ret >= 0 && eth_get_ops(current)->free_pkt)
eth_get_ops(current)->free_pkt(current, packet, ret);
[..]
recv returns the packet, free_pkt free()s the packet. Thus we may
only use the packet's contents between the recv and the free_pkt.
net_process_received_packet():
[..]
net_rx_packet = in_packet;
net_rx_packet_len = len;
[..]
if (push_packet) {
(*push_packet)(in_packet, len);
return;
}
[..]
push_packet is set to efi_net_push during efi_network_timer_notify,
which does nothing more than to set a status flag:
static void efi_net_push(void *pkt, int len)
{
new_rx_packet = true;
}
This does *not* touch the packet at all. Instead, efi_net_receive
will, as soon as the EFI application calls it, access net_rx_packet
directly. But this only happens *after* the packet has already been
free()d. Something else could have already started using that memory!
The following diff changes efi_net_push() to allocate a new buffer, but
I think it's not enough since eth_rx() will try to receive 32 packets
at one time. So I think maybe efi_net_push() needs to add the packets
to a list, and efi_net_receive() takes the first packet from that list.
Best regards,
Patrick
Signed-off-by: Patrick Wildt <patrick@blueri.se>
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index 22f0123eca..6e3c29cba2 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -25,6 +25,8 @@ static const efi_guid_t efi_pxe_base_code_protocol_guid =
EFI_PXE_BASE_CODE_PROTOCOL_GUID;
static struct efi_pxe_packet *dhcp_ack;
static bool new_rx_packet;
+static uchar *efi_net_rx_packet;
+static int efi_net_rx_packet_len;
static void *new_tx_packet;
static void *transmit_buffer;
@@ -607,11 +609,11 @@ static efi_status_t EFIAPI efi_net_receive
goto out;
}
/* Fill export parameters */
- eth_hdr = (struct ethernet_hdr *)net_rx_packet;
+ eth_hdr = (struct ethernet_hdr *)efi_net_rx_packet;
protlen = ntohs(eth_hdr->et_protlen);
if (protlen == 0x8100) {
hdr_size += 4;
- protlen = ntohs(*(u16 *)&net_rx_packet[hdr_size - 2]);
+ protlen = ntohs(*(u16 *)&efi_net_rx_packet[hdr_size - 2]);
}
if (header_size)
*header_size = hdr_size;
@@ -621,16 +623,19 @@ static efi_status_t EFIAPI efi_net_receive
memcpy(src_addr, eth_hdr->et_src, ARP_HLEN);
if (protocol)
*protocol = protlen;
- if (*buffer_size < net_rx_packet_len) {
+ if (*buffer_size < efi_net_rx_packet_len) {
/* Packet doesn't fit, try again with bigger buffer */
- *buffer_size = net_rx_packet_len;
+ *buffer_size = efi_net_rx_packet_len;
ret = EFI_BUFFER_TOO_SMALL;
goto out;
}
/* Copy packet */
- memcpy(buffer, net_rx_packet, net_rx_packet_len);
- *buffer_size = net_rx_packet_len;
+ memcpy(buffer, efi_net_rx_packet, efi_net_rx_packet_len);
+ *buffer_size = efi_net_rx_packet_len;
new_rx_packet = 0;
+ free(efi_net_rx_packet);
+ efi_net_rx_packet = NULL;
+ efi_net_rx_packet_len = 0;
this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
out:
return EFI_EXIT(ret);
@@ -664,6 +669,13 @@ void efi_net_set_dhcp_ack(void *pkt, int len)
*/
static void efi_net_push(void *pkt, int len)
{
+ efi_net_rx_packet = malloc(len);
+ if (efi_net_rx_packet == NULL)
+ return;
+
+ memcpy(efi_net_rx_packet, pkt, len);
+ efi_net_rx_packet_len = len;
+
new_rx_packet = true;
}
next reply other threads:[~2020-10-06 14:56 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-10-06 14:56 Patrick Wildt [this message]
2020-10-06 16:32 ` efi_loader: fix free() before use in RX path Patrick Wildt
2020-10-06 20:26 ` Heinrich Schuchardt
2020-10-06 22:29 ` Patrick Wildt
2020-10-06 22:30 ` [PATCH] efi_loader: fix use after free in receive path Patrick Wildt
2020-10-06 22:45 ` Heinrich Schuchardt
2020-10-06 22:51 ` Patrick Wildt
2020-10-06 22:57 ` [PATCH v2 1/2] net: add a define for the number of packets received as batch Patrick Wildt
2020-10-06 22:59 ` [PATCH v2 2/2] efi_loader: fix use after free in receive path Patrick Wildt
2020-10-07 9:03 ` [PATCH v3 1/2] net: add a define for the number of packets received as batch Patrick Wildt
2020-10-07 9:04 ` [PATCH v3 2/2] efi_loader: fix use after free in receive path Patrick Wildt
2020-10-07 13:26 ` Heinrich Schuchardt
2020-11-20 22:56 ` Patrick Wildt
2020-11-20 23:31 ` Tom Rini
2020-11-21 1:36 ` Patrick Wildt
2020-10-07 10:51 ` [PATCH v3 1/2] net: add a define for the number of packets received as batch Heinrich Schuchardt
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=20201006145631.GA2844@jump \
--to=patrick@blueri.se \
--cc=u-boot@lists.denx.de \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.