diff options
author | Michael Brown | 2017-09-07 00:18:29 +0200 |
---|---|---|
committer | Michael Brown | 2017-09-07 00:28:21 +0200 |
commit | 3f429bdcfe0c3698f886e93a1f603656ccaa0f28 (patch) | |
tree | c68f71887170586c36c84e5e68e76f68a53c0372 /src/interface | |
parent | [dns] Report current DNS query as job progress status message (diff) | |
download | ipxe-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.c | 17 |
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 ); } |