[alsa-devel] sound: out-of-bounds write in snd_rawmidi_kernel_write1
Hello,
The following program triggers an out-of-bounds write in snd_rawmidi_kernel_write1 (run in parallel loop). It seems to try to copy -1 bytes (aka 4GB) from user space into kernel smashing all on its way.
================================================================== BUG: KASAN: use-after-free in memset+0x1a/0x30 at addr ffff8800326e3cef Write of size 4294950912 by task a.out/7292 ============================================================================= BUG kmalloc-4096 (Not tainted): kasan: bad access detected -----------------------------------------------------------------------------
INFO: Allocated in open_substream+0x2ff/0x780 age=288 cpu=1 pid=7287 [< none >] ___slab_alloc+0x564/0x5b0 mm/slub.c:2470 [< none >] __slab_alloc+0x66/0xc0 mm/slub.c:2499 [< inline >] slab_alloc_node mm/slub.c:2562 [< inline >] slab_alloc mm/slub.c:2604 [< none >] kmem_cache_alloc_trace+0x25c/0x300 mm/slub.c:2621 [< inline >] kmalloc include/linux/slab.h:463 [< inline >] snd_rawmidi_runtime_create sound/core/rawmidi.c:127 [< none >] open_substream+0x2ff/0x780 sound/core/rawmidi.c:266 [< none >] rawmidi_open_priv+0x144/0x300 sound/core/rawmidi.c:312 [< none >] snd_rawmidi_open+0x3fb/0xa90 sound/core/rawmidi.c:416 [< none >] soundcore_open+0x30f/0x640 sound/sound_core.c:639 [< none >] chrdev_open+0x22a/0x4c0 fs/char_dev.c:388 [< none >] do_dentry_open+0x6a2/0xcb0 fs/open.c:736 [< none >] vfs_open+0x17b/0x1f0 fs/open.c:853 [< inline >] do_last fs/namei.c:3254 [< none >] path_openat+0xde9/0x5e30 fs/namei.c:3386 [< none >] do_filp_open+0x18e/0x250 fs/namei.c:3421 [< none >] do_sys_open+0x1fc/0x420 fs/open.c:1022 [< inline >] SYSC_open fs/open.c:1040 [< none >] SyS_open+0x2d/0x40 fs/open.c:1035 [< none >] entry_SYSCALL_64_fastpath+0x16/0x7a arch/x86/entry/entry_64.S:185
Call Trace: [<ffffffff817654b7>] __asan_storeN+0x127/0x1a0 mm/kasan/kasan.c:522 [<ffffffff8176582a>] memset+0x1a/0x30 mm/kasan/kasan.c:280 [<ffffffff82c15294>] copy_user_handle_tail+0xb4/0xd0 arch/x86/lib/usercopy_64.c:86 [< inline >] copy_from_user ./arch/x86/include/asm/uaccess.h:735 [<ffffffff852855da>] snd_rawmidi_kernel_write1+0x34a/0x760 sound/core/rawmidi.c:1250 [<ffffffff852878b3>] snd_rawmidi_write+0x543/0xb30 sound/core/rawmidi.c:1318 [<ffffffff817b8be1>] do_loop_readv_writev+0x141/0x1e0 fs/read_write.c:719 [<ffffffff817bcb38>] do_readv_writev+0x5f8/0x6e0 fs/read_write.c:849 [<ffffffff817bcd56>] vfs_writev+0x86/0xc0 fs/read_write.c:886 [< inline >] SYSC_writev fs/read_write.c:919 [<ffffffff817bfec1>] SyS_writev+0x111/0x2b0 fs/read_write.c:911 [<ffffffff86661376>] entry_SYSCALL_64_fastpath+0x16/0x7a arch/x86/entry/entry_64.S:185 ==================================================================
// autogenerated by syzkaller (http://github.com/google/syzkaller) #include <pthread.h> #include <stdint.h> #include <string.h> #include <sys/syscall.h> #include <unistd.h>
long r[19];
int main() { memset(r, -1, sizeof(r)); r[0] = syscall(SYS_mmap, 0x20000000ul, 0x22000ul, 0x3ul, 0x32ul, 0xfffffffffffffffful, 0x0ul); r[2] = syscall(SYS_open, "/dev/midi3", 0x2ul, 0, 0, 0); *(uint64_t*)0x20013ffe = (uint64_t)0x20013f69; *(uint64_t*)0x20014006 = (uint64_t)0x97; *(uint64_t*)0x2001400e = (uint64_t)0x20003ffe; *(uint64_t*)0x20014016 = (uint64_t)0x3; *(uint64_t*)0x2001401e = (uint64_t)0x2001ef70; *(uint64_t*)0x20014026 = (uint64_t)0x92; *(uint64_t*)0x2001402e = (uint64_t)0x20014730; *(uint64_t*)0x20014036 = (uint64_t)0x1; *(uint64_t*)0x2001403e = (uint64_t)0x2001e000; *(uint64_t*)0x20014046 = (uint64_t)0x1000; memcpy((void*)0x20013f69, "\x0e\x6f\xfe\xa4\xc8\xbf\xaa\x28\x69\x82\xe0\x8c\x45\xab\x90" "\xb9\x6a\xeb\x50\x3d\x1a\x59\x59\x33\x0a\xa5\xb8\xfe\x83\x75" "\x1f\xb5\x25\x76\x65\x53\xb6\xe7\xe2\xe7\xe3\xd7\x55\x36\xb6" "\x59\x2f\xf8\x61\xda\xdb\x73\x32\x94\xb1\x0e\x17\x87\xad\x8f" "\x73\x6c\xc7\xeb\x47\xa2\x65\x77\xfb\xfc\xec\x70\x5c\x9e\x01" "\x78\xef\x1b\x69\xab\xef\x58\x13\x35\x99\xf0\x2b\x25\x99\xdb" "\xba\x16\xa7\x43\xc5\x19\x32\x91\x13\x24\x15\xd1\x5e\xb0\x1a" "\x5f\x63\xe2\xc3\x61\x9a\x79\x82\x57\x60\x21\x79\x6e\xf5\x21" "\x74\x18\xcf\x8f\x73\x93\x70\x3a\xfe\xf8\xe3\xde\x6a\x85\x3b" "\x5a\xfc\x0b\xfe\x02\x8f\x32\xe6\xc5\x14\x1c\x07\x24\xce\xcb" "\x95", 151); memcpy((void*)0x20003ffe, "\x3d\x07\x31", 3); memcpy((void*)0x2001ef70, "\x5c\x39\xe0\x3f\xe7\xdd\x08\xeb\x7c\xb0\xe7\x31\x09\xdf\x84" "\x1a\xbb\x98\xe1\xc8\x08\x00\x3b\xe9\xef\x62\x4a\x18\x10\xff" "\xa1\x7f\xa0\xd6\x81\x86\xed\xb5\x43\x33\x7c\xa6\x01\xb8\xfc" "\xe1\xee\x43\x95\x05\xf1\x5d\xa6\xb4\xb1\x62\x74\x82\xc6\x8b" "\x9f\xfb\x9b\xe8\x41\xee\x2e\x44\xc0\x20\x37\xca\xe5\x33\xf3" "\xeb\x9e\x2e\x15\x56\xce\x26\x5e\x6c\xee\xca\x49\x00\xe6\xf2" "\x21\xd4\x07\xf1\x00\xee\x21\x5a\xd5\x7a\x84\x4c\x3e\x7c\x8d" "\xe5\xb5\x35\x57\x69\xe4\x18\x09\x5b\xa7\xdb\xe6\x2f\x56\x78" "\x83\xa1\x0c\xdd\x07\x74\x32\xb2\x85\x75\xeb\x51\x5b\x22\xd1" "\x57\x95\xcd\xc2\xc4\xf9\x2e\xd8\xce\x9a\x52", 146); memcpy((void*)0x20014730, "\xc3", 1); memcpy( (void*)0x2001e000, "\xff\x20\xcc\xa3\x99\x07\x76\x17\xc4\x29\xef\xa5\x6a\xef\x9c\x9b" "\x58\x94\x16\xfc\x87\x60\xb1\x04\x16\x80\x1d\xcb\xfd\x8b\xd7\x9a" "\x41\x87\xb2\xdf\xe8\xc3\x17\x50\xd6\x5a\x01\x06\xc7\xc5\xb1\xf3" "\x56\x57\x81\xa8\x2c\x0b\x81\x67\x93\x59\xc1\xbb\xb5\x2d\x45\xc5" "\x27\x05\x66\x0b\xfd\x28\x1e\xdb\x45\x89\x34\x0b\x03\xfe\x5f\xa7" "\x47\xeb\xa1\xe0\xff\xe1\xdb\x12\xa7\x11\x37\xe0\x96\x53\xa2\x29" "\x1d\x3c\x3c\xda\x8e\x97\xeb\x58\x64\x8d\xff\x13\x70\x08\x96\x28" "\x32\x4e\xce\x4c\xb3\x17\x1c\x74\xa8\x8d\x7b\x78\x32\x4b\xcc\xf8" "\xf7\xcb\x33\x5c\xd5\x6b\xa3\x2a\x9c\x7c\x41\x3e\x87\x92\xec\x22" "\x44\x36\x28\x2d\x76\xde\x44\xa8\xef\x9d\x2c\xa2\xf2\xc5\x94\x2b" "\x3a\x17\xa4\xd7\x82\x4e\xef\xee\x1a\x4a\x6b\x98\xd5\xe4\x40\xbc" "\x5a\xe1\x76\x47\x17\x2b\x45\xb6\xb6\xa4\xeb\x5a\x54\x82\x6a\x98" "\x14\xf0\x4e\x5a\x8c\x30\x6a\x0f\xcb\x0f\x1b\x62\x8c\x48\x54\x16" "\xb8\x94\x28\xd0\xcc\x47\x4f\xb4\x01\x40\x3c\xb7\xed\xf0\x96\x2a" "\x55\xb2\xac\xf6\xa2\xab\x93\x19\x3f\xf6\xf8\xad\x8f\xa3\x5a\x6f" "\x15\x26\xa3\x25\xbb\x58\x6e\x02\x58\xfa\x3a\xcf\xd9\xf8\x17\xb9" "\xa1\x4c\x45\x16\x45\xcb\x7a\x84\x37\x3a\xb4\x3a\xc6\x98\xa9\x5c" "\xf4\x9e\xdb\xcf\xa9\xbb\xcc\xcb\x15\x36\x52\xb0\xcc\x3d\xd0\xfa" "\xd6\xc0\xff\xf6\xb7\x0e\x80\x31\x8e\x76\xfc\xe9\xd8\xf6\xb4\xbc" "\xfa\xec\x94\x13\x64\x9d\x13\x7e\x91\x9c\x10\x27\xda\xc8\xea\x9b" "\xc2\x09\x58\x81\x9e\x44\xf2\xc3\xef\x94\x6d\x2f\xa9\xa5\x19\xd7" "\x78\x61\x2e\xd3\x01\x8a\xc3\xac\x1b\xb9\xaa\x00\x12\xc5\x7e\x7f" "\x7b\x34\x27\x4c\x38\x00\x9c\x57\xa6\xe2\x5a\x5a\xe6\x00\x01\x56" "\xa2\xed\xa6\xcd\x95\x0b\xde\x5e\x09\x62\x61\x7c\x2b\x16\x13\xb4" "\x04\xf8\x1a\x5b\x15\x9d\x62\xd5\xac\x4b\x5b\x35\x70\xd0\xe2\x26" "\xf9\xc0\x7c\x73\xad\x9c\xd5\xef\x7b\x9f\x01\x8b\xb6\xb3\x85\xbf" "\x34\xa2\x8c\xce\x8a\xaf\xe1\x5b\xdd\x7f\xa6\x23\x55\x8b\xa4\xa3" "\x06\x2f\xf1\xa0\xd8\x2a\xcc\x9a\x94\x19\x22\xfe\x65\x69\x9b\xcb" "\x6d\x6c\x1c\x38\x25\x82\x9b\xec\xe1\x75\xb4\xbe\xac\x21\x4b\xec" "\xfd\x22\x76\xcb\x35\x4b\xaa\x5c\x3a\x7b\xaa\x6f\x3c\x68\xa7\xa5" "\x3d\xa2\xd5\x25\x9a\xe4\x6f\x80\xc5\xb5\xcf\x76\x37\xd8\xd9\x25" "\xe6\xc7\x26\x40\xdf\x1d\xd3\x41\xb2\x58\x69\xa7\x18\x57\xf8\x35" "\x26\x70\x30\x08\x76\xed\x2b\x37\x2a\x54\x7d\xa5\x7a\x66\x8d\xbf" "\x4a\x20\x3d\x1b\xd1\x28\x1e\x7e\xfe\xd3\xb1\x6c\x64\x87\x70\x27" "\x9e\xcf\x07\xd9\x5a\x9e\xbb\xdb\x3b\xb2\xcb\x50\x78\x3c\x45\x76" "\xec\x59\xa9\xca\xb2\x80\x8c\xc5\x62\x76\x8c\x76\x61\xb5\xf2\xcf" "\x0f\x37\x7d\x44\x7f\xc3\x2c\xef\x7a\x07\x3b\xe2\xb9\x9b\x15\xc6" "\xa6\xb5\xdf\x02\x12\x75\x7d\x8c\x09\x1a\x50\x91\x70\x46\xbb\x18" "\xf7\x44\x05\xc8\xdb\x78\xa2\x87\xd6\x0a\x5f\x14\xf0\xaf\x61\xd7" "\x14\x91\x31\xae\xad\xea\x05\xb3\xd7\xc3\xae\x57\xe5\xbe\x9a\x43" "\xde\x55\xcc\x8e\x91\xac\x5c\xb5\xb9\x0a\x68\x28\x41\xdc\x09\x69" "\x0b\x86\xa1\x46\x67\x96\x04\xf6\x2e\x6e\x07\x11\x62\xb5\x96\x09" "\x2b\x5f\xcb\x7a\x9b\xcb\x77\x1b\x79\xb0\xab\x05\x89\x15\x5a\xcd" "\xab\xd6\x82\x8c\xb0\x65\xc1\x88\x6c\x14\x60\x3d\x77\xf7\xb4\xc1" "\xdf\x43\x0a\x80\x37\xc4\x82\x31\x27\x93\x2d\x93\x06\xfb\x92\xce" "\x19\x3b\xb8\xcf\x4f\x42\xf6\x44\x7a\x5d\xed\xe7\x09\x79\x19\x42" "\xb8\x30\x7e\x4b\x36\xd9\x75\x46\xd8\x7b\xba\x32\x01\x29\x8b\xec" "\xdb\x66\xcf\x4b\x04\xde\x8d\x5e\x1d\xf1\x58\xc1\x3b\xcb\x04\x13" "\x3d\x8a\x9e\xa8\x8f\xce\x0c\xed\x8c\x1e\xf0\x3e\x8c\x59\x14\x53" "\x17\x9d\xb8\x47\x33\xbc\xa3\xe2\xdc\x16\xaf\xd2\x28\xe4\xfe\xa1" "\xaf\x98\x7a\xc9\x4b\x3b\x38\xea\x8e\x1a\x36\x3d\xb4\xb8\x9d\x28" "\xbc\xc6\x9f\xd4\x21\xa9\x52\xbd\x1c\x77\x69\xb8\x41\x0e\x66\x9a" "\x29\x99\x50\x4c\x76\x46\x99\xcc\xbc\x5a\x23\x1c\x19\xbb\x25\x07" "\xf5\xb3\x5c\x38\x9d\xed\xc5\x85\xea\xb4\xd6\x14\xdb\xd1\x54\xb7" "\x13\xec\xcb\x24\xce\x8c\xf9\xb5\xc7\xbe\x54\x17\x29\x19\xa2\xaf" "\xb6\xd3\x14\xae\x83\xa7\x43\xb7\xbe\x28\xba\x2c\x52\xc0\xaa\x37" "\x98\x14\x87\xe9\xbd\x2e\x1c\x93\x29\xd4\xad\x87\x4e\x9a\x7b\x94" "\x30\x72\x68\x31\x2c\xa5\x2b\xed\x52\xc9\x31\x43\xf1\x2c\x77\xcb" "\x73\x64\x07\x3f\x8a\x59\x59\xf3\x8a\x9c\x9e\xb0\xb6\x7b\x8d\x0e" "\x6b\x5a\x33\xcd\x04\x5e\x77\x93\xd4\x23\xb0\xbe\xca\x08\x95\xd6" "\x02\xd2\x22\xbb\x8d\x4c\xbc\x68\x6b\xc7\x6f\x47\x3d\x78\x4e\x56" "\xaf\x86\x11\x9f\x8b\x16\x22\x8b\x93\x89\x10\x58\xaa\x1a\xaf\x97" "\xc7\x33\x97\xcd\x6d\xb2\x17\xa3\x90\xd5\x92\x5e\xb7\xeb\x9f\x13" "\x02\x34\xa3\x2c\xe8\x0c\xc9\xf0\xe6\xda\x06\x70\xe5\x87\xe9\xbf" "\x8e\x68\x34\x5a\xfb\xe5\x39\x6a\xde\xc4\x15\xae\x4c\xe0\x6e\x0b" "\x42\x2f\x2a\x77\xd3\x5b\x69\xa0\x07\xaf\x1c\x55\xa8\x28\x24\x81" "\xc0\x34\xd5\xde\xca\xcf\xa9\x85\x58\x90\xd4\x5b\xf3\x73\xd1\xfb" "\xc4\x25\x64\xb0\x15\xf6\x98\x73\x65\x38\x89\x72\xa6\x5b\x5e\xdb" "\xca\x92\xeb\x39\xb9\x90\x29\x18\x72\xeb\xee\xa0\x90\x1a\x34\x4c" "\x62\x4f\xd9\x2f\x69\x49\x88\x4c\x24\x26\x02\x3b\x74\x12\xf1\x4c" "\x78\x25\xbb\xd3\x26\xc9\x25\xf0\xda\x68\x5a\x50\x7b\x69\x90\x9e" "\xd7\x50\x07\x9d\x4d\xec\x0b\xf8\x88\x78\x2b\xb9\x9e\x9a\x41\x40" "\x7f\xbe\xad\x6f\x4d\x3e\x83\x7f\x6a\x89\x79\x32\x68\x97\x37\x96" "\x90\x41\xde\x3a\x69\x49\xf3\x7e\x0a\xb6\x4a\x0f\x3c\x41\x69\x8a" "\xcb\xad\xb7\xe7\xf4\x59\x95\xa5\xf4\x8d\xac\xeb\xdf\x07\xf3\x1e" "\x81\x52\x66\x19\xb4\x07\xe6\x63\x0e\xda\x2d\x0e\xf6\x72\x94\x84" "\x53\x70\x22\x0e\x46\xa6\xe5\x4e\x9d\x34\x38\xa1\x6d\x2b\xdf\xa9" "\x67\x33\x81\xcf\xa5\x92\xff\x94\x2b\x19\x1f\x55\x05\xd8\xbc\x2d" "\xab\x7b\x15\xa2\x4c\xe7\xcb\xdb\x96\xfc\xb2\x51\x34\xb4\x84\xba" "\x1d\x68\x7a\xff\x64\x71\xa8\x46\x12\x97\xe6\xf5\x14\x4e\xf5\xcb" "\x72\xce\xaf\x3e\xf7\x60\x27\x42\xa0\x92\xdf\x90\x86\x40\x55\x94" "\x95\x11\xf4\xe4\xbf\xbc\x6e\xa6\x7f\x3f\x01\x8c\xa6\x01\xa2\x4e" "\x4e\x4d\xaf\x62\x3b\x55\x8d\x91\x34\x35\x43\x23\x51\x3b\xf6\x3e" "\xbd\x79\x04\x25\x20\xc1\x13\x23\xe2\x46\x78\xde\xd5\x0d\xb6\x89" "\x2c\x43\x71\x9a\x89\x8a\x3c\x70\xee\x20\x6b\x8b\x9c\x31\x48\x3a" "\x41\x9a\xde\xf0\x18\x46\xee\x47\x09\xcb\xad\x2a\x6b\x95\x2d\x72" "\xd7\x01\xf8\x68\xfe\x75\x37\x15\x6a\x15\x65\x8e\x95\x88\x66\x08" "\xea\x31\x6d\xee\x8f\xc9\xac\x01\x06\x89\x3a\x82\x35\x79\x0a\x40" "\x37\x51\x1a\x53\xd9\x85\xd6\x99\x12\xbf\xb6\xe0\x72\x3c\xc2\xfe" "\x07\x1e\x92\xce\x18\x9f\xfb\xa0\xf6\xd3\x42\xbb\x41\xce\x31\x61" "\x2f\xe1\x8d\x55\x80\x03\x16\xb0\xd9\x2d\xd3\x64\xca\x62\x49\x5f" "\x3e\x28\xe6\x54\xd5\xb9\xdf\x7f\x5a\xcb\xa2\x87\xbc\x34\xbe\x06" "\x0a\x4c\x77\x34\xa6\xae\xbd\xad\x22\x62\xf2\x56\x28\x99\x21\x4b" "\x58\x68\x1f\xa5\xb6\x89\x5e\xa4\x76\x58\x60\x8a\x61\x17\x63\x77" "\xbd\xef\x1c\x3e\xfd\xc2\x26\x29\x69\xd9\xa0\x6e\xef\x81\x6d\xec" "\xa0\x14\xac\x42\x47\x77\xd5\x1e\xa5\xc7\x40\xa3\x7e\xac\x80\xf7" "\x1f\x25\xa7\x04\x58\xbe\x65\x32\xe2\xb0\x47\x9d\x71\xa1\x5c\x60" "\x25\xa6\x9c\xb4\x9d\x6f\xf3\xfc\x66\x51\x50\xaa\x98\x1b\x16\x57" "\x66\xb8\xcc\x81\x30\x7c\x25\xd9\x6e\xef\x86\x3e\x05\xf5\x58\x51" "\xd5\x5f\xec\x3b\x78\x5e\xe1\x20\x1b\x44\x8d\xee\x3d\x01\xd2\xbe" "\x72\x54\x46\x71\xd7\x38\x65\xa4\xf8\x75\xa5\x30\xca\x74\x20\xb8" "\xbe\xcf\x6f\x59\xa6\x52\x7b\x23\x4b\xf5\x90\x50\x12\x85\xf1\xd6" "\xa2\x75\xf4\xd9\xd6\x52\xb1\xcd\x0b\x1f\x79\xfa\x0a\xda\xa0\x70" "\xa1\x02\x78\xcb\xc4\x68\x16\x3f\xc4\x87\x6a\x0e\xb6\xba\x09\x26" "\x3d\xc0\x0f\x38\xbd\x38\x4f\x04\x92\xdb\xe5\x2d\xf6\x07\x74\xcf" "\x66\x9b\x02\x2f\x49\x71\xf8\x3c\xd2\x9c\x31\x5d\x3b\xd0\x17\x8d" "\x90\xf3\x58\x4c\x5e\x41\xb7\x6e\x8c\xe4\x73\xd3\xd5\x76\x1b\x94" "\xb0\x08\x11\xf7\x9e\x08\x4f\x3a\xd7\xdb\x69\x47\x77\xbb\xae\xc2" "\x85\xf9\xfb\x0c\x1e\xfa\xaa\xb9\xe7\xb4\x1c\x1d\xf0\x4d\xd3\x95" "\x57\x12\xea\xc4\x21\xb2\xa6\x45\x26\x4d\x1c\x91\xf0\x69\xda\xa1" "\x09\x05\xd7\x6c\xe4\x3a\x08\xc8\x2d\xf0\x8b\xc8\x21\x99\xad\xf4" "\xb9\x9c\x2a\x86\x88\xf1\x40\x31\xe0\xb4\xe8\xdd\xaf\x59\x0b\x38" "\x9a\x57\xfb\xa0\x9c\xdc\x1d\xca\xab\x51\xb3\x20\xaa\x71\xca\x01" "\x4a\x85\x3f\x5c\x0c\x3f\x22\x73\x0d\x0f\xbf\x3e\x0f\x05\x26\xb0" "\xd0\x48\xb4\xe2\x5b\x83\xbd\x90\x30\x9e\xf3\xbd\xd6\x78\xc4\x7d" "\x8a\xe8\x88\x72\x14\x30\x11\x51\xf3\x8d\x44\x8c\x17\xc2\x22\x04" "\xcc\xea\x02\x38\x23\x43\x3a\x77\x1d\xcd\x95\xc2\xa2\xc2\xbc\xef" "\x26\xec\x54\xab\xe3\x80\x7e\x77\x3b\xdf\x6a\xb9\x7e\xbf\x40\x93" "\x87\x6d\x0e\x66\xb9\xce\x95\x1c\xb5\x2b\x86\x16\x90\x67\x1a\x87" "\xe7\x96\x59\xb4\x96\x44\xf9\x31\x0c\x0c\xab\x1f\xfc\xac\x29\xee" "\xbd\x51\x64\xb4\x21\x51\xf9\x4a\x74\x08\xaa\xbb\x49\xad\xf8\xc6" "\x9f\x41\xe5\x30\xf9\xd1\x5b\x32\x4b\x0a\xb9\xba\x3a\xac\x90\xa1" "\x12\xd7\x36\x8b\xba\x86\xe2\xe7\x5c\x3d\x27\xce\x8f\x83\x0a\x59" "\x28\x6f\xe3\x71\x93\x4d\x89\xc1\x39\x3a\x0f\xdf\x68\x03\xe8\xf2" "\x95\xa9\x71\x0f\x6d\xd5\x1d\xba\x50\x3c\x6a\xfe\xcf\xdd\xc4\x98" "\xf3\xf2\xe8\x8a\xd6\xca\xfc\xb1\x42\x21\x37\x52\x97\xfb\x8d\x0a" "\xe7\x72\x65\xc3\x4a\xf8\x4c\xb8\x04\xdd\x2e\x8e\xcd\xb3\x68\xe1" "\xbf\x9c\xd3\xef\x0c\xe0\xda\xff\x9c\x6f\xab\xcc\x97\x53\xfa\xdd" "\xd5\x47\xf1\xaa\x89\x9e\xa2\x1a\x5e\xb4\x18\xb3\x3f\xf8\xb8\x49" "\x61\x81\xac\xd0\x5a\x7b\x5c\x77\x96\x4e\xd9\x70\x54\x69\x78\xd4" "\x4e\xc1\xba\xe5\x0a\xc9\xec\x44\xd6\x00\x66\xe7\xd8\x31\x51\x7f" "\x18\xef\xee\x6a\x6c\xb9\x27\x34\xe9\x91\x28\x54\xd4\x39\xf0\x82" "\x6d\xa7\x26\x85\x34\x3b\x59\x7a\x2a\x94\xfb\x34\x0d\x84\xae\xc2" "\x18\x79\x2d\x4a\xb0\xf9\x62\xdf\x3e\x5e\x71\x13\x6e\x22\xb9\xdb" "\x15\xce\xf1\xad\x69\x48\xb3\x61\x27\x83\x7d\xdc\x5b\xdb\x20\x66" "\x39\x24\x21\xac\xd6\xac\xca\xfb\x6e\x05\xd6\x1e\x32\xa7\xbf\x81" "\x3f\xb3\x18\x8a\x31\xbb\x1e\x67\x21\x93\x4b\xb1\x14\x54\xfd\xfe" "\x4e\xaa\x8c\xdc\x12\x02\x72\x14\x8e\x01\xf7\xe8\xbc\x1b\x6c\x6a" "\x1b\xe6\xb2\xbd\x69\x5e\x75\x54\xa7\xf0\x3a\x84\x2e\x5a\x65\x4e" "\x70\x81\x31\xdd\xde\x36\xaa\x2d\xdd\xed\x8e\x3a\x54\x80\x5a\xac" "\xce\x1c\x48\xb9\xc3\x44\x1a\x94\xe0\xb3\x34\x19\xba\x08\x74\x8a" "\xf5\x0e\x74\x35\x78\x83\x15\xe2\x41\xba\x4a\x21\xb9\xd9\x03\x01" "\x58\x03\x2b\xa6\xc3\x26\xcf\x8e\x8c\x27\x4f\x2d\x59\x0c\xca\xf3" "\xa6\xe9\xa1\xaf\x34\x43\x35\x1f\x55\x36\x3a\x6a\x5e\xe5\x41\xf8" "\xd5\x18\xe8\x31\x31\xc4\x4e\x66\xe4\x10\x43\x81\x43\xb2\xe7\xab" "\xe6\xe6\x3f\x8f\xb3\xd9\xd9\x79\xf6\xc8\xfb\x8f\x6e\xee\xba\x3e" "\x43\x5d\x8e\xca\xcb\x05\x34\x43\x2c\xb3\x6b\xc9\xbd\x27\xfe\xcf" "\xe6\x38\x86\xdc\x98\xb0\x0f\x13\x92\xf2\x91\x57\x51\xb2\xd2\x5b" "\x84\xef\x5c\xd2\xa4\x75\x82\x54\x24\x74\x5a\x4a\xee\x82\x2d\xaa" "\x1e\x97\x2e\xae\x77\x75\x6c\x39\x2f\x13\x71\xab\x8e\x19\xbc\x49" "\x1a\x14\x1a\xc9\x26\xcd\xc3\x0d\x31\xf2\x7e\x1c\x85\x38\x24\x04" "\x60\x54\x2b\xfe\xec\x8b\xbc\xc0\x71\xe6\xc2\x8d\xe1\x82\x8b\xf0" "\xae\xed\x06\x7c\x2f\x93\x3d\xfb\x9a\x61\xc3\xac\x96\xf7\x24\x4a" "\x69\xc8\x26\x2c\xba\x42\x0c\x11\xf5\x65\x20\x62\x73\x37\x59\xca" "\xe9\x50\xe2\xb0\x20\x4c\x79\x90\xe2\x24\xc3\x99\xaa\x79\x0b\x92" "\x57\x6f\x91\x96\x3d\xe8\xd5\xb1\x34\x12\xaa\xb9\x43\x6f\xed\xec" "\xbc\x7f\xe7\xeb\xab\x73\x52\x5f\x59\x63\x04\x1f\xa2\x6e\x08\x41" "\x43\x28\xd1\xdf\xfe\xbc\x76\x27\xa1\x8c\xd3\x30\xc5\xe3\xf7\x31" "\xdc\x59\xc2\x95\x86\x71\xcd\x89\xeb\xeb\x76\x93\xcf\xb1\xa0\xa3" "\x42\x3e\x34\x24\x77\x1e\x58\x1a\x99\x46\xe1\x8a\xd9\xe9\xad\xdc" "\xcb\xdc\x75\x5c\x36\x17\x2a\x92\x5d\x7d\x05\xc9\xee\x68\x3e\x69" "\x67\xb8\x89\x7b\x7e\xba\x85\x88\xa0\xf3\xef\xab\x84\x2b\xa5\x7c" "\x54\x57\xf6\xac\x65\xd1\x93\x29\xb5\x61\xc7\xcb\x6c\x33\x86\xae" "\x31\x2b\xe8\x65\x95\xc8\xb6\x76\x64\x63\x05\x02\xc5\x4b\x32\xe6" "\x41\x4c\xfc\xd0\xd4\xe4\x69\x14\xf0\xc0\x80\x5f\x0b\xb9\x94\x92" "\xf7\x58\xdf\x68\xb2\x7f\x74\x1e\xc4\xd0\x41\xf1\x9d\xe9\x60\x02" "\xf1\x0f\x41\xb8\x4c\x1a\x8f\xcb\xed\x47\xc6\xb1\xa4\x46\x63\x1e" "\xcb\xc7\xe5\x75\x44\x82\x44\x5a\x5b\x0a\x62\xd3\x85\xfd\x0d\x72" "\xc6\x1b\x3a\x35\xc8\xd9\xd0\x92\xc1\xd7\xcd\x9a\xbf\x33\x01\xa3" "\xe0\x9c\x58\x73\x36\x56\xc8\x26\x8d\xc3\xb6\x98\xe5\x87\x79\x91" "\xf2\x8f\x4d\x5a\x68\x13\xbd\x37\xa6\xf1\x9a\x2e\xe6\x22\xfa\x71" "\x43\x17\x9a\x93\xa9\x82\x2c\xb8\xee\x54\x38\x31\xbc\x64\x54\x20" "\x61\x48\x1c\xfa\xde\xf0\x49\xfd\x34\xb1\xee\x06\x94\x63\xd5\x27" "\x10\xde\x2b\xbe\x97\x76\x6f\xc1\x65\x2f\x81\x36\xc6\x62\xef\x48" "\xf4\x5b\xb2\x02\x9b\x1c\x24\x98\xbb\xed\x3e\xe8\x85\xc3\xe2\x45" "\xdb\x69\x35\xd5\x97\xf9\x86\x5c\x8a\xe2\xd4\x33\xaf\x3b\x1c\xbc" "\x8a\xf5\xfb\x9d\x83\xec\x73\x00\x0a\xd3\xca\x10\xe5\x3e\x38\x1e" "\x5e\xfd\xb9\x54\x92\xe0\x44\x08\x7f\xeb\xb7\x59\x49\x48\x15\x0d" "\x85\xb0\x72\x4d\xc0\x99\x4e\x66\x3b\xd5\x0d\xaa\xb4\xf8\xb6\x9a" "\x8b\xc9\x8d\x6e\x2f\x7a\xb4\xd5\xe3\x00\x82\x80\xa5\x70\x34\xdf" "\xb1\x5c\xd1\xab\x8b\x64\x56\x43\x9e\xb4\x91\x5f\x0e\x90\x3f\xd8" "\xd0\xe3\xfc\x31\x13\x0a\x04\xbe\x4b\x2a\x2a\xdf\x44\x4c\xb2\x69" "\xab\xe0\x8a\x11\x2c\x01\xe6\x59\x2f\x07\x51\x84\xa4\x85\x94\x46" "\xe9\x30\x9f\xf5\x91\x25\x93\x85\x93\xe9\xd6\x35\x9f\x5f\x85\xa6" "\x7b\x59\x92\xb1\x7a\x79\xc6\x71\x0d\xc7\xd3\x20\xfa\x84\xcc\xf4" "\xab\x4c\xf7\xd2\xe6\xd7\xec\x62\x85\x52\x2f\x1f\x4c\x92\x8e\x85" "\x93\x3c\x6f\xfd\xe8\xb9\xaa\xec\x9b\xe7\x0d\xa4\x1b\x13\x31\x97" "\x29\x20\x3d\xc5\xd0\xd4\x4d\xec\x4a\x18\x9c\x28\x48\xa3\x6c\x14" "\x86\x5d\xe0\xc1\x60\x6d\x90\x5d\xaa\x6c\x70\xbd\x6a\xe0\x68\xb5" "\x74\x8c\x46\x09\x86\x9a\xb1\xba\xe4\xf6\x3f\xd0\x88\x1f\x54\x83" "\x14\x17\x5b\x5a\x52\xd5\x72\x09\x22\x28\xdb\x18\x2d\xeb\xac\x59" "\x10\x1b\x88\x6d\x45\xa7\x2e\x19\xfd\xdc\x4f\xb1\x1f\xde\x8d\xcc" "\x95\xbe\x19\x56\x22\x10\x89\x68\x80\x4e\x7c\x7e\xac\xba\xce\x73" "\x2b\x1b\x8c\x38\x85\x59\x9d\xa7\x12\xb5\x8c\x0e\x7f\xd3\x2b\xf5" "\x9d\x46\xe8\x65\xc8\xe5\x40\x9e\x6b\x84\x0b\x5a\xc7\x52\x89\x59" "\x35\x57\x8f\x71\x0a\x37\xc0\xf0\xf3\x0f\x06\xd2\x8e\xab\x2a\x92" "\xf3\x4e\x5e\x14\xe0\xfd\x04\xa0\xc1\x5a\x93\x52\x31\x45\x14\x77" "\x1d\xe6\x81\x49\xca\xe3\x7f\xf0\x89\x80\x3e\x6a\x49\xbc\x6c\x0b" "\xb5\x46\x3f\x32\x48\x3e\x9c\x61\x3b\x50\xf4\x18\x48\x83\xb5\x19" "\x22\x35\x5b\x08\xcb\xb2\x89\x87\x4d\x1f\xb3\xd6\xaf\x4a\x02\xe8" "\x9e\xe0\xdc\x04\xc7\x25\x4e\x49\xe6\x5a\xb5\x43\x68\x26\x0d\xb6" "\xd2\x64\xbe\x27\x79\x30\xf0\x2b\xd5\x13\xca\x99\x6b\x2d\x6a\x0e" "\x40\xa7\x1d\xcc\xb7\x4f\xec\xdc\x23\x06\xb1\x3a\xd8\xe1\x24\x86" "\xde\x73\xa4\x22\x7c\x5d\xd8\x6f\xbd\xdc\xd9\xab\x8d\x7b\x16\x22" "\xa7\x6b\xd8\x8a\xdf\x5f\xa0\x3b\x34\x11\xc9\x40\x6f\xab\xc2\x37" "\xdc\x6b\xd2\x25\x44\xa5\xc7\xec\x67\x0c\x3f\xf6\xba\x77\x53\x2e" "\xd0\xae\xc2\x0e\xe2\x56\x2d\x72\x92\xb2\x91\xfe\x04\x89\xc3\x34" "\x20\x6d\x8a\x92\xb1\x1a\xfc\xff\xcd\xd9\xc0\xc1\xa0\xa7\x7d\x9e" "\xe8\x5e\x76\xf1\x81\x03\xdf\xd4\x0b\x98\x0a\x36\xd4\x1a\x50\xd0" "\xe3\x2f\x51\xc2\xd8\x4e\xc9\x77\xbc\xb8\x7f\x38\xe3\x00\xdb\x2f" "\xbc\x48\x16\x6a\x28\xcf\x56\xd2\x58\x01\xbb\x21\x72\x55\xfa\x3c" "\xd3\xc9\x04\x80\xdc\x38\xa6\xa5\xcd\xed\xba\xd1\xbc\xb7\x9a\x7e" "\xb4\xe8\x59\x2a\x8d\x2e\xcf\x7c\xdd\x31\xf7\x8b\x96\x71\xf0\x06" "\xfb\x29\x23\xf6\x0d\x66\x59\x8e\x82\x95\x8d\x42\x8e\x4e\x01\x9e" "\x6d\x19\x83\x04\x36\x3d\xe3\x8a\xc4\x54\x90\x23\xa9\x81\xda\xcb" "\x08\x6f\x9a\xd2\x13\x8d\x46\x1c\x4d\xf3\xa9\x3e\x60\x5d\x90\x3b" "\xca\x95\x82\x1b\xa2\x1a\x19\xc5\x5c\x5a\xc9\x67\xcf\x65\xe4\x8d" "\xb2\x2b\x4e\x0c\x7f\x7b\xfa\x32\x49\x69\xda\x5a\xb4\x9c\x06\xbf" "\x12\xa4\x0f\x4a\x8c\xd0\x73\x8e\xdf\x66\x72\xd9\x29\xab\x06\x3a" "\xf1\x3c\xd8\x30\xd6\xbb\x0e\x37\x07\x4e\xe5\xf6\x87\x8a\x4a\xd0" "\x66\x68\x84\xd1\x23\x62\xb6\x07\x77\x0e\x60\x7d\x30\x22\xc2\xff" "\x53\x46\x60\x69\xb0\x73\xe5\x33\x25\x0b\x47\x68\xa0\xf4\x52\x3d" "\x91\x6e\x1c\x4d\x9e\x0a\x16\xd5\xb3\x3b\x2d\x3a\x7a\x87\x6c\xfe" "\x7b\xc8\x81\xa8\xe6\xce\xb9\xb3\xc5\xc2\xd1\xde\x90\x92\x0f\x57" "\x71\x90\x6a\x73\x4b\x5b\x07\x97\xe6\xda\x7d\xdb\xd5\xd1\x3e\xa6" "\xbf\x26\x23\x46\xc6\xcf\xef\x2a\xed\xa7\xc0\x52\xda\x40\x2e\xd6" "\x2e\xc4\xf1\xb2\x2f\x69\xac\x73\xe4\x2d\x75\xea\x19\x4c\xb5\x50" "\xbc\x03\x51\x9c\x05\xda\x8a\x3b\xc9\x98\xd2\x43\x40\xc6\xd9\x0f" "\x53\x2e\x24\x56\x55\x4e\x41\xc9\xcd\xa9\x06\xe8\xbc\x69\x10\xaa" "\x99\x3d\x56\x9e\xd2\xbc\x48\xcd\x58\x2d\xe3\x16\x6a\x23\x3d\x85" "\xc5\x14\x80\x46\x07\x96\xcf\xd9\xdc\xff\x14\x39\xfd\x5c\xc2\x2d" "\xb9\xf9\x51\x09\x5d\xd3\xe4\xf6\x3f\x51\x62\x10\xf6\xd4\x76\x78" "\x11\xf0\xd5\x63\xb8\x53\x2b\xb2\xa0\x58\x4e\x71\x90\xea\xb6\xc6" "\x92\x59\x06\x8d\x53\x63\x0a\x0c\xd4\x62\x2d\x57\x12\xf9\xf8\xd8" "\xdb\x10\x40\x2e\x09\x83\x1b\xbb\x8c\xdd\xbc\x0c\xa0\xc8\x14\x23" "\xa5\x93\xed\xd9\x2d\x0b\xc0\xfd\x0e\x1d\xd1\xbb\x95\x96\xb6\xbc" "\x81\x31\x6f\x20\x6f\x72\x1c\x4a\x87\xfb\x66\x2d\x79\x3c\xa4\x6d" "\x05\xc1\x71\x50\x83\xad\xea\x03\x26\x2b\xe4\x10\xc8\x33\x0b\x61" "\xdf\x30\x4b\x27\x8f\xfe\xbd\xcc\x8d\xda\x4f\xaf\x8f\xad\xaa\x25" "\xa1\x50\x95\x95\x7d\x8e\x35\xec\xe8\x7e\xd4\x98\x68\xe4\x95\xac" "\xa6\x98\x95\x38\xf8\xd2\xab\xdc\xb9\x77\xfc\xa9\xbf\xb5\x18\xed" "\xca\x15\xb2\xe7\xd0\x23\xcb\xc4\x73\xc0\x85\x0b\x57\xeb\xf4\xe6" "\x11\x97\xb1\x03\xa6\x66\x0a\x24\x3b\xb6\xe8\x2f\xfe\x9c\x78\x0a" "\x42\x01\xe9\x35\x58\xf7\x55\x13\x80\x24\x23\x30\x62\x6c\x7b\x86" "\xff\x7e\x12\x34\xf3\x33\x4c\x1c\xed\x5a\x96\xd6\xcd\x04\xfb\xf9" "\x7c\xde\xc0\xd5\x70\x52\x4e\x0f\xa2\x8e\x6b\xa6\x8f\x3a\x08\xf9" "\x08\x0f\x2f\xd7\xa2\xb1\x91\x53\x65\x63\x63\xb8\x31\xba\xf4\x21" "\xb5\x17\xd7\x59\x94\xd0\x0e\x8c\x91\x5c\x37\xf8\x3a\xd8\x8c\x7f" "\x76\xd0\x63\x7a\xd9\xb4\xa6\x3d\xf8\xfb\x72\xd5\x65\xf0\x10\x4a" "\x42\x15\x70\xb1\x9b\x5f\xf8\xf9\x9f\x5b\x29\x0a\x28\x2a\x68\x6b" "\xaf\xec\x84\x94\xbc\x22\xdf\xe8\x3e\xcb\xee\xc3\xc8\x03\x00\xf3" "\x02\xff\x07\x4d\x95\x62\x12\x9e\x51\x1a\x20\x4a\x5a\xa2\x66\x81" "\x3d\x29\x98\x23\x17\x11\x95\x84\x51\x9f\x40\x7a\x3d\x6f\x61\xbe" "\x2b\x1b\x03\x82\xad\xb6\x8f\x69\x3d\x31\x39\xc7\x8b\x0a\x77\x6e" "\x02\x88\xdd\x13\x6a\x9c\x72\x46\x5d\xf0\x92\xb4\x76\xac\xc0\xbd" "\x8d\x2e\x3c\xcb\xa3\x89\x31\x07\x36\x68\x35\x03\x4c\x95\x6d" "\xbd", 4096); r[18] = syscall(SYS_writev, r[2], 0x20013ffeul, 0x5ul, 0, 0, 0); return 0; }
On commit 34229b277480f46c1e9a19f027f30b074512e68b.
On Wed, 03 Feb 2016 09:57:50 +0100, Dmitry Vyukov wrote:
Hello,
The following program triggers an out-of-bounds write in snd_rawmidi_kernel_write1 (run in parallel loop). It seems to try to copy -1 bytes (aka 4GB) from user space into kernel smashing all on its way.
What card is /dev/midi3? Please check /proc/asound/cards. Is it MTPAV?
Takashi
On Wed, 03 Feb 2016 10:35:14 +0100, Takashi Iwai wrote:
On Wed, 03 Feb 2016 09:57:50 +0100, Dmitry Vyukov wrote:
Hello,
The following program triggers an out-of-bounds write in snd_rawmidi_kernel_write1 (run in parallel loop). It seems to try to copy -1 bytes (aka 4GB) from user space into kernel smashing all on its way.
What card is /dev/midi3? Please check /proc/asound/cards. Is it MTPAV?
In anyway the patch below should paper over it. But it's still strange that it gets a negative value there. Could you put
WARN_ON(count1 < 0)
before the newly added check?
I tried it locally with virmidi but it didn't appear, so far. Maybe my setup is too slow and has fewer CPUs than yours.
thanks,
Takashi
--- diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 26ca02248885..2fef77d9de50 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1239,6 +1239,8 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, } while (count > 0 && runtime->avail > 0) { count1 = runtime->buffer_size - runtime->appl_ptr; + if (count1 <= 0) + break; if (count1 > count) count1 = count; if (count1 > (long)runtime->avail)
On Wed, 03 Feb 2016 10:41:14 +0100, Takashi Iwai wrote:
On Wed, 03 Feb 2016 10:35:14 +0100, Takashi Iwai wrote:
On Wed, 03 Feb 2016 09:57:50 +0100, Dmitry Vyukov wrote:
Hello,
The following program triggers an out-of-bounds write in snd_rawmidi_kernel_write1 (run in parallel loop). It seems to try to copy -1 bytes (aka 4GB) from user space into kernel smashing all on its way.
What card is /dev/midi3? Please check /proc/asound/cards. Is it MTPAV?
In anyway the patch below should paper over it. But it's still strange that it gets a negative value there. Could you put
WARN_ON(count1 < 0)
before the newly added check?
I tried it locally with virmidi but it didn't appear, so far. Maybe my setup is too slow and has fewer CPUs than yours.
Scratch my previous patch, I could reproduce the issue on a faster machine in my office now :) Will work on it.
Takashi
On Wed, 03 Feb 2016 12:39:31 +0100, Takashi Iwai wrote:
On Wed, 03 Feb 2016 10:41:14 +0100, Takashi Iwai wrote:
On Wed, 03 Feb 2016 10:35:14 +0100, Takashi Iwai wrote:
On Wed, 03 Feb 2016 09:57:50 +0100, Dmitry Vyukov wrote:
Hello,
The following program triggers an out-of-bounds write in snd_rawmidi_kernel_write1 (run in parallel loop). It seems to try to copy -1 bytes (aka 4GB) from user space into kernel smashing all on its way.
What card is /dev/midi3? Please check /proc/asound/cards. Is it MTPAV?
In anyway the patch below should paper over it. But it's still strange that it gets a negative value there. Could you put
WARN_ON(count1 < 0)
before the newly added check?
I tried it locally with virmidi but it didn't appear, so far. Maybe my setup is too slow and has fewer CPUs than yours.
Scratch my previous patch, I could reproduce the issue on a faster machine in my office now :) Will work on it.
This turned out to be a race in updates of runtime->appl_ptr & co. We do temporary spin unlock and relock while copying the user-space data, and then update these values. Meanwhile these values are referred as the position to copy, and the concurrent accesses may lead to the negative value.
Below is a quick fix for that, just updating these before the temporary unlock.
The patch also fixes the read size where it has more race problems...
It seems working on my machine. Let me know if this works for you, too. Then I'll cook up the official patch.
thanks,
Takashi
--- diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 26ca02248885..795437b10082 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -942,31 +942,36 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, unsigned long flags; long result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long appl_ptr;
+ spin_lock_irqsave(&runtime->lock, flags); while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; if (count1 > count) count1 = count; - spin_lock_irqsave(&runtime->lock, flags); if (count1 > (int)runtime->avail) count1 = runtime->avail; + + /* update runtime->appl_ptr before unlocking for userbuf */ + appl_ptr = runtime->appl_ptr; + runtime->appl_ptr += count1; + runtime->appl_ptr %= runtime->buffer_size; + runtime->avail -= count1; + if (kernelbuf) - memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1); + memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1); if (userbuf) { spin_unlock_irqrestore(&runtime->lock, flags); if (copy_to_user(userbuf + result, - runtime->buffer + runtime->appl_ptr, count1)) { + runtime->buffer + appl_ptr, count1)) { return result > 0 ? result : -EFAULT; } spin_lock_irqsave(&runtime->lock, flags); } - runtime->appl_ptr += count1; - runtime->appl_ptr %= runtime->buffer_size; - runtime->avail -= count1; - spin_unlock_irqrestore(&runtime->lock, flags); result += count1; count -= count1; } + spin_unlock_irqrestore(&runtime->lock, flags); return result; }
@@ -1223,6 +1228,7 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, unsigned long flags; long count1, result; struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long appl_ptr;
if (!kernelbuf && !userbuf) return -EINVAL; @@ -1243,12 +1249,19 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, count1 = count; if (count1 > (long)runtime->avail) count1 = runtime->avail; + + /* update runtime->appl_ptr before unlocking for userbuf */ + appl_ptr = runtime->appl_ptr; + runtime->appl_ptr += count1; + runtime->appl_ptr %= runtime->buffer_size; + runtime->avail -= count1; + if (kernelbuf) - memcpy(runtime->buffer + runtime->appl_ptr, + memcpy(runtime->buffer + appl_ptr, kernelbuf + result, count1); else if (userbuf) { spin_unlock_irqrestore(&runtime->lock, flags); - if (copy_from_user(runtime->buffer + runtime->appl_ptr, + if (copy_from_user(runtime->buffer + appl_ptr, userbuf + result, count1)) { spin_lock_irqsave(&runtime->lock, flags); result = result > 0 ? result : -EFAULT; @@ -1256,9 +1269,6 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, } spin_lock_irqsave(&runtime->lock, flags); } - runtime->appl_ptr += count1; - runtime->appl_ptr %= runtime->buffer_size; - runtime->avail -= count1; result += count1; count -= count1; }
On Wed, Feb 3, 2016 at 1:02 PM, Takashi Iwai tiwai@suse.de wrote:
On Wed, 03 Feb 2016 12:39:31 +0100, Takashi Iwai wrote:
On Wed, 03 Feb 2016 10:41:14 +0100, Takashi Iwai wrote:
On Wed, 03 Feb 2016 10:35:14 +0100, Takashi Iwai wrote:
On Wed, 03 Feb 2016 09:57:50 +0100, Dmitry Vyukov wrote:
Hello,
The following program triggers an out-of-bounds write in snd_rawmidi_kernel_write1 (run in parallel loop). It seems to try to copy -1 bytes (aka 4GB) from user space into kernel smashing all on its way.
What card is /dev/midi3? Please check /proc/asound/cards. Is it MTPAV?
In anyway the patch below should paper over it. But it's still strange that it gets a negative value there. Could you put
WARN_ON(count1 < 0)
before the newly added check?
I tried it locally with virmidi but it didn't appear, so far. Maybe my setup is too slow and has fewer CPUs than yours.
Scratch my previous patch, I could reproduce the issue on a faster machine in my office now :) Will work on it.
This turned out to be a race in updates of runtime->appl_ptr & co. We do temporary spin unlock and relock while copying the user-space data, and then update these values. Meanwhile these values are referred as the position to copy, and the concurrent accesses may lead to the negative value.
Below is a quick fix for that, just updating these before the temporary unlock.
The patch also fixes the read size where it has more race problems...
It seems working on my machine. Let me know if this works for you, too. Then I'll cook up the official patch.
Yes, it fixes the crash for me. Thanks!
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 26ca02248885..795437b10082 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -942,31 +942,36 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, unsigned long flags; long result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime;
unsigned long appl_ptr;
spin_lock_irqsave(&runtime->lock, flags); while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; if (count1 > count) count1 = count;
spin_lock_irqsave(&runtime->lock, flags); if (count1 > (int)runtime->avail) count1 = runtime->avail;
/* update runtime->appl_ptr before unlocking for userbuf */
appl_ptr = runtime->appl_ptr;
runtime->appl_ptr += count1;
runtime->appl_ptr %= runtime->buffer_size;
runtime->avail -= count1;
if (kernelbuf)
memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1);
memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1); if (userbuf) { spin_unlock_irqrestore(&runtime->lock, flags); if (copy_to_user(userbuf + result,
runtime->buffer + runtime->appl_ptr, count1)) {
runtime->buffer + appl_ptr, count1)) { return result > 0 ? result : -EFAULT; } spin_lock_irqsave(&runtime->lock, flags); }
runtime->appl_ptr += count1;
runtime->appl_ptr %= runtime->buffer_size;
runtime->avail -= count1;
spin_unlock_irqrestore(&runtime->lock, flags); result += count1; count -= count1; }
spin_unlock_irqrestore(&runtime->lock, flags); return result;
}
@@ -1223,6 +1228,7 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, unsigned long flags; long count1, result; struct snd_rawmidi_runtime *runtime = substream->runtime;
unsigned long appl_ptr; if (!kernelbuf && !userbuf) return -EINVAL;
@@ -1243,12 +1249,19 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, count1 = count; if (count1 > (long)runtime->avail) count1 = runtime->avail;
/* update runtime->appl_ptr before unlocking for userbuf */
appl_ptr = runtime->appl_ptr;
runtime->appl_ptr += count1;
runtime->appl_ptr %= runtime->buffer_size;
runtime->avail -= count1;
if (kernelbuf)
memcpy(runtime->buffer + runtime->appl_ptr,
memcpy(runtime->buffer + appl_ptr, kernelbuf + result, count1); else if (userbuf) { spin_unlock_irqrestore(&runtime->lock, flags);
if (copy_from_user(runtime->buffer + runtime->appl_ptr,
if (copy_from_user(runtime->buffer + appl_ptr, userbuf + result, count1)) { spin_lock_irqsave(&runtime->lock, flags); result = result > 0 ? result : -EFAULT;
@@ -1256,9 +1269,6 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, } spin_lock_irqsave(&runtime->lock, flags); }
runtime->appl_ptr += count1;
runtime->appl_ptr %= runtime->buffer_size;
runtime->avail -= count1; result += count1; count -= count1; }
On Wed, 03 Feb 2016 14:37:17 +0100, Dmitry Vyukov wrote:
On Wed, Feb 3, 2016 at 1:02 PM, Takashi Iwai tiwai@suse.de wrote:
On Wed, 03 Feb 2016 12:39:31 +0100, Takashi Iwai wrote:
On Wed, 03 Feb 2016 10:41:14 +0100, Takashi Iwai wrote:
On Wed, 03 Feb 2016 10:35:14 +0100, Takashi Iwai wrote:
On Wed, 03 Feb 2016 09:57:50 +0100, Dmitry Vyukov wrote:
Hello,
The following program triggers an out-of-bounds write in snd_rawmidi_kernel_write1 (run in parallel loop). It seems to try to copy -1 bytes (aka 4GB) from user space into kernel smashing all on its way.
What card is /dev/midi3? Please check /proc/asound/cards. Is it MTPAV?
In anyway the patch below should paper over it. But it's still strange that it gets a negative value there. Could you put
WARN_ON(count1 < 0)
before the newly added check?
I tried it locally with virmidi but it didn't appear, so far. Maybe my setup is too slow and has fewer CPUs than yours.
Scratch my previous patch, I could reproduce the issue on a faster machine in my office now :) Will work on it.
This turned out to be a race in updates of runtime->appl_ptr & co. We do temporary spin unlock and relock while copying the user-space data, and then update these values. Meanwhile these values are referred as the position to copy, and the concurrent accesses may lead to the negative value.
Below is a quick fix for that, just updating these before the temporary unlock.
The patch also fixes the read size where it has more race problems...
It seems working on my machine. Let me know if this works for you, too. Then I'll cook up the official patch.
Yes, it fixes the crash for me. Thanks!
Great, I'll queue the fix. FWIW, below is the final form I'm going to push.
thanks,
Takashi
-- 8< -- From: Takashi Iwai tiwai@suse.de Subject: [PATCH] ALSA: rawmidi: Fix race at copying & updating the position
The rawmidi read and write functions manage runtime stream status such as runtime->appl_ptr and runtime->avail. These point where to copy the new data and how many bytes have been copied (or to be read). The problem is that rawmidi read/write call copy_from_user() or copy_to_user(), and the runtime spinlock is temporarily unlocked and relocked while copying user-space. Since the current code advances and updates the runtime status after the spin unlock/relock, the copy and the update may be asynchronous, and eventually runtime->avail might go to a negative value when many concurrent accesses are done. This may lead to memory corruption in the end.
For fixing this race, in this patch, the status update code is performed in the same lock before the temporary unlock. Also, the spinlock is now taken more widely in snd_rawmidi_kernel_read1() for protecting more properly during the whole operation.
BugLink: http://lkml.kernel.org/r/CACT4Y+b-dCmNf1GpgPKfDO0ih+uZCL2JV4__j-r1kdhPLSgQCQ... Reported-by: Dmitry Vyukov dvyukov@google.com Tested-by: Dmitry Vyukov dvyukov@google.com Cc: stable@vger.kernel.org Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/core/rawmidi.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-)
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 26ca02248885..795437b10082 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -942,31 +942,36 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, unsigned long flags; long result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long appl_ptr;
+ spin_lock_irqsave(&runtime->lock, flags); while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; if (count1 > count) count1 = count; - spin_lock_irqsave(&runtime->lock, flags); if (count1 > (int)runtime->avail) count1 = runtime->avail; + + /* update runtime->appl_ptr before unlocking for userbuf */ + appl_ptr = runtime->appl_ptr; + runtime->appl_ptr += count1; + runtime->appl_ptr %= runtime->buffer_size; + runtime->avail -= count1; + if (kernelbuf) - memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1); + memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1); if (userbuf) { spin_unlock_irqrestore(&runtime->lock, flags); if (copy_to_user(userbuf + result, - runtime->buffer + runtime->appl_ptr, count1)) { + runtime->buffer + appl_ptr, count1)) { return result > 0 ? result : -EFAULT; } spin_lock_irqsave(&runtime->lock, flags); } - runtime->appl_ptr += count1; - runtime->appl_ptr %= runtime->buffer_size; - runtime->avail -= count1; - spin_unlock_irqrestore(&runtime->lock, flags); result += count1; count -= count1; } + spin_unlock_irqrestore(&runtime->lock, flags); return result; }
@@ -1223,6 +1228,7 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, unsigned long flags; long count1, result; struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long appl_ptr;
if (!kernelbuf && !userbuf) return -EINVAL; @@ -1243,12 +1249,19 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, count1 = count; if (count1 > (long)runtime->avail) count1 = runtime->avail; + + /* update runtime->appl_ptr before unlocking for userbuf */ + appl_ptr = runtime->appl_ptr; + runtime->appl_ptr += count1; + runtime->appl_ptr %= runtime->buffer_size; + runtime->avail -= count1; + if (kernelbuf) - memcpy(runtime->buffer + runtime->appl_ptr, + memcpy(runtime->buffer + appl_ptr, kernelbuf + result, count1); else if (userbuf) { spin_unlock_irqrestore(&runtime->lock, flags); - if (copy_from_user(runtime->buffer + runtime->appl_ptr, + if (copy_from_user(runtime->buffer + appl_ptr, userbuf + result, count1)) { spin_lock_irqsave(&runtime->lock, flags); result = result > 0 ? result : -EFAULT; @@ -1256,9 +1269,6 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, } spin_lock_irqsave(&runtime->lock, flags); } - runtime->appl_ptr += count1; - runtime->appl_ptr %= runtime->buffer_size; - runtime->avail -= count1; result += count1; count -= count1; }
On Wed, Feb 3, 2016 at 10:35 AM, Takashi Iwai tiwai@suse.de wrote:
On Wed, 03 Feb 2016 09:57:50 +0100, Dmitry Vyukov wrote:
Hello,
The following program triggers an out-of-bounds write in snd_rawmidi_kernel_write1 (run in parallel loop). It seems to try to copy -1 bytes (aka 4GB) from user space into kernel smashing all on its way.
What card is /dev/midi3? Please check /proc/asound/cards. Is it MTPAV?
Yes, it was MTPAV. There is only generic code in the stack traces, so I though it may be a generic issue. Though, of course, the driver could mess things already. I've dropped CONFIG_SND_MTPAV now.
participants (2)
-
Dmitry Vyukov
-
Takashi Iwai