mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	RDMA/uverbs: Fix slab-out-of-bounds in ib_uverbs_ex_create_flow
The check of cmd.flow_attr.size should check into account the size of the
reserved field (2 bytes), otherwise user can provide a size which will
cause a slab-out-of-bounds warning below.
==================================================================
BUG: KASAN: slab-out-of-bounds in ib_uverbs_ex_create_flow+0x1740/0x1d00
Read of size 2 at addr ffff880068dff1a6 by task syz-executor775/269
CPU: 0 PID: 269 Comm: syz-executor775 Not tainted 4.18.0-rc1+ #245
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
rel-1.11.0-0-g63451fca13-prebuilt.qemu-project.org 04/01/2014
Call Trace:
 dump_stack+0xef/0x17e
 print_address_description+0x83/0x3b0
 kasan_report+0x18d/0x4d0
 ib_uverbs_ex_create_flow+0x1740/0x1d00
 ib_uverbs_write+0x923/0x1010
 __vfs_write+0x10d/0x720
 vfs_write+0x1b0/0x550
 ksys_write+0xc6/0x1a0
 do_syscall_64+0xa7/0x590
 entry_SYSCALL_64_after_hwframe+0x49/0xbe
RIP: 0033:0x433899
Code: fd ff 48 81 c4 80 00 00 00 e9 f1 fe ff ff 0f 1f 00 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 0f 83 3b 91 fd ff c3 66
2e 0f 1f 84 00 00 00 00
RSP: 002b:00007ffc2724db58 EFLAGS: 00000217 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 0000000020006880 RCX: 0000000000433899
RDX: 00000000000000e0 RSI: 0000000020002480 RDI: 0000000000000003
RBP: 00000000006d7018 R08: 00000000004002f8 R09: 00000000004002f8
R10: 00000000004002f8 R11: 0000000000000217 R12: 0000000000000000
R13: 000000000040cd20 R14: 000000000040cdb0 R15: 0000000000000006
Allocated by task 269:
 kasan_kmalloc+0xa0/0xd0
 __kmalloc+0x1a9/0x510
 ib_uverbs_ex_create_flow+0x26c/0x1d00
 ib_uverbs_write+0x923/0x1010
 __vfs_write+0x10d/0x720
 vfs_write+0x1b0/0x550
 ksys_write+0xc6/0x1a0
 do_syscall_64+0xa7/0x590
 entry_SYSCALL_64_after_hwframe+0x49/0xbe
Freed by task 0:
 __kasan_slab_free+0x12e/0x180
 kfree+0x159/0x630
 detach_buf+0x559/0x7a0
 virtqueue_get_buf_ctx+0x3cc/0xab0
 virtblk_done+0x1eb/0x3d0
 vring_interrupt+0x16d/0x2b0
 __handle_irq_event_percpu+0x10a/0x980
 handle_irq_event_percpu+0x77/0x190
 handle_irq_event+0xc6/0x1a0
 handle_edge_irq+0x211/0xd80
 handle_irq+0x3d/0x60
 do_IRQ+0x9b/0x220
The buggy address belongs to the object at ffff880068dff180
 which belongs to the cache kmalloc-64 of size 64
The buggy address is located 38 bytes inside of
 64-byte region [ffff880068dff180, ffff880068dff1c0)
The buggy address belongs to the page:
page:ffffea0001a37fc0 count:1 mapcount:0 mapping:ffff88006c401780
index:0x0
flags: 0x4000000000000100(slab)
raw: 4000000000000100 ffffea0001a31100 0000001100000011 ffff88006c401780
raw: 0000000000000000 00000000802a002a 00000001ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
 ffff880068dff080: fb fb fb fb fc fc fc fc fb fb fb fb fb fb fb fb
 ffff880068dff100: fc fc fc fc fb fb fb fb fb fb fb fb fc fc fc fc
>ffff880068dff180: 00 00 00 00 07 fc fc fc fc fc fc fc fb fb fb fb
                               ^
 ffff880068dff200: fb fb fb fb fc fc fc fc 00 00 00 00 00 00 fc fc
 ffff880068dff280: fc fc fc fc 00 00 00 00 00 00 00 00 fc fc fc fc
==================================================================
Cc: <stable@vger.kernel.org> # 3.12
Fixes: f884827438 ("IB/core: clarify overflow/underflow checks on ib_create/destroy_flow")
Cc: syzkaller <syzkaller@googlegroups.com>
Reported-by: Noa Osherovich <noaos@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
			
			
This commit is contained in:
		
							parent
							
								
									940efcc888
								
							
						
					
					
						commit
						4fae7f1704
					
				
					 1 changed files with 12 additions and 11 deletions
				
			
		| 
						 | 
				
			
			@ -3488,8 +3488,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
 | 
			
		|||
	struct ib_flow_attr		  *flow_attr;
 | 
			
		||||
	struct ib_qp			  *qp;
 | 
			
		||||
	struct ib_uflow_resources	  *uflow_res;
 | 
			
		||||
	struct ib_uverbs_flow_spec_hdr	  *kern_spec;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
	void *kern_spec;
 | 
			
		||||
	void *ib_spec;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3538,8 +3538,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
 | 
			
		|||
		if (!kern_flow_attr)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
		memcpy(kern_flow_attr, &cmd.flow_attr, sizeof(*kern_flow_attr));
 | 
			
		||||
		err = ib_copy_from_udata(kern_flow_attr + 1, ucore,
 | 
			
		||||
		*kern_flow_attr = cmd.flow_attr;
 | 
			
		||||
		err = ib_copy_from_udata(&kern_flow_attr->flow_specs, ucore,
 | 
			
		||||
					 cmd.flow_attr.size);
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto err_free_attr;
 | 
			
		||||
| 
						 | 
				
			
			@ -3583,21 +3583,22 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
 | 
			
		|||
	flow_attr->flags = kern_flow_attr->flags;
 | 
			
		||||
	flow_attr->size = sizeof(*flow_attr);
 | 
			
		||||
 | 
			
		||||
	kern_spec = kern_flow_attr + 1;
 | 
			
		||||
	kern_spec = kern_flow_attr->flow_specs;
 | 
			
		||||
	ib_spec = flow_attr + 1;
 | 
			
		||||
	for (i = 0; i < flow_attr->num_of_specs &&
 | 
			
		||||
	     cmd.flow_attr.size > offsetof(struct ib_uverbs_flow_spec, reserved) &&
 | 
			
		||||
	     cmd.flow_attr.size >=
 | 
			
		||||
	     ((struct ib_uverbs_flow_spec *)kern_spec)->size; i++) {
 | 
			
		||||
		err = kern_spec_to_ib_spec(file->ucontext, kern_spec, ib_spec,
 | 
			
		||||
					   uflow_res);
 | 
			
		||||
			cmd.flow_attr.size > sizeof(*kern_spec) &&
 | 
			
		||||
			cmd.flow_attr.size >= kern_spec->size;
 | 
			
		||||
	     i++) {
 | 
			
		||||
		err = kern_spec_to_ib_spec(
 | 
			
		||||
				file->ucontext, (struct ib_uverbs_flow_spec *)kern_spec,
 | 
			
		||||
				ib_spec, uflow_res);
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto err_free;
 | 
			
		||||
 | 
			
		||||
		flow_attr->size +=
 | 
			
		||||
			((union ib_flow_spec *) ib_spec)->size;
 | 
			
		||||
		cmd.flow_attr.size -= ((struct ib_uverbs_flow_spec *)kern_spec)->size;
 | 
			
		||||
		kern_spec += ((struct ib_uverbs_flow_spec *) kern_spec)->size;
 | 
			
		||||
		cmd.flow_attr.size -= kern_spec->size;
 | 
			
		||||
		kern_spec = ((void *)kern_spec) + kern_spec->size;
 | 
			
		||||
		ib_spec += ((union ib_flow_spec *) ib_spec)->size;
 | 
			
		||||
	}
 | 
			
		||||
	if (cmd.flow_attr.size || (i != flow_attr->num_of_specs)) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue