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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox