All of lore.kernel.org
 help / color / mirror / Atom feed
* efi_loader: fix free() before use in RX path
@ 2020-10-06 14:56 Patrick Wildt
  2020-10-06 16:32 ` Patrick Wildt
  0 siblings, 1 reply; 16+ messages in thread
From: Patrick Wildt @ 2020-10-06 14:56 UTC (permalink / raw)
  To: u-boot

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;
 }
 

^ permalink raw reply related	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2020-11-21  1:36 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-10-06 14:56 efi_loader: fix free() before use in RX path Patrick Wildt
2020-10-06 16:32 ` 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

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.