lkml.org 
[lkml]   [2021]   [Apr]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH] usbhid: fix info leak in hid_submit_ctrl
    Date
    In hid_submit_ctrl(), the way of calculating the report length doesn't
    take into account that report->size can be zero. When running the
    syzkaller reproducer, a report of size 0 causes hid_submit_ctrl) to
    calculate transfer_buffer_length as 16384. When this urb is passed to
    the usb core layer, KMSAN reports an info leak of 16384 bytes.

    To fix this, first modify hid_report_len() to account for the zero
    report size case by using DIV_ROUND_UP for the division. Then, call it
    from hid_submit_ctrl().

    Reported-by: syzbot+7c2bb71996f95a82524c@syzkaller.appspotmail.com
    Signed-off-by: Anirudh Rayabharam <mail@anirudhrb.com>
    ---
    drivers/hid/usbhid/hid-core.c | 2 +-
    include/linux/hid.h | 3 +--
    2 files changed, 2 insertions(+), 3 deletions(-)

    diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
    index 86257ce6d619..4e9077363c96 100644
    --- a/drivers/hid/usbhid/hid-core.c
    +++ b/drivers/hid/usbhid/hid-core.c
    @@ -374,7 +374,7 @@ static int hid_submit_ctrl(struct hid_device *hid)
    raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report;
    dir = usbhid->ctrl[usbhid->ctrltail].dir;

    - len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
    + len = hid_report_len(report);
    if (dir == USB_DIR_OUT) {
    usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
    usbhid->urbctrl->transfer_buffer_length = len;
    diff --git a/include/linux/hid.h b/include/linux/hid.h
    index 271021e20a3f..10e922cee4eb 100644
    --- a/include/linux/hid.h
    +++ b/include/linux/hid.h
    @@ -1167,8 +1167,7 @@ static inline void hid_hw_wait(struct hid_device *hdev)
    */
    static inline u32 hid_report_len(struct hid_report *report)
    {
    - /* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
    - return ((report->size - 1) >> 3) + 1 + (report->id > 0);
    + return DIV_ROUND_UP(report->size, 8) + (report->id > 0);
    }

    int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
    --
    2.26.2
    \
     
     \ /
      Last update: 2021-04-25 19:38    [W:2.958 / U:0.156 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site