Pull request for UEFI sub-system for efi-2021-01-rc1 (2)

A use after free in the UEFI network stack is fixed.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAl+N/tQACgkQxIHbvCwF
 GsTxbBAAmiql4LcM9DeSZPjRpza92PeYcsu0ZErvRgFJ2HdY88RpvK3UBeJRul2y
 CqdajQmusPX3mcCdwKVdLPiesAhDq5bOuZ5OPwixpkYr8QgFavkvN2YQLYm1Qzc7
 wc21QKET82lp4Xzc9qnIPtOheP6GPwN3Bvpgy2OaRviqiD82Ezp59D/9hjw5vu0p
 /SzFibYzZqyGGJiNk3sRSmxPa+mTZ1Zd3hq+ZFDEyw3SNcWtJ5bhFv/sl0CWVOOJ
 HGRVh6KfgW63ZNwyy4NYojUE5H62+l+AMYeNYf1zdFWtS2y1dxP3sP7IP/UizA3C
 UAYuq8qIuz8F1Hue29bbZcPVvge5bBou0B7ocO2B7mOqkr3ttKVBjXuJkkuTc4nm
 DcpqVZsbTV8gdmFNeX7BEAWjCGnzWxjlG8AOdb3VQHX/Trx1n1NxIerqF5pNny6w
 Vakh71DAxT782YoCHzJG3NJfRwLek7XfedNZhpbWgLd+uSIgDotMxyoMVYLxN3Vz
 98ejZ0XP9XDFgrpNjQqmBC3Re+CSmU3n8amIyG8SHkd4QiroCC0O7qRhamjq1JAu
 w2XsPfaJyOJ9ugzy+LB5/SbRPMlZu6Cr3wahNyBmpOmGyDOpRwKXJB7gjljMndnQ
 IXVw3ADpqHyymsOikD/NDCSvJQWWWIGtPMpzT0CjWGfa6iwZmBU=
 =YCCZ
 -----END PGP SIGNATURE-----

Merge tag 'efi-2021-01-rc1-2' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi

Pull request for UEFI sub-system for efi-2021-01-rc1 (2)

A use after free in the UEFI network stack is fixed.
This commit is contained in:
Tom Rini 2020-10-21 19:13:05 -04:00
commit 5d92dacbbe
3 changed files with 73 additions and 24 deletions

View file

@ -44,6 +44,9 @@ struct udevice;
#define PKTALIGN ARCH_DMA_MINALIGN
/* Number of packets processed together */
#define ETH_PACKETS_BATCH_RECV 32
/* ARP hardware address length */
#define ARP_HLEN 6
/*

View file

@ -24,9 +24,12 @@ static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
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 void *new_tx_packet;
static void *transmit_buffer;
static uchar **receive_buffer;
static size_t *receive_lengths;
static int rx_packet_idx;
static int rx_packet_num;
/*
* The notification function of this event is called in every timer cycle
@ -115,6 +118,8 @@ static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
} else {
/* Disable hardware and put it into the reset state */
eth_halt();
/* Clear cache of packets */
rx_packet_num = 0;
this->mode->state = EFI_NETWORK_STOPPED;
}
out:
@ -160,6 +165,8 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
net_init();
/* Disable hardware and put it into the reset state */
eth_halt();
/* Clear cache of packets */
rx_packet_num = 0;
/* Set current device according to environment variables */
eth_set_current();
/* Get hardware ready for send and receive operations */
@ -602,16 +609,16 @@ static efi_status_t EFIAPI efi_net_receive
break;
}
if (!new_rx_packet) {
if (!rx_packet_num) {
ret = EFI_NOT_READY;
goto out;
}
/* Fill export parameters */
eth_hdr = (struct ethernet_hdr *)net_rx_packet;
eth_hdr = (struct ethernet_hdr *)receive_buffer[rx_packet_idx];
protlen = ntohs(eth_hdr->et_protlen);
if (protlen == 0x8100) {
hdr_size += 4;
protlen = ntohs(*(u16 *)&net_rx_packet[hdr_size - 2]);
protlen = ntohs(*(u16 *)&receive_buffer[rx_packet_idx][hdr_size - 2]);
}
if (header_size)
*header_size = hdr_size;
@ -621,17 +628,22 @@ 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 < receive_lengths[rx_packet_idx]) {
/* Packet doesn't fit, try again with bigger buffer */
*buffer_size = net_rx_packet_len;
*buffer_size = receive_lengths[rx_packet_idx];
ret = EFI_BUFFER_TOO_SMALL;
goto out;
}
/* Copy packet */
memcpy(buffer, net_rx_packet, net_rx_packet_len);
*buffer_size = net_rx_packet_len;
new_rx_packet = 0;
this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
memcpy(buffer, receive_buffer[rx_packet_idx],
receive_lengths[rx_packet_idx]);
*buffer_size = receive_lengths[rx_packet_idx];
rx_packet_idx = (rx_packet_idx + 1) % ETH_PACKETS_BATCH_RECV;
rx_packet_num--;
if (rx_packet_num)
wait_for_packet->is_signaled = true;
else
this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
out:
return EFI_EXIT(ret);
}
@ -664,7 +676,26 @@ void efi_net_set_dhcp_ack(void *pkt, int len)
*/
static void efi_net_push(void *pkt, int len)
{
new_rx_packet = true;
int rx_packet_next;
/* Check that we at least received an Ethernet header */
if (len < sizeof(struct ethernet_hdr))
return;
/* Check that the buffer won't overflow */
if (len > PKTSIZE_ALIGN)
return;
/* Can't store more than pre-alloced buffer */
if (rx_packet_num >= ETH_PACKETS_BATCH_RECV)
return;
rx_packet_next = (rx_packet_idx + rx_packet_num) %
ETH_PACKETS_BATCH_RECV;
memcpy(receive_buffer[rx_packet_next], pkt, len);
receive_lengths[rx_packet_next] = len;
rx_packet_num++;
}
/**
@ -689,20 +720,14 @@ static void EFIAPI efi_network_timer_notify(struct efi_event *event,
if (!this || this->mode->state != EFI_NETWORK_INITIALIZED)
goto out;
if (!new_rx_packet) {
if (!rx_packet_num) {
push_packet = efi_net_push;
eth_rx();
push_packet = NULL;
if (new_rx_packet) {
/* Check that we at least received an Ethernet header */
if (net_rx_packet_len >=
sizeof(struct ethernet_hdr)) {
this->int_status |=
EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
wait_for_packet->is_signaled = true;
} else {
new_rx_packet = 0;
}
if (rx_packet_num) {
this->int_status |=
EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
wait_for_packet->is_signaled = true;
}
}
out:
@ -830,6 +855,7 @@ efi_status_t efi_net_register(void)
{
struct efi_net_obj *netobj = NULL;
efi_status_t r;
int i;
if (!eth_get_dev()) {
/* No network device active, don't expose any */
@ -847,6 +873,21 @@ efi_status_t efi_net_register(void)
goto out_of_resources;
transmit_buffer = (void *)ALIGN((uintptr_t)transmit_buffer, PKTALIGN);
/* Allocate a number of receive buffers */
receive_buffer = calloc(ETH_PACKETS_BATCH_RECV,
sizeof(*receive_buffer));
if (!receive_buffer)
goto out_of_resources;
for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
receive_buffer[i] = malloc(PKTSIZE_ALIGN);
if (!receive_buffer[i])
goto out_of_resources;
}
receive_lengths = calloc(ETH_PACKETS_BATCH_RECV,
sizeof(*receive_lengths));
if (!receive_lengths)
goto out_of_resources;
/* Hook net up to the device list */
efi_add_handle(&netobj->header);
@ -941,7 +982,12 @@ failure_to_add_protocol:
return r;
out_of_resources:
free(netobj);
/* free(transmit_buffer) not needed yet */
free(transmit_buffer);
if (receive_buffer)
for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++)
free(receive_buffer[i]);
free(receive_buffer);
free(receive_lengths);
printf("ERROR: Out of memory\n");
return EFI_OUT_OF_RESOURCES;
}

View file

@ -383,7 +383,7 @@ int eth_rx(void)
/* Process up to 32 packets at one time */
flags = ETH_RECV_CHECK_DEVICE;
for (i = 0; i < 32; i++) {
for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
ret = eth_get_ops(current)->recv(current, flags, &packet);
flags = 0;
if (ret > 0)