Skip to content

Commit 47e594b

Browse files
committed
smb: client: fix potential OOBs in smb2_parse_contexts()
jira LE-1907 cve CVE-2023-52434 Rebuild_History Non-Buildable kernel-5.14.0-427.16.1.el9_4 commit-author Paulo Alcantara <[email protected]> commit af1689a Empty-Commit: Cherry-Pick Conflicts during history rebuild. Will be included in final tarball splat. Ref for failed cherry-pick at: ciq/ciq_backports/kernel-5.14.0-427.16.1.el9_4/af1689a9.failed Validate offsets and lengths before dereferencing create contexts in smb2_parse_contexts(). This fixes following oops when accessing invalid create contexts from server: BUG: unable to handle page fault for address: ffff8881178d8cc3 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 4a01067 P4D 4a01067 PUD 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 3 PID: 1736 Comm: mount.cifs Not tainted 6.7.0-rc4 #1 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.2-3-gd478f380-rebuilt.opensuse.org 04/01/2014 RIP: 0010:smb2_parse_contexts+0xa0/0x3a0 [cifs] Code: f8 10 75 13 48 b8 93 ad 25 50 9c b4 11 e7 49 39 06 0f 84 d2 00 00 00 8b 45 00 85 c0 74 61 41 29 c5 48 01 c5 41 83 fd 0f 76 55 <0f> b7 7d 04 0f b7 45 06 4c 8d 74 3d 00 66 83 f8 04 75 bc ba 04 00 RSP: 0018:ffffc900007939e0 EFLAGS: 00010216 RAX: ffffc90000793c78 RBX: ffff8880180cc000 RCX: ffffc90000793c90 RDX: ffffc90000793cc0 RSI: ffff8880178d8cc0 RDI: ffff8880180cc000 RBP: ffff8881178d8cbf R08: ffffc90000793c22 R09: 0000000000000000 R10: ffff8880180cc000 R11: 0000000000000024 R12: 0000000000000000 R13: 0000000000000020 R14: 0000000000000000 R15: ffffc90000793c22 FS: 00007f873753cbc0(0000) GS:ffff88806bc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffff8881178d8cc3 CR3: 00000000181ca000 CR4: 0000000000750ef0 PKRU: 55555554 Call Trace: <TASK> ? __die+0x23/0x70 ? page_fault_oops+0x181/0x480 ? search_module_extables+0x19/0x60 ? srso_alias_return_thunk+0x5/0xfbef5 ? exc_page_fault+0x1b6/0x1c0 ? asm_exc_page_fault+0x26/0x30 ? smb2_parse_contexts+0xa0/0x3a0 [cifs] SMB2_open+0x38d/0x5f0 [cifs] ? smb2_is_path_accessible+0x138/0x260 [cifs] smb2_is_path_accessible+0x138/0x260 [cifs] cifs_is_path_remote+0x8d/0x230 [cifs] cifs_mount+0x7e/0x350 [cifs] cifs_smb3_do_mount+0x128/0x780 [cifs] smb3_get_tree+0xd9/0x290 [cifs] vfs_get_tree+0x2c/0x100 ? capable+0x37/0x70 path_mount+0x2d7/0xb80 ? srso_alias_return_thunk+0x5/0xfbef5 ? _raw_spin_unlock_irqrestore+0x44/0x60 __x64_sys_mount+0x11a/0x150 do_syscall_64+0x47/0xf0 entry_SYSCALL_64_after_hwframe+0x6f/0x77 RIP: 0033:0x7f8737657b1e Reported-by: Robert Morris <[email protected]> Cc: [email protected] Signed-off-by: Paulo Alcantara (SUSE) <[email protected]> Signed-off-by: Steve French <[email protected]> (cherry picked from commit af1689a) Signed-off-by: Jonathan Maple <[email protected]> # Conflicts: # fs/smb/client/cached_dir.c
1 parent ff0e559 commit 47e594b

File tree

1 file changed

+282
-0
lines changed

1 file changed

+282
-0
lines changed
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
smb: client: fix potential OOBs in smb2_parse_contexts()
2+
3+
jira LE-1907
4+
cve CVE-2023-52434
5+
Rebuild_History Non-Buildable kernel-5.14.0-427.16.1.el9_4
6+
commit-author Paulo Alcantara <[email protected]>
7+
commit af1689a9b7701d9907dfc84d2a4b57c4bc907144
8+
Empty-Commit: Cherry-Pick Conflicts during history rebuild.
9+
Will be included in final tarball splat. Ref for failed cherry-pick at:
10+
ciq/ciq_backports/kernel-5.14.0-427.16.1.el9_4/af1689a9.failed
11+
12+
Validate offsets and lengths before dereferencing create contexts in
13+
smb2_parse_contexts().
14+
15+
This fixes following oops when accessing invalid create contexts from
16+
server:
17+
18+
BUG: unable to handle page fault for address: ffff8881178d8cc3
19+
#PF: supervisor read access in kernel mode
20+
#PF: error_code(0x0000) - not-present page
21+
PGD 4a01067 P4D 4a01067 PUD 0
22+
Oops: 0000 [#1] PREEMPT SMP NOPTI
23+
CPU: 3 PID: 1736 Comm: mount.cifs Not tainted 6.7.0-rc4 #1
24+
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS
25+
rel-1.16.2-3-gd478f380-rebuilt.opensuse.org 04/01/2014
26+
RIP: 0010:smb2_parse_contexts+0xa0/0x3a0 [cifs]
27+
Code: f8 10 75 13 48 b8 93 ad 25 50 9c b4 11 e7 49 39 06 0f 84 d2 00
28+
00 00 8b 45 00 85 c0 74 61 41 29 c5 48 01 c5 41 83 fd 0f 76 55 <0f> b7
29+
7d 04 0f b7 45 06 4c 8d 74 3d 00 66 83 f8 04 75 bc ba 04 00
30+
RSP: 0018:ffffc900007939e0 EFLAGS: 00010216
31+
RAX: ffffc90000793c78 RBX: ffff8880180cc000 RCX: ffffc90000793c90
32+
RDX: ffffc90000793cc0 RSI: ffff8880178d8cc0 RDI: ffff8880180cc000
33+
RBP: ffff8881178d8cbf R08: ffffc90000793c22 R09: 0000000000000000
34+
R10: ffff8880180cc000 R11: 0000000000000024 R12: 0000000000000000
35+
R13: 0000000000000020 R14: 0000000000000000 R15: ffffc90000793c22
36+
FS: 00007f873753cbc0(0000) GS:ffff88806bc00000(0000)
37+
knlGS:0000000000000000
38+
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
39+
CR2: ffff8881178d8cc3 CR3: 00000000181ca000 CR4: 0000000000750ef0
40+
PKRU: 55555554
41+
Call Trace:
42+
<TASK>
43+
? __die+0x23/0x70
44+
? page_fault_oops+0x181/0x480
45+
? search_module_extables+0x19/0x60
46+
? srso_alias_return_thunk+0x5/0xfbef5
47+
? exc_page_fault+0x1b6/0x1c0
48+
? asm_exc_page_fault+0x26/0x30
49+
? smb2_parse_contexts+0xa0/0x3a0 [cifs]
50+
SMB2_open+0x38d/0x5f0 [cifs]
51+
? smb2_is_path_accessible+0x138/0x260 [cifs]
52+
smb2_is_path_accessible+0x138/0x260 [cifs]
53+
cifs_is_path_remote+0x8d/0x230 [cifs]
54+
cifs_mount+0x7e/0x350 [cifs]
55+
cifs_smb3_do_mount+0x128/0x780 [cifs]
56+
smb3_get_tree+0xd9/0x290 [cifs]
57+
vfs_get_tree+0x2c/0x100
58+
? capable+0x37/0x70
59+
path_mount+0x2d7/0xb80
60+
? srso_alias_return_thunk+0x5/0xfbef5
61+
? _raw_spin_unlock_irqrestore+0x44/0x60
62+
__x64_sys_mount+0x11a/0x150
63+
do_syscall_64+0x47/0xf0
64+
entry_SYSCALL_64_after_hwframe+0x6f/0x77
65+
RIP: 0033:0x7f8737657b1e
66+
67+
Reported-by: Robert Morris <[email protected]>
68+
69+
Signed-off-by: Paulo Alcantara (SUSE) <[email protected]>
70+
Signed-off-by: Steve French <[email protected]>
71+
(cherry picked from commit af1689a9b7701d9907dfc84d2a4b57c4bc907144)
72+
Signed-off-by: Jonathan Maple <[email protected]>
73+
74+
# Conflicts:
75+
# fs/smb/client/cached_dir.c
76+
diff --cc fs/smb/client/cached_dir.c
77+
index bfc964b36c72,d64a306a414b..000000000000
78+
--- a/fs/smb/client/cached_dir.c
79+
+++ b/fs/smb/client/cached_dir.c
80+
@@@ -265,18 -291,32 +265,40 @@@ int open_cached_dir(unsigned int xid, s
81+
oparms.fid->mid = le64_to_cpu(o_rsp->hdr.MessageId);
82+
#endif /* CIFS_DEBUG2 */
83+
84+
++<<<<<<< HEAD
85+
+ if (o_rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
86+
++=======
87+
+
88+
+ if (o_rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE) {
89+
+ spin_unlock(&cfids->cfid_list_lock);
90+
+ rc = -EINVAL;
91+
+ goto oshr_free;
92+
+ }
93+
+
94+
+ rc = smb2_parse_contexts(server, rsp_iov,
95+
+ &oparms.fid->epoch,
96+
+ oparms.fid->lease_key,
97+
+ &oplock, NULL, NULL);
98+
+ if (rc) {
99+
+ spin_unlock(&cfids->cfid_list_lock);
100+
++>>>>>>> af1689a9b770 (smb: client: fix potential OOBs in smb2_parse_contexts())
101+
goto oshr_free;
102+
- }
103+
104+
++<<<<<<< HEAD
105+
+ smb2_parse_contexts(server, o_rsp,
106+
+ &oparms.fid->epoch,
107+
+ oparms.fid->lease_key, &oplock,
108+
+ NULL, NULL);
109+
+ if (!(oplock & SMB2_LEASE_READ_CACHING_HE))
110+
++=======
111+
+ rc = -EINVAL;
112+
+ if (!(oplock & SMB2_LEASE_READ_CACHING_HE)) {
113+
+ spin_unlock(&cfids->cfid_list_lock);
114+
++>>>>>>> af1689a9b770 (smb: client: fix potential OOBs in smb2_parse_contexts())
115+
goto oshr_free;
116+
- }
117+
qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
118+
- if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info)) {
119+
- spin_unlock(&cfids->cfid_list_lock);
120+
+ if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info))
121+
goto oshr_free;
122+
- }
123+
if (!smb2_validate_and_copy_iov(
124+
le16_to_cpu(qi_rsp->OutputBufferOffset),
125+
sizeof(struct smb2_file_all_info),
126+
* Unmerged path fs/smb/client/cached_dir.c
127+
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
128+
index 456aa71f0a98..31bf5cdb5d81 100644
129+
--- a/fs/smb/client/smb2pdu.c
130+
+++ b/fs/smb/client/smb2pdu.c
131+
@@ -2125,17 +2125,18 @@ parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *info,
132+
posix->nlink, posix->mode, posix->reparse_tag);
133+
}
134+
135+
-void
136+
-smb2_parse_contexts(struct TCP_Server_Info *server,
137+
- struct smb2_create_rsp *rsp,
138+
- unsigned int *epoch, char *lease_key, __u8 *oplock,
139+
- struct smb2_file_all_info *buf,
140+
- struct create_posix_rsp *posix)
141+
+int smb2_parse_contexts(struct TCP_Server_Info *server,
142+
+ struct kvec *rsp_iov,
143+
+ unsigned int *epoch,
144+
+ char *lease_key, __u8 *oplock,
145+
+ struct smb2_file_all_info *buf,
146+
+ struct create_posix_rsp *posix)
147+
{
148+
- char *data_offset;
149+
+ struct smb2_create_rsp *rsp = rsp_iov->iov_base;
150+
struct create_context *cc;
151+
- unsigned int next;
152+
- unsigned int remaining;
153+
+ size_t rem, off, len;
154+
+ size_t doff, dlen;
155+
+ size_t noff, nlen;
156+
char *name;
157+
static const char smb3_create_tag_posix[] = {
158+
0x93, 0xAD, 0x25, 0x50, 0x9C,
159+
@@ -2144,45 +2145,63 @@ smb2_parse_contexts(struct TCP_Server_Info *server,
160+
};
161+
162+
*oplock = 0;
163+
- data_offset = (char *)rsp + le32_to_cpu(rsp->CreateContextsOffset);
164+
- remaining = le32_to_cpu(rsp->CreateContextsLength);
165+
- cc = (struct create_context *)data_offset;
166+
+
167+
+ off = le32_to_cpu(rsp->CreateContextsOffset);
168+
+ rem = le32_to_cpu(rsp->CreateContextsLength);
169+
+ if (check_add_overflow(off, rem, &len) || len > rsp_iov->iov_len)
170+
+ return -EINVAL;
171+
+ cc = (struct create_context *)((u8 *)rsp + off);
172+
173+
/* Initialize inode number to 0 in case no valid data in qfid context */
174+
if (buf)
175+
buf->IndexNumber = 0;
176+
177+
- while (remaining >= sizeof(struct create_context)) {
178+
- name = le16_to_cpu(cc->NameOffset) + (char *)cc;
179+
- if (le16_to_cpu(cc->NameLength) == 4 &&
180+
- strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4) == 0)
181+
- *oplock = server->ops->parse_lease_buf(cc, epoch,
182+
- lease_key);
183+
- else if (buf && (le16_to_cpu(cc->NameLength) == 4) &&
184+
- strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4) == 0)
185+
- parse_query_id_ctxt(cc, buf);
186+
- else if ((le16_to_cpu(cc->NameLength) == 16)) {
187+
- if (posix &&
188+
- memcmp(name, smb3_create_tag_posix, 16) == 0)
189+
+ while (rem >= sizeof(*cc)) {
190+
+ doff = le16_to_cpu(cc->DataOffset);
191+
+ dlen = le32_to_cpu(cc->DataLength);
192+
+ if (check_add_overflow(doff, dlen, &len) || len > rem)
193+
+ return -EINVAL;
194+
+
195+
+ noff = le16_to_cpu(cc->NameOffset);
196+
+ nlen = le16_to_cpu(cc->NameLength);
197+
+ if (noff + nlen >= doff)
198+
+ return -EINVAL;
199+
+
200+
+ name = (char *)cc + noff;
201+
+ switch (nlen) {
202+
+ case 4:
203+
+ if (!strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) {
204+
+ *oplock = server->ops->parse_lease_buf(cc, epoch,
205+
+ lease_key);
206+
+ } else if (buf &&
207+
+ !strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4)) {
208+
+ parse_query_id_ctxt(cc, buf);
209+
+ }
210+
+ break;
211+
+ case 16:
212+
+ if (posix && !memcmp(name, smb3_create_tag_posix, 16))
213+
parse_posix_ctxt(cc, buf, posix);
214+
+ break;
215+
+ default:
216+
+ cifs_dbg(FYI, "%s: unhandled context (nlen=%zu dlen=%zu)\n",
217+
+ __func__, nlen, dlen);
218+
+ if (IS_ENABLED(CONFIG_CIFS_DEBUG2))
219+
+ cifs_dump_mem("context data: ", cc, dlen);
220+
+ break;
221+
}
222+
- /* else {
223+
- cifs_dbg(FYI, "Context not matched with len %d\n",
224+
- le16_to_cpu(cc->NameLength));
225+
- cifs_dump_mem("Cctxt name: ", name, 4);
226+
- } */
227+
-
228+
- next = le32_to_cpu(cc->Next);
229+
- if (!next)
230+
+
231+
+ off = le32_to_cpu(cc->Next);
232+
+ if (!off)
233+
break;
234+
- remaining -= next;
235+
- cc = (struct create_context *)((char *)cc + next);
236+
+ if (check_sub_overflow(rem, off, &rem))
237+
+ return -EINVAL;
238+
+ cc = (struct create_context *)((u8 *)cc + off);
239+
}
240+
241+
if (rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
242+
*oplock = rsp->OplockLevel;
243+
244+
- return;
245+
+ return 0;
246+
}
247+
248+
static int
249+
@@ -3013,8 +3032,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
250+
}
251+
252+
253+
- smb2_parse_contexts(server, rsp, &oparms->fid->epoch,
254+
- oparms->fid->lease_key, oplock, buf, posix);
255+
+ rc = smb2_parse_contexts(server, &rsp_iov, &oparms->fid->epoch,
256+
+ oparms->fid->lease_key, oplock, buf, posix);
257+
creat_exit:
258+
SMB2_open_free(&rqst);
259+
free_rsp_buf(resp_buftype, rsp);
260+
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
261+
index d5d7ffb7711c..8a386e4e0d75 100644
262+
--- a/fs/smb/client/smb2proto.h
263+
+++ b/fs/smb/client/smb2proto.h
264+
@@ -249,11 +249,13 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
265+
266+
extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
267+
enum securityEnum);
268+
-extern void smb2_parse_contexts(struct TCP_Server_Info *server,
269+
- struct smb2_create_rsp *rsp,
270+
- unsigned int *epoch, char *lease_key,
271+
- __u8 *oplock, struct smb2_file_all_info *buf,
272+
- struct create_posix_rsp *posix);
273+
+int smb2_parse_contexts(struct TCP_Server_Info *server,
274+
+ struct kvec *rsp_iov,
275+
+ unsigned int *epoch,
276+
+ char *lease_key, __u8 *oplock,
277+
+ struct smb2_file_all_info *buf,
278+
+ struct create_posix_rsp *posix);
279+
+
280+
extern int smb3_encryption_required(const struct cifs_tcon *tcon);
281+
extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
282+
struct kvec *iov, unsigned int min_buf_size);

0 commit comments

Comments
 (0)