lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <e70ba561-dd55-c38d-62a4-dd2e0603be10@interlog.com>
Date:   Mon, 12 Apr 2021 12:35:59 -0400
From:   Douglas Gilbert <dgilbert@...erlog.com>
To:     Hao Sun <sunhao.th@...il.com>, axboe@...nel.dk, jejb@...ux.ibm.com,
        martin.petersen@...cle.com
Cc:     linux-block@...r.kernel.org, linux-kernel@...r.kernel.org,
        linux-scsi@...r.kernel.org
Subject: Re: KMSAN: kernel-infoleak in sg_scsi_ioctl

Hi,
See below.

On 2021-04-12 9:02 a.m., Hao Sun wrote:
> Hi
> 
> When using Healer(https://github.com/SunHao-0/healer/tree/dev) to fuzz
> the Linux kernel, I found the following bug report.
> 
> commit:   4ebaab5fb428374552175aa39832abf5cedb916a
> version:   linux 5.12
> git tree:    kmsan
> kernel config and full log can be found in the attached file.
> 
> =====================================================
> BUG: KMSAN: kernel-infoleak in kmsan_copy_to_user+0x9c/0xb0
> mm/kmsan/kmsan_hooks.c:249
> CPU: 2 PID: 23939 Comm: executor Not tainted 5.12.0-rc6+ #1
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
> 1.13.0-1ubuntu1.1 04/01/2014
> Call Trace:
>   __dump_stack lib/dump_stack.c:79 [inline]
>   dump_stack+0x1ff/0x275 lib/dump_stack.c:120
>   kmsan_report+0xfb/0x1e0 mm/kmsan/kmsan_report.c:118
>   kmsan_internal_check_memory+0x48c/0x520 mm/kmsan/kmsan.c:437
>   kmsan_copy_to_user+0x9c/0xb0 mm/kmsan/kmsan_hooks.c:249
>   instrument_copy_to_user ./include/linux/instrumented.h:121 [inline]
>   _copy_to_user+0x112/0x1d0 lib/usercopy.c:33
>   copy_to_user ./include/linux/uaccess.h:209 [inline]
>   sg_scsi_ioctl+0xfa9/0x1180 block/scsi_ioctl.c:507
>   sg_ioctl_common+0x2713/0x4930 drivers/scsi/sg.c:1108
>   sg_ioctl+0x166/0x2d0 drivers/scsi/sg.c:1162
>   vfs_ioctl fs/ioctl.c:48 [inline]
>   __do_sys_ioctl fs/ioctl.c:753 [inline]
>   __se_sys_ioctl+0x2c2/0x400 fs/ioctl.c:739
>   __x64_sys_ioctl+0x4a/0x70 fs/ioctl.c:739
>   do_syscall_64+0xa2/0x120 arch/x86/entry/common.c:48
>   entry_SYSCALL_64_after_hwframe+0x44/0xae
> RIP: 0033:0x47338d
> Code: 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa 48 89 f8 48
> 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d
> 01 f0 ff ff 73 01 c3 48 c7 c1 bc ff ff ff f7 d8 64 89 01 48
> RSP: 002b:00007fe31ab90c58 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
> RAX: ffffffffffffffda RBX: 000000000059c128 RCX: 000000000047338d
> RDX: 0000000020000040 RSI: 0000000000000001 RDI: 0000000000000003
> RBP: 00000000004e8e5d R08: 0000000000000000 R09: 0000000000000000
> R10: 0000000000000000 R11: 0000000000000246 R12: 000000000059c128
> R13: 00007ffe2284af2f R14: 00007ffe2284b0d0 R15: 00007fe31ab90dc0
> Uninit was stored to memory at:
>   kmsan_save_stack_with_flags mm/kmsan/kmsan.c:121 [inline]
>   kmsan_internal_chain_origin+0xad/0x130 mm/kmsan/kmsan.c:289
>   kmsan_memcpy_memmove_metadata+0x25b/0x290 mm/kmsan/kmsan.c:226
>   kmsan_memcpy_metadata+0xb/0x10 mm/kmsan/kmsan.c:246
>   __msan_memcpy+0x46/0x60 mm/kmsan/kmsan_instr.c:110
>   bio_copy_kern_endio_read+0x3ee/0x560 block/blk-map.c:443
>   bio_endio+0xa1a/0xcc0 block/bio.c:1453
>   req_bio_endio block/blk-core.c:265 [inline]
>   blk_update_request+0xd4f/0x2190 block/blk-core.c:1456
>   scsi_end_request+0x111/0xc50 drivers/scsi/scsi_lib.c:570
>   scsi_io_completion+0x276/0x2840 drivers/scsi/scsi_lib.c:970
>   scsi_finish_command+0x6fc/0x720 drivers/scsi/scsi.c:214
>   scsi_softirq_done+0x205/0xa40 drivers/scsi/scsi_lib.c:1450
>   blk_complete_reqs block/blk-mq.c:576 [inline]
>   blk_done_softirq+0x133/0x1e0 block/blk-mq.c:581
>   __do_softirq+0x271/0x782 kernel/softirq.c:345
> 
> Uninit was created at:
>   kmsan_save_stack_with_flags+0x3c/0x90
>   kmsan_alloc_page+0xc4/0x1b0
>   __alloc_pages_nodemask+0xdb0/0x54a0
>   alloc_pages_current+0x671/0x990
>   blk_rq_map_kern+0xb8e/0x1310
>   sg_scsi_ioctl+0xc94/0x1180
>   sg_ioctl_common+0x2713/0x4930
>   sg_ioctl+0x166/0x2d0
>   __se_sys_ioctl+0x2c2/0x400
>   __x64_sys_ioctl+0x4a/0x70
>   do_syscall_64+0xa2/0x120
>   entry_SYSCALL_64_after_hwframe+0x44/0xae
> 
> Byte 0 of 1 is uninitialized
>   Memory access of size 1 starts at ffff99e033fb9360
>   Data copied to user address 0000000020000048
> 
> The following system call sequence (Syzlang format) can reproduce the crash:
> # {Threaded:false Collide:false Repeat:false RepeatTimes:0 Procs:1
> Slowdown:1 Sandbox:none Fault:false FaultCall:-1 FaultNth:0 Leak:false
> NetInjection:true NetDevices:true NetReset:false Cgroups:false
> BinfmtMisc:true CloseFDs:true KCSAN:false DevlinkPCI:true USB:true
> VhciInjection:true Wifi:true IEEE802154:true Sysctl:true
> UseTmpDir:true HandleSegv:true Repro:false Trace:false}
> 
> r0 = syz_open_dev$sg(&(0x7f0000000000)='/dev/sg#\x00', 0x0, 0x20000094b402)
> ioctl$SG_GET_LOW_DMA(r0, 0x227a, &(0x7f0000000040))
> ioctl$SCSI_IOCTL_SEND_COMMAND(r0, 0x1, &(0x7f0000000040)={0x0, 0x1, 0x1})

Since the code opens a sg device node then the sg driver, which is a
pass-through driver, is invoked. However instead of using sg's pass-through
facilities, that call to ioctl(SCSI_IOCTL_SEND_COMMAND) is invoking the
long deprecated SCSI mid-level pass-through. So if there is infoleak bug
you should flag sg_scsi_ioctl() in block/scsi_ioctl.c. See the notes
associated with that function which imply it can't be protected from
certain types of abuse due to its interface design. That is why it is
deprecated. Also the equivalent of root permissions are required
to execute those functions.

That code looks strange, ioctl(SG_GET_LOW_DMA) reads the
host->unchecked_isa_dma value (now always 0 ??) into an int at
0x7f0000000040. That same address is then used for the struct
scsi_ioctl_command object passed to ioctl(SCSI_IOCTL_SEND_COMMAND).

Looking at the data passed to SCSI_IOCTL_SEND_COMMAND in_len=0
(data-out length in bytes), out_len=1 and, if 2 zero bytes follow
what is shown, that is a (SCSI-2) REZERO UNIT command which returns
no data. Now the BUG print-out seems to come from this line:
     copy_to_user(sic->data, buffer, out_len);

but buffer was kzalloc-ed and nothing was (should have been) DMA-ed
into it. So where is the problem?

Since the bio/block code isn't often asked to handle a block size
of 1 byte, this addition may strengthen things:
	if ((in_len % 512) != 0 || (out_len % 512) != 0)
		return -EINVAL;

Since bytes=max(in_len, out_len) then that can be simplified to:
	if ((bytes % 512) != 0)
		return -EINVAL;

Doug Gilbert

> Using syz-execprog can run this reproduction program directly:
>   ./syz-execprog -repeat 0 -procs 1 -slowdown 1 -enable tun -enable
> netdev -enable binfmt-misc -enable close_fds -enable devlinkpci
> -enable usb -enable vhci -enable wifi -enable ieee802154 -enable
> sysctl repro.prog
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ