summaryrefslogtreecommitdiffstats
path: root/src/interface
diff options
context:
space:
mode:
authorMichael Brown2017-09-07 00:18:29 +0200
committerMichael Brown2017-09-07 00:28:21 +0200
commit3f429bdcfe0c3698f886e93a1f603656ccaa0f28 (patch)
treec68f71887170586c36c84e5e68e76f68a53c0372 /src/interface
parent[dns] Report current DNS query as job progress status message (diff)
downloadipxe-3f429bdcfe0c3698f886e93a1f603656ccaa0f28.tar.gz
ipxe-3f429bdcfe0c3698f886e93a1f603656ccaa0f28.tar.xz
ipxe-3f429bdcfe0c3698f886e93a1f603656ccaa0f28.zip
[efi] Check buffer length for packets retrieved via our SNP protocol
We do not currently check the length of the caller's buffer for received packets. This creates a potential buffer overrun when iPXE is being used via the SNP or UNDI protocols. Fix by checking the buffer length and correctly returning the required length and an EFI_BUFFER_TOO_SMALL error. Reported-by: Paul McMillan <paul.mcmillan@oracle.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/interface')
-rw-r--r--src/interface/efi/efi_snp.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c
index e6388bf6..5c3592e5 100644
--- a/src/interface/efi/efi_snp.c
+++ b/src/interface/efi/efi_snp.c
@@ -710,6 +710,7 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
const void *iob_ll_src;
uint16_t iob_net_proto;
unsigned int iob_flags;
+ size_t max_len;
int rc;
DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data,
@@ -722,19 +723,28 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
/* Poll the network device */
efi_snp_poll ( snpdev );
- /* Dequeue a packet, if one is available */
+ /* Check for an available packet */
iobuf = list_first_entry ( &snpdev->rx, struct io_buffer, list );
if ( ! iobuf ) {
DBGC2 ( snpdev, "\n" );
rc = -EAGAIN;
goto out_no_packet;
}
- list_del ( &iobuf->list );
DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
+ /* Check buffer length */
+ max_len = *len;
+ *len = iob_len ( iobuf );
+ if ( *len > max_len ) {
+ rc = -ERANGE;
+ goto out_too_long;
+ }
+
+ /* Dequeue packet */
+ list_del ( &iobuf->list );
+
/* Return packet to caller */
memcpy ( data, iobuf->data, iob_len ( iobuf ) );
- *len = iob_len ( iobuf );
/* Attempt to decode link-layer header */
if ( ( rc = ll_protocol->pull ( snpdev->netdev, iobuf, &iob_ll_dest,
@@ -759,6 +769,7 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
out_bad_ll_header:
free_iob ( iobuf );
+ out_too_long:
out_no_packet:
return EFIRC ( rc );
}