Skip to content

Commit f3d66d4

Browse files
Leon Romanovskygregkh
authored andcommitted
RDMA/uverbs: Protect from command mask overflow
commit 3f802b1 upstream. The command number is not bounds checked against the command mask before it is shifted, resulting in an ubsan hit. This does not cause malfunction since the command number is eventually bounds checked, but we can make this ubsan clean by moving the bounds check to before the mask check. ================================================================================ UBSAN: Undefined behaviour in drivers/infiniband/core/uverbs_main.c:647:21 shift exponent 207 is too large for 64-bit type 'long long unsigned int' CPU: 0 PID: 446 Comm: syz-executor3 Not tainted 4.15.0-rc2+ #61 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 Call Trace: dump_stack+0xde/0x164 ? dma_virt_map_sg+0x22c/0x22c ubsan_epilogue+0xe/0x81 __ubsan_handle_shift_out_of_bounds+0x293/0x2f7 ? debug_check_no_locks_freed+0x340/0x340 ? __ubsan_handle_load_invalid_value+0x19b/0x19b ? lock_acquire+0x440/0x440 ? lock_acquire+0x19d/0x440 ? __might_fault+0xf4/0x240 ? ib_uverbs_write+0x68d/0xe20 ib_uverbs_write+0x68d/0xe20 ? __lock_acquire+0xcf7/0x3940 ? uverbs_devnode+0x110/0x110 ? cyc2ns_read_end+0x10/0x10 ? sched_clock_cpu+0x18/0x200 ? sched_clock_cpu+0x18/0x200 __vfs_write+0x10d/0x700 ? uverbs_devnode+0x110/0x110 ? kernel_read+0x170/0x170 ? __fget+0x35b/0x5d0 ? security_file_permission+0x93/0x260 vfs_write+0x1b0/0x550 SyS_write+0xc7/0x1a0 ? SyS_read+0x1a0/0x1a0 ? trace_hardirqs_on_thunk+0x1a/0x1c entry_SYSCALL_64_fastpath+0x18/0x85 RIP: 0033:0x448e29 RSP: 002b:00007f033f567c58 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 00007f033f5686bc RCX: 0000000000448e29 RDX: 0000000000000060 RSI: 0000000020001000 RDI: 0000000000000012 RBP: 000000000070bea0 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00000000ffffffff R13: 00000000000056a0 R14: 00000000006e8740 R15: 0000000000000000 ================================================================================ Cc: syzkaller <syzkaller@googlegroups.com> Cc: <stable@vger.kernel.org> # 4.5 Fixes: 2dbd518 ("IB/core: IB/core: Allow legacy verbs through extended interfaces") Reported-by: Noa Osherovich <noaos@mellanox.com> Reviewed-by: Matan Barak <matanb@mellanox.com> Signed-off-by: Leon Romanovsky <leonro@mellanox.com> Signed-off-by: Jason Gunthorpe <jgg@mellanox.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent da768ed commit f3d66d4

File tree

1 file changed

+20
-7
lines changed

1 file changed

+20
-7
lines changed

drivers/infiniband/core/uverbs_main.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -647,12 +647,21 @@ static int verify_command_mask(struct ib_device *ib_dev, __u32 command)
647647
return -1;
648648
}
649649

650+
static bool verify_command_idx(u32 command, bool extended)
651+
{
652+
if (extended)
653+
return command < ARRAY_SIZE(uverbs_ex_cmd_table);
654+
655+
return command < ARRAY_SIZE(uverbs_cmd_table);
656+
}
657+
650658
static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
651659
size_t count, loff_t *pos)
652660
{
653661
struct ib_uverbs_file *file = filp->private_data;
654662
struct ib_device *ib_dev;
655663
struct ib_uverbs_cmd_hdr hdr;
664+
bool extended_command;
656665
__u32 command;
657666
__u32 flags;
658667
int srcu_key;
@@ -685,6 +694,15 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
685694
}
686695

687696
command = hdr.command & IB_USER_VERBS_CMD_COMMAND_MASK;
697+
flags = (hdr.command &
698+
IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT;
699+
700+
extended_command = flags & IB_USER_VERBS_CMD_FLAG_EXTENDED;
701+
if (!verify_command_idx(command, extended_command)) {
702+
ret = -EINVAL;
703+
goto out;
704+
}
705+
688706
if (verify_command_mask(ib_dev, command)) {
689707
ret = -EOPNOTSUPP;
690708
goto out;
@@ -696,12 +714,8 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
696714
goto out;
697715
}
698716

699-
flags = (hdr.command &
700-
IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT;
701-
702717
if (!flags) {
703-
if (command >= ARRAY_SIZE(uverbs_cmd_table) ||
704-
!uverbs_cmd_table[command]) {
718+
if (!uverbs_cmd_table[command]) {
705719
ret = -EINVAL;
706720
goto out;
707721
}
@@ -722,8 +736,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
722736
struct ib_udata uhw;
723737
size_t written_count = count;
724738

725-
if (command >= ARRAY_SIZE(uverbs_ex_cmd_table) ||
726-
!uverbs_ex_cmd_table[command]) {
739+
if (!uverbs_ex_cmd_table[command]) {
727740
ret = -ENOSYS;
728741
goto out;
729742
}

0 commit comments

Comments
 (0)