Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag '6.7-rc5-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:
"Address OOBs and NULL dereference found by Dr. Morris's recent
analysis and fuzzing.

All marked for stable as well"

* tag '6.7-rc5-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
smb: client: fix OOB in smb2_query_reparse_point()
smb: client: fix NULL deref in asn1_ber_decoder()
smb: client: fix potential OOBs in smb2_parse_contexts()
smb: client: fix OOB in receive_encrypted_standard()

+110 -80
+12 -5
fs/smb/client/cached_dir.c
··· 291 291 oparms.fid->mid = le64_to_cpu(o_rsp->hdr.MessageId); 292 292 #endif /* CIFS_DEBUG2 */ 293 293 294 - rc = -EINVAL; 294 + 295 295 if (o_rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE) { 296 + spin_unlock(&cfids->cfid_list_lock); 297 + rc = -EINVAL; 298 + goto oshr_free; 299 + } 300 + 301 + rc = smb2_parse_contexts(server, rsp_iov, 302 + &oparms.fid->epoch, 303 + oparms.fid->lease_key, 304 + &oplock, NULL, NULL); 305 + if (rc) { 296 306 spin_unlock(&cfids->cfid_list_lock); 297 307 goto oshr_free; 298 308 } 299 309 300 - smb2_parse_contexts(server, o_rsp, 301 - &oparms.fid->epoch, 302 - oparms.fid->lease_key, &oplock, 303 - NULL, NULL); 310 + rc = -EINVAL; 304 311 if (!(oplock & SMB2_LEASE_READ_CACHING_HE)) { 305 312 spin_unlock(&cfids->cfid_list_lock); 306 313 goto oshr_free;
+10 -16
fs/smb/client/smb2misc.c
··· 313 313 char * 314 314 smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *shdr) 315 315 { 316 + const int max_off = 4096; 317 + const int max_len = 128 * 1024; 318 + 316 319 *off = 0; 317 320 *len = 0; 318 321 ··· 387 384 * Invalid length or offset probably means data area is invalid, but 388 385 * we have little choice but to ignore the data area in this case. 389 386 */ 390 - if (*off > 4096) { 391 - cifs_dbg(VFS, "offset %d too large, data area ignored\n", *off); 392 - *len = 0; 393 - *off = 0; 394 - } else if (*off < 0) { 395 - cifs_dbg(VFS, "negative offset %d to data invalid ignore data area\n", 396 - *off); 387 + if (unlikely(*off < 0 || *off > max_off || 388 + *len < 0 || *len > max_len)) { 389 + cifs_dbg(VFS, "%s: invalid data area (off=%d len=%d)\n", 390 + __func__, *off, *len); 397 391 *off = 0; 398 392 *len = 0; 399 - } else if (*len < 0) { 400 - cifs_dbg(VFS, "negative data length %d invalid, data area ignored\n", 401 - *len); 402 - *len = 0; 403 - } else if (*len > 128 * 1024) { 404 - cifs_dbg(VFS, "data area larger than 128K: %d\n", *len); 393 + } else if (*off == 0) { 405 394 *len = 0; 406 395 } 407 396 408 397 /* return pointer to beginning of data area, ie offset from SMB start */ 409 - if ((*off != 0) && (*len != 0)) 398 + if (*off > 0 && *len > 0) 410 399 return (char *)shdr + *off; 411 - else 412 - return NULL; 400 + return NULL; 413 401 } 414 402 415 403 /*
+24 -16
fs/smb/client/smb2ops.c
··· 3003 3003 struct kvec *rsp_iov; 3004 3004 struct smb2_ioctl_rsp *ioctl_rsp; 3005 3005 struct reparse_data_buffer *reparse_buf; 3006 - u32 plen; 3006 + u32 off, count, len; 3007 3007 3008 3008 cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); 3009 3009 ··· 3084 3084 */ 3085 3085 if (rc == 0) { 3086 3086 /* See MS-FSCC 2.3.23 */ 3087 + off = le32_to_cpu(ioctl_rsp->OutputOffset); 3088 + count = le32_to_cpu(ioctl_rsp->OutputCount); 3089 + if (check_add_overflow(off, count, &len) || 3090 + len > rsp_iov[1].iov_len) { 3091 + cifs_tcon_dbg(VFS, "%s: invalid ioctl: off=%d count=%d\n", 3092 + __func__, off, count); 3093 + rc = -EIO; 3094 + goto query_rp_exit; 3095 + } 3087 3096 3088 - reparse_buf = (struct reparse_data_buffer *) 3089 - ((char *)ioctl_rsp + 3090 - le32_to_cpu(ioctl_rsp->OutputOffset)); 3091 - plen = le32_to_cpu(ioctl_rsp->OutputCount); 3092 - 3093 - if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) > 3094 - rsp_iov[1].iov_len) { 3095 - cifs_tcon_dbg(FYI, "srv returned invalid ioctl len: %d\n", 3096 - plen); 3097 + reparse_buf = (void *)((u8 *)ioctl_rsp + off); 3098 + len = sizeof(*reparse_buf); 3099 + if (count < len || 3100 + count < le16_to_cpu(reparse_buf->ReparseDataLength) + len) { 3101 + cifs_tcon_dbg(VFS, "%s: invalid ioctl: off=%d count=%d\n", 3102 + __func__, off, count); 3097 3103 rc = -EIO; 3098 3104 goto query_rp_exit; 3099 3105 } ··· 4949 4943 struct smb2_hdr *shdr; 4950 4944 unsigned int pdu_length = server->pdu_size; 4951 4945 unsigned int buf_size; 4946 + unsigned int next_cmd; 4952 4947 struct mid_q_entry *mid_entry; 4953 4948 int next_is_large; 4954 4949 char *next_buffer = NULL; ··· 4978 4971 next_is_large = server->large_buf; 4979 4972 one_more: 4980 4973 shdr = (struct smb2_hdr *)buf; 4981 - if (shdr->NextCommand) { 4974 + next_cmd = le32_to_cpu(shdr->NextCommand); 4975 + if (next_cmd) { 4976 + if (WARN_ON_ONCE(next_cmd > pdu_length)) 4977 + return -1; 4982 4978 if (next_is_large) 4983 4979 next_buffer = (char *)cifs_buf_get(); 4984 4980 else 4985 4981 next_buffer = (char *)cifs_small_buf_get(); 4986 - memcpy(next_buffer, 4987 - buf + le32_to_cpu(shdr->NextCommand), 4988 - pdu_length - le32_to_cpu(shdr->NextCommand)); 4982 + memcpy(next_buffer, buf + next_cmd, pdu_length - next_cmd); 4989 4983 } 4990 4984 4991 4985 mid_entry = smb2_find_mid(server, buf); ··· 5010 5002 else 5011 5003 ret = cifs_handle_standard(server, mid_entry); 5012 5004 5013 - if (ret == 0 && shdr->NextCommand) { 5014 - pdu_length -= le32_to_cpu(shdr->NextCommand); 5005 + if (ret == 0 && next_cmd) { 5006 + pdu_length -= next_cmd; 5015 5007 server->large_buf = next_is_large; 5016 5008 if (next_is_large) 5017 5009 server->bigbuf = buf = next_buffer;
+57 -38
fs/smb/client/smb2pdu.c
··· 2236 2236 posix->nlink, posix->mode, posix->reparse_tag); 2237 2237 } 2238 2238 2239 - void 2240 - smb2_parse_contexts(struct TCP_Server_Info *server, 2241 - struct smb2_create_rsp *rsp, 2242 - unsigned int *epoch, char *lease_key, __u8 *oplock, 2243 - struct smb2_file_all_info *buf, 2244 - struct create_posix_rsp *posix) 2239 + int smb2_parse_contexts(struct TCP_Server_Info *server, 2240 + struct kvec *rsp_iov, 2241 + unsigned int *epoch, 2242 + char *lease_key, __u8 *oplock, 2243 + struct smb2_file_all_info *buf, 2244 + struct create_posix_rsp *posix) 2245 2245 { 2246 - char *data_offset; 2246 + struct smb2_create_rsp *rsp = rsp_iov->iov_base; 2247 2247 struct create_context *cc; 2248 - unsigned int next; 2249 - unsigned int remaining; 2248 + size_t rem, off, len; 2249 + size_t doff, dlen; 2250 + size_t noff, nlen; 2250 2251 char *name; 2251 2252 static const char smb3_create_tag_posix[] = { 2252 2253 0x93, 0xAD, 0x25, 0x50, 0x9C, ··· 2256 2255 }; 2257 2256 2258 2257 *oplock = 0; 2259 - data_offset = (char *)rsp + le32_to_cpu(rsp->CreateContextsOffset); 2260 - remaining = le32_to_cpu(rsp->CreateContextsLength); 2261 - cc = (struct create_context *)data_offset; 2258 + 2259 + off = le32_to_cpu(rsp->CreateContextsOffset); 2260 + rem = le32_to_cpu(rsp->CreateContextsLength); 2261 + if (check_add_overflow(off, rem, &len) || len > rsp_iov->iov_len) 2262 + return -EINVAL; 2263 + cc = (struct create_context *)((u8 *)rsp + off); 2262 2264 2263 2265 /* Initialize inode number to 0 in case no valid data in qfid context */ 2264 2266 if (buf) 2265 2267 buf->IndexNumber = 0; 2266 2268 2267 - while (remaining >= sizeof(struct create_context)) { 2268 - name = le16_to_cpu(cc->NameOffset) + (char *)cc; 2269 - if (le16_to_cpu(cc->NameLength) == 4 && 2270 - strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4) == 0) 2271 - *oplock = server->ops->parse_lease_buf(cc, epoch, 2272 - lease_key); 2273 - else if (buf && (le16_to_cpu(cc->NameLength) == 4) && 2274 - strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4) == 0) 2275 - parse_query_id_ctxt(cc, buf); 2276 - else if ((le16_to_cpu(cc->NameLength) == 16)) { 2277 - if (posix && 2278 - memcmp(name, smb3_create_tag_posix, 16) == 0) 2279 - parse_posix_ctxt(cc, buf, posix); 2280 - } 2281 - /* else { 2282 - cifs_dbg(FYI, "Context not matched with len %d\n", 2283 - le16_to_cpu(cc->NameLength)); 2284 - cifs_dump_mem("Cctxt name: ", name, 4); 2285 - } */ 2269 + while (rem >= sizeof(*cc)) { 2270 + doff = le16_to_cpu(cc->DataOffset); 2271 + dlen = le32_to_cpu(cc->DataLength); 2272 + if (check_add_overflow(doff, dlen, &len) || len > rem) 2273 + return -EINVAL; 2286 2274 2287 - next = le32_to_cpu(cc->Next); 2288 - if (!next) 2275 + noff = le16_to_cpu(cc->NameOffset); 2276 + nlen = le16_to_cpu(cc->NameLength); 2277 + if (noff + nlen >= doff) 2278 + return -EINVAL; 2279 + 2280 + name = (char *)cc + noff; 2281 + switch (nlen) { 2282 + case 4: 2283 + if (!strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) { 2284 + *oplock = server->ops->parse_lease_buf(cc, epoch, 2285 + lease_key); 2286 + } else if (buf && 2287 + !strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4)) { 2288 + parse_query_id_ctxt(cc, buf); 2289 + } 2289 2290 break; 2290 - remaining -= next; 2291 - cc = (struct create_context *)((char *)cc + next); 2291 + case 16: 2292 + if (posix && !memcmp(name, smb3_create_tag_posix, 16)) 2293 + parse_posix_ctxt(cc, buf, posix); 2294 + break; 2295 + default: 2296 + cifs_dbg(FYI, "%s: unhandled context (nlen=%zu dlen=%zu)\n", 2297 + __func__, nlen, dlen); 2298 + if (IS_ENABLED(CONFIG_CIFS_DEBUG2)) 2299 + cifs_dump_mem("context data: ", cc, dlen); 2300 + break; 2301 + } 2302 + 2303 + off = le32_to_cpu(cc->Next); 2304 + if (!off) 2305 + break; 2306 + if (check_sub_overflow(rem, off, &rem)) 2307 + return -EINVAL; 2308 + cc = (struct create_context *)((u8 *)cc + off); 2292 2309 } 2293 2310 2294 2311 if (rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE) 2295 2312 *oplock = rsp->OplockLevel; 2296 2313 2297 - return; 2314 + return 0; 2298 2315 } 2299 2316 2300 2317 static int ··· 3143 3124 } 3144 3125 3145 3126 3146 - smb2_parse_contexts(server, rsp, &oparms->fid->epoch, 3147 - oparms->fid->lease_key, oplock, buf, posix); 3127 + rc = smb2_parse_contexts(server, &rsp_iov, &oparms->fid->epoch, 3128 + oparms->fid->lease_key, oplock, buf, posix); 3148 3129 creat_exit: 3149 3130 SMB2_open_free(&rqst); 3150 3131 free_rsp_buf(resp_buftype, rsp);
+7 -5
fs/smb/client/smb2proto.h
··· 251 251 252 252 extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, 253 253 enum securityEnum); 254 - extern void smb2_parse_contexts(struct TCP_Server_Info *server, 255 - struct smb2_create_rsp *rsp, 256 - unsigned int *epoch, char *lease_key, 257 - __u8 *oplock, struct smb2_file_all_info *buf, 258 - struct create_posix_rsp *posix); 254 + int smb2_parse_contexts(struct TCP_Server_Info *server, 255 + struct kvec *rsp_iov, 256 + unsigned int *epoch, 257 + char *lease_key, __u8 *oplock, 258 + struct smb2_file_all_info *buf, 259 + struct create_posix_rsp *posix); 260 + 259 261 extern int smb3_encryption_required(const struct cifs_tcon *tcon); 260 262 extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length, 261 263 struct kvec *iov, unsigned int min_buf_size);