]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Check buffer length for packets retrieved via our SNP protocol
authorMichael Brown <mcb30@ipxe.org>
Wed, 6 Sep 2017 22:18:29 +0000 (23:18 +0100)
committerMichael Brown <mcb30@ipxe.org>
Wed, 6 Sep 2017 22:28:21 +0000 (23:28 +0100)
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>
src/interface/efi/efi_snp.c

index e6388bf67a266f2fe3f86e54ddf9268973b8a099..5c3592e5217bfedb896820accaee607df533b10e 100644 (file)
@@ -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 );
 }