Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753881AbeAKGNW (ORCPT + 1 other); Thu, 11 Jan 2018 01:13:22 -0500 Received: from smtp.infotech.no ([82.134.31.41]:45756 "EHLO smtp.infotech.no" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751284AbeAKGNV (ORCPT ); Thu, 11 Jan 2018 01:13:21 -0500 X-Greylist: delayed 551 seconds by postgrey-1.27 at vger.kernel.org; Thu, 11 Jan 2018 01:13:20 EST Reply-To: dgilbert@interlog.com Subject: Re: scsi: memory leak in sg_start_req To: Dmitry Vyukov , jejb@linux.vnet.ibm.com, "Martin K. Petersen" , linux-scsi , LKML , Jens Axboe , linux-block@vger.kernel.org, syzkaller References: From: Douglas Gilbert Message-ID: Date: Thu, 11 Jan 2018 01:04:03 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.0 MIME-Version: 1.0 In-Reply-To: Content-Type: multipart/mixed; boundary="------------3625D9BE46E8B1E0F7D40F5F" Content-Language: en-CA Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Return-Path: This is a multi-part message in MIME format. --------------3625D9BE46E8B1E0F7D40F5F Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit On 2018-01-09 11:05 AM, Dmitry Vyukov wrote: > Hello, > > syzkaller has found the following memory leak: > > unreferenced object 0xffff88004c190000 (size 8328): > comm "syz-executor", pid 4627, jiffies 4294749150 (age 45.507s) > hex dump (first 32 bytes): > 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > 20 00 00 00 22 01 00 00 00 00 00 00 04 00 00 00 ..."........... > backtrace: > [<000000005955b5a9>] kmalloc_order+0x59/0x80 mm/slab_common.c:1124 > [<0000000043ae006e>] kmalloc_order_trace+0x1f/0x160 mm/slab_common.c:1133 > [<00000000d33b2e16>] kmalloc_large include/linux/slab.h:433 [inline] > [<00000000d33b2e16>] __kmalloc+0x2c4/0x340 mm/slub.c:3751 > [<00000000e7430040>] kmalloc include/linux/slab.h:504 [inline] > [<00000000e7430040>] bio_alloc_bioset+0x4d5/0x7e0 block/bio.c:450 > [<00000000f370e717>] bio_kmalloc include/linux/bio.h:410 [inline] > [<00000000f370e717>] bio_copy_user_iov+0x2be/0xcb0 block/bio.c:1226 > [<000000001d0b79ed>] __blk_rq_map_user_iov block/blk-map.c:67 [inline] > [<000000001d0b79ed>] blk_rq_map_user_iov+0x2b6/0x7d0 block/blk-map.c:136 > [<000000004200a869>] blk_rq_map_user+0x11e/0x170 block/blk-map.c:166 > [<000000008f21739e>] sg_start_req drivers/scsi/sg.c:1794 [inline] > [<000000008f21739e>] sg_common_write.isra.16+0x14df/0x1ed0 > drivers/scsi/sg.c:777 > [<00000000093f61e3>] sg_write+0x8a7/0xd7b drivers/scsi/sg.c:677 > [<00000000b67dafdc>] __vfs_write+0x10d/0x8f0 fs/read_write.c:480 > [<000000000638f16f>] vfs_write+0x1fd/0x570 fs/read_write.c:544 > [<000000006a7e6867>] SYSC_write fs/read_write.c:589 [inline] > [<000000006a7e6867>] SyS_write+0xfa/0x250 fs/read_write.c:581 > > can be reproduced with the following program: > > // autogenerated by syzkaller (http://github.com/google/syzkaller) > #include > #include > #include > #include > > int main() > { > int fd = open("/dev/sg1", O_RDWR); > const char *data = > "\xb6\x3d\xb8\x5e\x1e\x8d\x22\x00\x00\x00\x00\x00\x00\x08\xaf\xd6\x1d" > "\xcc\x43\x6a\xed\x5e\xd2\xbc\x70\x18\xce\xbc\x9b\x97\xae\x21\x91\x4d" > "\x87\x2c\x67\x8c\xe2\x2c\x9b\x16\x0e\x96\xaa\x1f\xae\x1a"; > write(fd, data, 0x30); > return 0; > } > > if executed in a loop, memory consumption grows infinitely. > > on upstream commit b2cd1df66037e7c4697c7e40496bf7e4a5e16a2d > The seemingly random data that program is sending is asking for a buffer of 2,264,314 bytes which the sg driver procures and waits for the caller to either issue a read() or close() the file or shutdown the program. The test program does none of those expected operations, it simply asks for the same resources again. In my version of your test code (attached), that happens 1,021 times at which point the file handles in that process are exhausted and all subsequent open()s fail with EBADF (as do the write()s). The output from my program was this on one run: # ./sg_syzk_grow First errno=9 [Bad file descriptor] index=1021 done_count=50000, err_count=48979, last_errno=9 [Bad file descriptor] # lsscsi -gs [0:0:0:0] disk Linux scsi_debug 0186 /dev/sda /dev/sg0 2.14GB Monitoring that program with 'free' from another terminal I see about 2.5 GBytes of ram "swallowed" almost immediately when the test program runs. When the program exits (about 50 seconds later) as far as I can see all that ram is given back. If you used the same program and wrote to a regular file rather than a sg device, then that program would eventually fill any file system, at the rate of 48 bytes per iteration (given enough file descriptor resources). The sg driver, using its original 1994 interface, deprecated for around 18 years, just gets a system to resource exhaustion quicker. Doug Gilbert --------------3625D9BE46E8B1E0F7D40F5F Content-Type: text/x-csrc; name="sg_syzk_grow.c" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="sg_syzk_grow.c" // autogenerated by syzkaller (http://github.com/google/syzkaller) #include #include #include #include #include #include #include #include static const char * sg_dev = "/dev/sg0"; int main() { const char *data = "\xb6\x3d\xb8\x5e\x1e\x8d\x22\x00\x00\x00\x00\x00\x00\x08\xaf\xd6\x1d" "\xcc\x43\x6a\xed\x5e\xd2\xbc\x70\x18\xce\xbc\x9b\x97\xae\x21\x91\x4d" "\x87\x2c\x67\x8c\xe2\x2c\x9b\x16\x0e\x96\xaa\x1f\xae\x1a"; int k, res, first_errno, prev_errno, first_err_index; int err_count = 0; int done_count = 0; bool got_1st_errno = false; for (k = 0; k < 10000; ++k) { int fd = open(sg_dev, O_RDWR); res = write(fd, data, 0x30); if (res < 0) { if (! got_1st_errno) { got_1st_errno = true; first_errno = errno; first_err_index = done_count + k; printf("First errno=%d [%s] index=%d\n", first_errno, strerror(first_errno), first_err_index); } ++err_count; } } done_count += k; sleep(10); for (k = 0; k < 10000; ++k) { int fd = open(sg_dev, O_RDWR); res = write(fd, data, 0x30); if (res < 0) { if (! got_1st_errno) { got_1st_errno = true; first_errno = errno; printf("First errno=%d [%s] index=%d\n", first_errno, strerror(first_errno), first_err_index); first_err_index = done_count + k; } ++err_count; } } done_count += k; sleep(10); for (k = 0; k < 10000; ++k) { int fd = open(sg_dev, O_RDWR); res = write(fd, data, 0x30); if (res < 0) ++err_count; } done_count += k; sleep(10); for (k = 0; k < 10000; ++k) { int fd = open(sg_dev, O_RDWR); res = write(fd, data, 0x30); if (res < 0) ++err_count; } done_count += k; sleep(10); for (k = 0; k < 10000; ++k) { int fd = open(sg_dev, O_RDWR); res = write(fd, data, 0x30); if (res < 0) { prev_errno = errno; ++err_count; } } done_count += k; sleep(10); printf("done_count=%d, err_count=%d, last_errno=%d [%s]\n", done_count, err_count, prev_errno, strerror(prev_errno)); return 0; } --------------3625D9BE46E8B1E0F7D40F5F--