Bug 1193802 (CVE-2021-39685) - VUL-0: CVE-2021-39685: kernel-source-rt, kernel-source-azure, kernel-source: USB Gadget buffer overflow
Summary: VUL-0: CVE-2021-39685: kernel-source-rt, kernel-source-azure, kernel-source: ...
Status: RESOLVED FIXED
Alias: CVE-2021-39685
Product: SUSE Security Incidents
Classification: Novell Products
Component: Incidents (show other bugs)
Version: unspecified
Hardware: Other Other
: P3 - Medium : Normal
Target Milestone: ---
Assignee: Security Team bot
QA Contact: Security Team bot
URL: https://smash.suse.de/issue/317621/
Whiteboard: CVSSv3.1:SUSE:CVE-2021-39685:7.8:(AV:...
Keywords:
Depends on:
Blocks: 1194459
  Show dependency treegraph
 
Reported: 2021-12-16 09:30 UTC by Thomas Leroy
Modified: 2024-06-25 16:30 UTC (History)
3 users (show)

See Also:
Found By: Security Response Team
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Thomas Leroy 2021-12-16 09:30:06 UTC
oss-sec
mailing list archives

CVE-2021-39685 : Linux Kernel USB Gadget buffer overflow


From: Szymon Heidrich 
Date: Wed, 15 Dec 2021 22:22:33 +0100


Hello,

As some of you might have already observed a buffer overflow vulnerability
was recently patched in the Linux USB Gadget subsystem.

TLTR; The issue reported to the Linux security team allowed one to read 
and/or write up to 65kB of kernel memory past buffer boundaries by exploiting
lack of limiting of the usb control transfer request wLength in certain
gadget functions.

You can find more details below. I also attached a sample exploit script
based on pyusb to this message. You can also find a up to date version
on my github under https://github.com/szymonh/inspector-gadget.

Best regards,
Szymon

---

Summary

An attacker can access kernel memory bypassing valid buffer boundaries by exploiting implementation of control request 
handlers in the following usb gadgets - rndis, hid, uac1, uac1_legacy and uac2. Processing of malicious control 
transfer requests with unexpectedly large wLength lacks assurance that this value does not exceed the buffer size. Due 
to this fact one is capable of reading and/or writing (depending on particular case) up to 65k of kernel memory.

Description

Some execution paths of usb control transfer handlers of gadgets such as rndis, hid, uac1, uac1_legacy and uac2 do not 
include proper handling of request length (wLength). This value should be limited to buffer size to prevent buffer 
overflow vulnerabilities in the data transfer phase. 

The buffer used by endpoint 0 is allocated in composite.c with size of USB_COMP_EP0_BUFSIZ (4096) bytes so
setting wLength to a value greater than USB_COMP_EP0_BUFSIZ will result in a buffer overflow.

For example in the case of f_uac1.c, execution of the f_audio_setup function allows one to perform both reads and 
writes past buffer boundaries. Neither f_audio_setup nor none of the called functions - audio_set_endpoint_req, 
audio_get_endpoint_req, out_rq_cur, ac_rq_in limit the return value to be smaller than the buffer size. Consequently 
the data transfer phase uses req->length = value = ctrl->wLength which is controlled by the attacker. This allows one 
to either read or write up to 65k bytes of kernel memory depending on the control transfer direction.

    static int
    f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
    {
            struct usb_composite_dev *cdev = f->config->cdev;
            struct usb_request      *req = cdev->req;
            int                     value = -EOPNOTSUPP;
            u16                     w_index = le16_to_cpu(ctrl->wIndex);
            u16                     w_value = le16_to_cpu(ctrl->wValue);
            u16                     w_length = le16_to_cpu(ctrl->wLength);

            /* composite driver infrastructure handles everything; interface
             * activation uses set_alt().
             */
            switch (ctrl->bRequestType) {
            case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
                    value = audio_set_endpoint_req(f, ctrl);
                    break;

            case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
                    value = audio_get_endpoint_req(f, ctrl);
                    break;
            case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
                    if (ctrl->bRequest == UAC_SET_CUR)
                            value = out_rq_cur(f, ctrl);
                    break;
            case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
                    value = ac_rq_in(f, ctrl);
                    break;
            default:
                    ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
                            ctrl->bRequestType, ctrl->bRequest,
                            w_value, w_index, w_length);
            }

            /* respond with data transfer or status phase? */
            if (value >= 0) {
                    DBG(cdev, "audio req%02x.%02x v%04x i%04x l%d\n",
                            ctrl->bRequestType, ctrl->bRequest,
                            w_value, w_index, w_length);
                    req->zero = 0;
                    req->length = value;
                    value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);

                    if (value < 0)
                            ERROR(cdev, "audio response on err %d\n", value);
            }

            /* device either stalls (value < 0) or reports success */
            return value;
    } 

 
Execution of the sample readout exploit allows dumping of up to 65k of memory.

    $ ./gadget.py -v 0x1b67 -p 0x400c -f uac1 | wc -c
    65535

     

    $ ./gadget.py -v 0x1b67 -p 0x400c -f uac1 | strings

    nsole=tty1 root=PARTUUID=e02024cb-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2
    tem.slice/system-getty.slice/getty@ttyGS0.service
    !rE*
    ?& .4!
    0usb_composite_setup_continue
    composite_setup
    usb_gadget_get_string
    usb_otg_descriptor_init
    usb_otg_descriptor_alloc
    usb_free_all_descriptors
    usb_assign_descriptors
    usb_copy_descriptors

    usb_gadget_config_buf 


On the other hand, execution of the overwrite exploit allows one to write arbitrary data past expected buffer 
boundaries.

    $ ./gadget.py -v 0x1b67 -p 0x400c -f uac1 -d write


    Message from syslogd@zero at Dec  6 19:56:01 ...
     kernel:[  103.850206] Internal error: Oops: 5 [#1] ARM


Similarly in case of the rndis gadget the rndis_setup function can be exploited to write past buffer boundaries using 
control transfer request with direction out, type class, recipient interface and bRequest set to 
USB_CDC_SEND_ENCAPSULATED_COMMAND. 

    static int
    rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
    {
            struct f_rndis          *rndis = func_to_rndis(f);
            struct usb_composite_dev *cdev = f->config->cdev;
            struct usb_request      *req = cdev->req;
            int                     value = -EOPNOTSUPP;
            u16                     w_index = le16_to_cpu(ctrl->wIndex);
            u16                     w_value = le16_to_cpu(ctrl->wValue);
            u16                     w_length = le16_to_cpu(ctrl->wLength);
            /* composite driver infrastructure handles everything except
             * CDC class messages; interface activation uses set_alt().
             */
            switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
            /* RNDIS uses the CDC command encapsulation mechanism to implement
             * an RPC scheme, with much getting/setting of attributes by OID.
             */
            case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
                            | USB_CDC_SEND_ENCAPSULATED_COMMAND:
                    if (w_value || w_index != rndis->ctrl_id)
                            goto invalid;
                    /* read the request; process it later */
                    value = w_length;
                    req->complete = rndis_command_complete;
                    req->context = rndis;
                    /* later, rndis_response_available() sends a notification */
                    break;

     ... 

     ...

            /* respond with data transfer or status phase? */
            if (value >= 0) {
                    DBG(cdev, "rndis req%02x.%02x v%04x i%04x l%d\n",
                            ctrl->bRequestType, ctrl->bRequest,
                            w_value, w_index, w_length);
                    req->zero = (value < w_length);
                    req->length = value;
                    value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
                    if (value < 0)
                            ERROR(cdev, "rndis response on err %d\n", value);
            }
            /* device either stalls (value < 0) or reports success */
            return value;

    } 


Vulnerable execution paths:
- f_rndis.c
    - rndis_setup
- f_uac1.c
    - out_rq_cur
    - ac_rq_in
    - audio_set_endpoint_req
    - audio_get_endpoint_req
- f_uac1_legacy.c
    - audio_set_intf_req
    - audio_set_endpoint_req
    - audio_get_endpoint_req
- f_uac2.c
    - out_rq_cur
- f_hid.c
    - hid_gsetup for HID_REQ_SET_REPORT case

Impact

Devices implementing affected usb device gadget classes (rndis, hid, uac1, uac1_legacy, uac2) may be affected by buffer 
overflow vulnerabilities resulting in information disclosure, denial of service or execution of arbitrary code in 
kernel context.

Expected resolution

Limit the transfer phase size to min(len, buffer_size) in affected control request handlers to assure that a buffer 
overflow will not occur.

Key dates

- 07.12.2021 - reported the issue to Kernel security team
- 09.12.2021 - draft patch provided by Kernel security team
- 12.12.2021 - fix merged to main Linux kernel tree (public)


I attached sample exploits based on pyusb. For optimal results libusb on the malicious host should be compiled with 
support for large request transfer messages (MAX_CTRL_BUFFER_LENGTH).



Ressources:
http://seclists.org/oss-sec/2021/q4/164
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2021-39685
Comment 1 Thomas Leroy 2021-12-16 14:13:31 UTC
I think the fixing commit is the following one:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=153a2d7e3350cc89d406ba2d35be8793a64c2038

Is is contained on stable and SLE15-SP4 branches.

However, the vulnerability seems quite old. The composite_setup function didn't contain any len check before the fix, and has been created a long time ago [0]. So the vulnerability is probably present since the adding of the reachable usb gadget component where a crash can occur (rndis, uac1, uac2, uac1_legacy and hid).


[0] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=40982be52d8f64c3e10adce17e66ab755a4fa26b
Comment 5 Oliver Neukum 2022-01-26 11:11:47 UTC
The affected branches are SLE15-SP3 SLE15-SP4

No other branch has a configuration that makes it vulnerable to that issue.
The fix had been applied and I've updated the references.
Comment 13 Swamp Workflow Management 2022-02-10 20:24:54 UTC
openSUSE-SU-2022:0363-1: An update that solves 12 vulnerabilities and has 20 fixes is now available.

Category: security (critical)
Bug References: 1154353,1154488,1160634,1176447,1177599,1183405,1185377,1187428,1187723,1188605,1191881,1193096,1193506,1193767,1193802,1193861,1193864,1193867,1194048,1194227,1194291,1194880,1195009,1195062,1195065,1195073,1195183,1195184,1195254,1195267,1195293,1195371
CVE References: CVE-2020-28097,CVE-2021-22600,CVE-2021-39648,CVE-2021-39657,CVE-2021-39685,CVE-2021-4159,CVE-2021-44733,CVE-2021-45095,CVE-2022-0286,CVE-2022-0330,CVE-2022-0435,CVE-2022-22942
JIRA References: 
Sources used:
openSUSE Leap 15.3 (src):    kernel-azure-5.3.18-150300.38.40.4, kernel-source-azure-5.3.18-150300.38.40.4, kernel-syms-azure-5.3.18-150300.38.40.1
Comment 14 Swamp Workflow Management 2022-02-10 20:34:19 UTC
SUSE-SU-2022:0363-1: An update that solves 12 vulnerabilities and has 20 fixes is now available.

Category: security (critical)
Bug References: 1154353,1154488,1160634,1176447,1177599,1183405,1185377,1187428,1187723,1188605,1191881,1193096,1193506,1193767,1193802,1193861,1193864,1193867,1194048,1194227,1194291,1194880,1195009,1195062,1195065,1195073,1195183,1195184,1195254,1195267,1195293,1195371
CVE References: CVE-2020-28097,CVE-2021-22600,CVE-2021-39648,CVE-2021-39657,CVE-2021-39685,CVE-2021-4159,CVE-2021-44733,CVE-2021-45095,CVE-2022-0286,CVE-2022-0330,CVE-2022-0435,CVE-2022-22942
JIRA References: 
Sources used:
SUSE Linux Enterprise Module for Public Cloud 15-SP3 (src):    kernel-azure-5.3.18-150300.38.40.4, kernel-source-azure-5.3.18-150300.38.40.4, kernel-syms-azure-5.3.18-150300.38.40.1

NOTE: This line indicates an update has been released for the listed product(s). At times this might be only a partial fix. If you have questions please reach out to maintenance coordination.
Comment 15 Swamp Workflow Management 2022-02-11 11:20:56 UTC
SUSE-SU-2022:0370-1: An update that solves 11 vulnerabilities and has 29 fixes is now available.

Category: security (critical)
Bug References: 1154353,1154488,1156395,1160634,1176447,1177599,1183405,1185377,1187428,1187723,1188605,1191881,1193096,1193506,1193767,1193802,1193861,1193864,1193867,1194048,1194227,1194291,1194880,1195009,1195062,1195065,1195073,1195183,1195184,1195254,1195267,1195293,1195371,1195476,1195477,1195478,1195479,1195480,1195481,1195482
CVE References: CVE-2020-28097,CVE-2021-22600,CVE-2021-39648,CVE-2021-39657,CVE-2021-39685,CVE-2021-44733,CVE-2021-45095,CVE-2022-0286,CVE-2022-0330,CVE-2022-0435,CVE-2022-22942
JIRA References: 
Sources used:
SUSE Linux Enterprise Workstation Extension 15-SP3 (src):    kernel-default-5.3.18-150300.59.49.1, kernel-preempt-5.3.18-150300.59.49.1
SUSE Linux Enterprise Module for Live Patching 15-SP3 (src):    kernel-default-5.3.18-150300.59.49.1, kernel-livepatch-SLE15-SP3_Update_14-1-150300.7.3.1
SUSE Linux Enterprise Module for Legacy Software 15-SP3 (src):    kernel-default-5.3.18-150300.59.49.1
SUSE Linux Enterprise Module for Development Tools 15-SP3 (src):    kernel-docs-5.3.18-150300.59.49.1, kernel-obs-build-5.3.18-150300.59.49.1, kernel-preempt-5.3.18-150300.59.49.1, kernel-source-5.3.18-150300.59.49.1, kernel-syms-5.3.18-150300.59.49.1
SUSE Linux Enterprise Module for Basesystem 15-SP3 (src):    kernel-64kb-5.3.18-150300.59.49.1, kernel-default-5.3.18-150300.59.49.1, kernel-default-base-5.3.18-150300.59.49.1.150300.18.31.1, kernel-preempt-5.3.18-150300.59.49.1, kernel-source-5.3.18-150300.59.49.1, kernel-zfcpdump-5.3.18-150300.59.49.1
SUSE Linux Enterprise Micro 5.1 (src):    kernel-default-5.3.18-150300.59.49.1, kernel-default-base-5.3.18-150300.59.49.1.150300.18.31.1
SUSE Linux Enterprise High Availability 15-SP3 (src):    kernel-default-5.3.18-150300.59.49.1

NOTE: This line indicates an update has been released for the listed product(s). At times this might be only a partial fix. If you have questions please reach out to maintenance coordination.
Comment 16 Swamp Workflow Management 2022-02-11 11:25:00 UTC
openSUSE-SU-2022:0370-1: An update that solves 11 vulnerabilities and has 29 fixes is now available.

Category: security (critical)
Bug References: 1154353,1154488,1156395,1160634,1176447,1177599,1183405,1185377,1187428,1187723,1188605,1191881,1193096,1193506,1193767,1193802,1193861,1193864,1193867,1194048,1194227,1194291,1194880,1195009,1195062,1195065,1195073,1195183,1195184,1195254,1195267,1195293,1195371,1195476,1195477,1195478,1195479,1195480,1195481,1195482
CVE References: CVE-2020-28097,CVE-2021-22600,CVE-2021-39648,CVE-2021-39657,CVE-2021-39685,CVE-2021-44733,CVE-2021-45095,CVE-2022-0286,CVE-2022-0330,CVE-2022-0435,CVE-2022-22942
JIRA References: 
Sources used:
openSUSE Leap 15.4 (src):    dtb-aarch64-5.3.18-150300.59.49.1, kernel-preempt-5.3.18-150300.59.49.1
openSUSE Leap 15.3 (src):    dtb-aarch64-5.3.18-150300.59.49.1, kernel-64kb-5.3.18-150300.59.49.1, kernel-debug-5.3.18-150300.59.49.1, kernel-default-5.3.18-150300.59.49.1, kernel-default-base-5.3.18-150300.59.49.1.150300.18.31.1, kernel-docs-5.3.18-150300.59.49.1, kernel-kvmsmall-5.3.18-150300.59.49.1, kernel-obs-build-5.3.18-150300.59.49.1, kernel-obs-qa-5.3.18-150300.59.49.1, kernel-preempt-5.3.18-150300.59.49.1, kernel-source-5.3.18-150300.59.49.1, kernel-syms-5.3.18-150300.59.49.1, kernel-zfcpdump-5.3.18-150300.59.49.1
Comment 18 Swamp Workflow Management 2022-02-21 17:23:19 UTC
SUSE-SU-2022:0543-1: An update that solves 9 vulnerabilities and has 29 fixes is now available.

Category: security (critical)
Bug References: 1154353,1154488,1156395,1160634,1176447,1177599,1183405,1185377,1187428,1187723,1188605,1191881,1193096,1193506,1193802,1193861,1193864,1193867,1194048,1194227,1194291,1194880,1195009,1195065,1195073,1195183,1195184,1195254,1195267,1195293,1195371,1195476,1195477,1195478,1195479,1195480,1195481,1195482
CVE References: CVE-2020-28097,CVE-2021-22600,CVE-2021-39648,CVE-2021-39657,CVE-2021-39685,CVE-2021-45095,CVE-2022-0286,CVE-2022-0330,CVE-2022-22942
JIRA References: 
Sources used:
SUSE Linux Enterprise Module for Realtime 15-SP3 (src):    kernel-rt-5.3.18-150300.76.1, kernel-rt_debug-5.3.18-150300.76.1, kernel-source-rt-5.3.18-150300.76.1, kernel-syms-rt-5.3.18-150300.76.1
SUSE Linux Enterprise Micro 5.1 (src):    kernel-rt-5.3.18-150300.76.1

NOTE: This line indicates an update has been released for the listed product(s). At times this might be only a partial fix. If you have questions please reach out to maintenance coordination.
Comment 19 Carlos López 2022-06-09 09:28:57 UTC
Done, closing.