Advertisement






FreeBSD <= 10 kernel qlxge/qlxgbe Driver IOCTL Multiple Kernel Memory Leak Bugs

CVE Category Price Severity
N/A CWE-416 N/A High
Author Risk Exploitation Type Date
Unknown High Local 2013-11-18
CVSS EPSS EPSSP
CVSS:4.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H 0.02192 0.50148

CVSS vector description

Our sensors found this exploit at: http://cxsecurity.com/ascii/WLB-2013110118

Below is a copy:

XADV-2013006
FreeBSD <= 10 kernel qlxge/qlxgbe Driver IOCTL Multiple Kernel Memory Leak Bugs


1. Overview

The qlxge Driver is Qlogic 10Gb Ethernet Driver for Qlogic 8100
Series CNA Adapter [1]. The qlxgbe for the QLogic 8300 series
of the same ethernet driver.

The qlxge/qlxgbe Driver in freebsd <= 10 has vulnerabilities to leak
arbitrary kernel memory to the userspace. It's occured at qls_eioctl()
/ ql_eioctl() kernel function and because no sanity check.

* Vulnerable Source Code:
  - qlxge: http://fxr.watson.org/fxr/source/dev/qlxge/qls_ioctl.c?v=FREEBSD10
  - qlxgbe: http://fxr.watson.org/fxr/source/dev/qlxgbe/ql_ioctl.c?v=FREEBSD10

* Credit:
  - x90c <[email protected]>
    (site: http://www.x90c.org)

* References:
  [1] http://fxr.watson.org/fxr/source/dev/qlxge/README.txt?v=FREEBSD10
  [2] http://fxr.watson.org/fxr/source/dev/ath/if_ath.c?v=FREEBSD10#L5881


2. Details

2.1 The vulerability for the qlxge driver

[/dev/qlxge/qls_ioctl.c?v=FREEBSD10#L80]
----
...
   40 #include "qls_ioctl.h"
   41 #include "qls_dump.h"
   42 extern qls_mpi_coredump_t ql_mpi_coredump; // XXX The leak kmem!
   43 
   44 static int qls_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
   45                 struct thread *td);
   46 
   47 static struct cdevsw qla_cdevsw = {
   48         .d_version = D_VERSION,
   49         .d_ioctl = qls_eioctl,// XXX qls_eioctl.
   50         .d_name = "qlxge",
   51 };
   52 
...

   80 static int
   81 qls_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
   82         struct thread *td)
   83 {
   84         qla_host_t *ha;
   85         int rval = 0;
   86         device_t pci_dev;
   87 
   88         qls_mpi_dump_t *mpi_dump;
   89 
   90         if ((ha = (qla_host_t *)dev->si_drv1) == NULL)
   91                 return ENXIO;
   92 
   93         pci_dev= ha->pci_dev;
   94 
   95         switch(cmd) {
   96 
   97         case QLA_MPI_DUMP:
   98                 mpi_dump = (qls_mpi_dump_t *)data; // mpi_dump = data(arg).
   99 
  100                 if (mpi_dump->size == 0) {
  101                         mpi_dump->size = sizeof (qls_mpi_coredump_t);

  102                 } else { // XXX mpi_dump->size > 0?

  103                         if (mpi_dump->size < sizeof (qls_mpi_coredump_t))
  104                                 rval = EINVAL;

  105                         else { // XXX mpi_dump_size > qls_mpi_coredump_t struct size?

  106                                 qls_mpi_core_dump(ha);

      /* XXX copy ql_mpi_coredump(static kmem) to userspace with 
       *     mpi_dump->size(arg). Kernel memory leak occured!
                                       */
  107                                 rval = copyout( &ql_mpi_coredump,
  108                                                 mpi_dump->dbuf,
  109                                                 mpi_dump->size);
----


2.2 The vulerability for the qlxgbe driver

[/dev/qlxgbe/ql_ioctl.c?v=FREEBSD10#L79]
----
46 static struct cdevsw qla_cdevsw = {
   47         .d_version = D_VERSION,
   48         .d_ioctl = ql_eioctl, /* XXX ql_eioctl! */
   49         .d_name = "qlcnic",
   50 };

...

  79 static int
   80 ql_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
   81         struct thread *td)
   82 {
   83         qla_host_t *ha;

...

   90         qla_rd_fw_dump_t *fw_dump;
   91         union {
   92                 qla_reg_val_t *rv;
   93                 qla_rd_flash_t *rdf;
   94                 qla_wr_flash_t *wrf;
   95                 qla_erase_flash_t *erf;
   96                 qla_offchip_mem_val_t *mem;
   97         } u;
   98 
   99 
  100         if ((ha = (qla_host_t *)dev->si_drv1) == NULL) /* XXX ha = dev->si_drv1. */
  101                 return ENXIO;
  102 
...
  105         switch(cmd) {
  106 
...
  218         case QLA_RD_FW_DUMP: /* XXX QLA_RD_FW_DUMP ioctl cmd */
  219 
  220                 if (ha->hw.mdump_init == 0) {
  221                         rval = EINVAL;
  222                         break;
  223                 }
  224                 
  225                 fw_dump = (qla_rd_fw_dump_t *)data; // XXX fw_dump = data(arg)

      /* XXX no sanity check and copy arbitrary ha... (the kmem)
                       *     kmem to userspace (kmem leak occured!)
                       */
  226                 if ((rval = copyout(ha->hw.dma_buf.minidump.dma_b,
  227                         fw_dump->md_template, fw_dump->template_size)))
  228                         rval = ENXIO;
  229                 break;
----


3. Patch code

[freebsd_qlxge_kmem_leak.patch]
----
+   if(mpi_dump->size > sizeof(qls_mpi_coredump_t))
+           return EINVAL;

    rval = copyout( &ql_mpi_coredump,
                    mpi_dump->dbuf,
                    mpi_dump->size);
----

[freebsd_qlxgbe_kmem_leak.patch]
----
+   if(fw_dump->template_size > sizeof(qla_host_t))
+       return EINVAL;
    if ((rval = copyout(ha->hw.dma_buf.minidump.dma_b,
        fw_dump->md_template, fw_dump->template_size)))
----


There's the vendor patch code.

[qlxg.diff]
----
Index: sys/dev/qlxgbe/ql_ioctl.c
===================================================================
--- sys/dev/qlxgbe/ql_ioctl.c(revision 258154)
+++ sys/dev/qlxgbe/ql_ioctl.c(working copy)
@@ -223,6 +223,10 @@ ql_eioctl(struct cdev *dev, u_long cmd, caddr_t da
 }
 
 fw_dump = (qla_rd_fw_dump_t *)data;
+if (fw_dump->template_size < ha->hw.dma_buf.minidump.size)
+return (EINVAL);
+else
+fw_dump->template_size = ha->hw.dma_buf.minidump.size;
 if ((rval = copyout(ha->hw.dma_buf.minidump.dma_b,
 fw_dump->md_template, fw_dump->template_size)))
 rval = ENXIO;
Index: sys/dev/qlxge/qls_ioctl.c
===================================================================
--- sys/dev/qlxge/qls_ioctl.c(revision 258154)
+++ sys/dev/qlxge/qls_ioctl.c(working copy)
@@ -103,10 +103,13 @@ qls_eioctl(struct cdev *dev, u_long cmd, caddr_t d
 if (mpi_dump->size < sizeof (qls_mpi_coredump_t))
 rval = EINVAL;
 else {
-qls_mpi_core_dump(ha);
-rval = copyout( &ql_mpi_coredump,
-mpi_dump->dbuf,
-mpi_dump->size);
+mpi_dump->size = sizeof(qls_mpi_coredump_t);
+if (qls_mpi_core_dump(ha) == 0) {
+rval = copyout( &ql_mpi_coredump,
+mpi_dump->dbuf,
+mpi_dump->size);
+} else
+rval = ENXIO;
 
 if (rval) {
 device_printf(ha->pci_dev,
----


4. Vendor Status

- 2013/11/12 I discovered two kernel memory leaks.
- 2013/11/14 Report to the vendor of [email protected].
- 2013/11/15 The vendor response with the coordination 
             with the vendor patch code. (will be freebsd's advisory)
- 2013/11/16 Cve-id for each bug request to the [email protected].
- 2013/11/16 The original advisory released on full-disclosure, bugtraq.


EOF


Copyright ©2024 Exploitalert.

This information is provided for TESTING and LEGAL RESEARCH purposes only.
All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum