Skip to content

Commit 203a412

Browse files
pcacjrgregkh
authored andcommitted
smb: client: fix OOB in SMB2_query_info_init()
[ Upstream commit 33eae65 ] A small CIFS buffer (448 bytes) isn't big enough to hold SMB2_QUERY_INFO request along with user's input data from CIFS_QUERY_INFO ioctl. That is, if the user passed an input buffer > 344 bytes, the client will memcpy() off the end of @req->Buffer in SMB2_query_info_init() thus causing the following KASAN splat: BUG: KASAN: slab-out-of-bounds in SMB2_query_info_init+0x242/0x250 [cifs] Write of size 1023 at addr ffff88801308c5a8 by task a.out/1240 CPU: 1 PID: 1240 Comm: a.out Not tainted 6.7.0-rc4 khadas#5 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.2-3-gd478f380-rebuilt.opensuse.org 04/01/2014 Call Trace: <TASK> dump_stack_lvl+0x4a/0x80 print_report+0xcf/0x650 ? srso_alias_return_thunk+0x5/0xfbef5 ? srso_alias_return_thunk+0x5/0xfbef5 ? srso_alias_return_thunk+0x5/0xfbef5 ? __phys_addr+0x46/0x90 kasan_report+0xd8/0x110 ? SMB2_query_info_init+0x242/0x250 [cifs] ? SMB2_query_info_init+0x242/0x250 [cifs] kasan_check_range+0x105/0x1b0 __asan_memcpy+0x3c/0x60 SMB2_query_info_init+0x242/0x250 [cifs] ? __pfx_SMB2_query_info_init+0x10/0x10 [cifs] ? srso_alias_return_thunk+0x5/0xfbef5 ? smb_rqst_len+0xa6/0xc0 [cifs] smb2_ioctl_query_info+0x4f4/0x9a0 [cifs] ? __pfx_smb2_ioctl_query_info+0x10/0x10 [cifs] ? __pfx_cifsConvertToUTF16+0x10/0x10 [cifs] ? kasan_set_track+0x25/0x30 ? srso_alias_return_thunk+0x5/0xfbef5 ? __kasan_kmalloc+0x8f/0xa0 ? srso_alias_return_thunk+0x5/0xfbef5 ? cifs_strndup_to_utf16+0x12d/0x1a0 [cifs] ? __build_path_from_dentry_optional_prefix+0x19d/0x2d0 [cifs] ? __pfx_smb2_ioctl_query_info+0x10/0x10 [cifs] cifs_ioctl+0x11c7/0x1de0 [cifs] ? __pfx_cifs_ioctl+0x10/0x10 [cifs] ? srso_alias_return_thunk+0x5/0xfbef5 ? rcu_is_watching+0x23/0x50 ? srso_alias_return_thunk+0x5/0xfbef5 ? __rseq_handle_notify_resume+0x6cd/0x850 ? __pfx___schedule+0x10/0x10 ? blkcg_iostat_update+0x250/0x290 ? srso_alias_return_thunk+0x5/0xfbef5 ? ksys_write+0xe9/0x170 __x64_sys_ioctl+0xc9/0x100 do_syscall_64+0x47/0xf0 entry_SYSCALL_64_after_hwframe+0x6f/0x77 RIP: 0033:0x7f893dde49cf Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 18 48 8b 44 24 18 64 48 2b 04 25 28 00 00 RSP: 002b:00007ffc03ff4160 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 00007ffc03ff4378 RCX: 00007f893dde49cf RDX: 00007ffc03ff41d0 RSI: 00000000c018cf07 RDI: 0000000000000003 RBP: 00007ffc03ff4260 R08: 0000000000000410 R09: 0000000000000001 R10: 00007f893dce7300 R11: 0000000000000246 R12: 0000000000000000 R13: 00007ffc03ff4388 R14: 00007f893df15000 R15: 0000000000406de0 </TASK> Fix this by increasing size of SMB2_QUERY_INFO request buffers and validating input length to prevent other callers from overflowing @Req in SMB2_query_info_init() as well. Fixes: f5b05d6 ("cifs: add IOCTL for QUERY_INFO passthrough to userspace") Cc: [email protected] Reported-by: Robert Morris <[email protected]> Signed-off-by: Paulo Alcantara <[email protected]> Signed-off-by: Steve French <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 79e158d commit 203a412

File tree

1 file changed

+22
-7
lines changed

1 file changed

+22
-7
lines changed

fs/cifs/smb2pdu.c

+22-7
Original file line numberDiff line numberDiff line change
@@ -373,10 +373,15 @@ static int __smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
373373
void **request_buf, unsigned int *total_len)
374374
{
375375
/* BB eventually switch this to SMB2 specific small buf size */
376-
if (smb2_command == SMB2_SET_INFO)
376+
switch (smb2_command) {
377+
case SMB2_SET_INFO:
378+
case SMB2_QUERY_INFO:
377379
*request_buf = cifs_buf_get();
378-
else
380+
break;
381+
default:
379382
*request_buf = cifs_small_buf_get();
383+
break;
384+
}
380385
if (*request_buf == NULL) {
381386
/* BB should we add a retry in here if not a writepage? */
382387
return -ENOMEM;
@@ -3346,8 +3351,13 @@ SMB2_query_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
33463351
struct smb2_query_info_req *req;
33473352
struct kvec *iov = rqst->rq_iov;
33483353
unsigned int total_len;
3354+
size_t len;
33493355
int rc;
33503356

3357+
if (unlikely(check_add_overflow(input_len, sizeof(*req), &len) ||
3358+
len > CIFSMaxBufSize))
3359+
return -EINVAL;
3360+
33513361
rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, server,
33523362
(void **) &req, &total_len);
33533363
if (rc)
@@ -3369,15 +3379,15 @@ SMB2_query_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
33693379

33703380
iov[0].iov_base = (char *)req;
33713381
/* 1 for Buffer */
3372-
iov[0].iov_len = total_len - 1 + input_len;
3382+
iov[0].iov_len = len;
33733383
return 0;
33743384
}
33753385

33763386
void
33773387
SMB2_query_info_free(struct smb_rqst *rqst)
33783388
{
33793389
if (rqst && rqst->rq_iov)
3380-
cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */
3390+
cifs_buf_release(rqst->rq_iov[0].iov_base); /* request */
33813391
}
33823392

33833393
static int
@@ -5104,6 +5114,11 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon,
51045114
return 0;
51055115
}
51065116

5117+
static inline void free_qfs_info_req(struct kvec *iov)
5118+
{
5119+
cifs_buf_release(iov->iov_base);
5120+
}
5121+
51075122
int
51085123
SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
51095124
u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata)
@@ -5135,7 +5150,7 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
51355150

51365151
rc = cifs_send_recv(xid, ses, server,
51375152
&rqst, &resp_buftype, flags, &rsp_iov);
5138-
cifs_small_buf_release(iov.iov_base);
5153+
free_qfs_info_req(&iov);
51395154
if (rc) {
51405155
cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
51415156
goto posix_qfsinf_exit;
@@ -5186,7 +5201,7 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
51865201

51875202
rc = cifs_send_recv(xid, ses, server,
51885203
&rqst, &resp_buftype, flags, &rsp_iov);
5189-
cifs_small_buf_release(iov.iov_base);
5204+
free_qfs_info_req(&iov);
51905205
if (rc) {
51915206
cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
51925207
goto qfsinf_exit;
@@ -5253,7 +5268,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
52535268

52545269
rc = cifs_send_recv(xid, ses, server,
52555270
&rqst, &resp_buftype, flags, &rsp_iov);
5256-
cifs_small_buf_release(iov.iov_base);
5271+
free_qfs_info_req(&iov);
52575272
if (rc) {
52585273
cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
52595274
goto qfsattr_exit;

0 commit comments

Comments
 (0)