@@ -2236,17 +2236,18 @@ parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *info,
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 ,
@@ -2255,45 +2256,63 @@ smb2_parse_contexts(struct TCP_Server_Info *server,
2255
2256
};
2256
2257
2257
2258
* oplock = 0 ;
2258
- data_offset = (char * )rsp + le32_to_cpu (rsp -> CreateContextsOffset );
2259
- remaining = le32_to_cpu (rsp -> CreateContextsLength );
2260
- cc = (struct create_context * )data_offset ;
2259
+
2260
+ off = le32_to_cpu (rsp -> CreateContextsOffset );
2261
+ rem = le32_to_cpu (rsp -> CreateContextsLength );
2262
+ if (check_add_overflow (off , rem , & len ) || len > rsp_iov -> iov_len )
2263
+ return - EINVAL ;
2264
+ cc = (struct create_context * )((u8 * )rsp + off );
2261
2265
2262
2266
/* Initialize inode number to 0 in case no valid data in qfid context */
2263
2267
if (buf )
2264
2268
buf -> IndexNumber = 0 ;
2265
2269
2266
- while (remaining >= sizeof (struct create_context )) {
2267
- name = le16_to_cpu (cc -> NameOffset ) + (char * )cc ;
2268
- if (le16_to_cpu (cc -> NameLength ) == 4 &&
2269
- strncmp (name , SMB2_CREATE_REQUEST_LEASE , 4 ) == 0 )
2270
- * oplock = server -> ops -> parse_lease_buf (cc , epoch ,
2271
- lease_key );
2272
- else if (buf && (le16_to_cpu (cc -> NameLength ) == 4 ) &&
2273
- strncmp (name , SMB2_CREATE_QUERY_ON_DISK_ID , 4 ) == 0 )
2274
- parse_query_id_ctxt (cc , buf );
2275
- else if ((le16_to_cpu (cc -> NameLength ) == 16 )) {
2276
- if (posix &&
2277
- memcmp (name , smb3_create_tag_posix , 16 ) == 0 )
2270
+ while (rem >= sizeof (* cc )) {
2271
+ doff = le16_to_cpu (cc -> DataOffset );
2272
+ dlen = le32_to_cpu (cc -> DataLength );
2273
+ if (check_add_overflow (doff , dlen , & len ) || len > rem )
2274
+ return - EINVAL ;
2275
+
2276
+ noff = le16_to_cpu (cc -> NameOffset );
2277
+ nlen = le16_to_cpu (cc -> NameLength );
2278
+ if (noff + nlen >= doff )
2279
+ return - EINVAL ;
2280
+
2281
+ name = (char * )cc + noff ;
2282
+ switch (nlen ) {
2283
+ case 4 :
2284
+ if (!strncmp (name , SMB2_CREATE_REQUEST_LEASE , 4 )) {
2285
+ * oplock = server -> ops -> parse_lease_buf (cc , epoch ,
2286
+ lease_key );
2287
+ } else if (buf &&
2288
+ !strncmp (name , SMB2_CREATE_QUERY_ON_DISK_ID , 4 )) {
2289
+ parse_query_id_ctxt (cc , buf );
2290
+ }
2291
+ break ;
2292
+ case 16 :
2293
+ if (posix && !memcmp (name , smb3_create_tag_posix , 16 ))
2278
2294
parse_posix_ctxt (cc , buf , posix );
2295
+ break ;
2296
+ default :
2297
+ cifs_dbg (FYI , "%s: unhandled context (nlen=%zu dlen=%zu)\n" ,
2298
+ __func__ , nlen , dlen );
2299
+ if (IS_ENABLED (CONFIG_CIFS_DEBUG2 ))
2300
+ cifs_dump_mem ("context data: " , cc , dlen );
2301
+ break ;
2279
2302
}
2280
- /* else {
2281
- cifs_dbg(FYI, "Context not matched with len %d\n",
2282
- le16_to_cpu(cc->NameLength));
2283
- cifs_dump_mem("Cctxt name: ", name, 4);
2284
- } */
2285
-
2286
- next = le32_to_cpu (cc -> Next );
2287
- if (!next )
2303
+
2304
+ off = le32_to_cpu (cc -> Next );
2305
+ if (!off )
2288
2306
break ;
2289
- remaining -= next ;
2290
- cc = (struct create_context * )((char * )cc + next );
2307
+ if (check_sub_overflow (rem , off , & rem ))
2308
+ return - EINVAL ;
2309
+ cc = (struct create_context * )((u8 * )cc + off );
2291
2310
}
2292
2311
2293
2312
if (rsp -> OplockLevel != SMB2_OPLOCK_LEVEL_LEASE )
2294
2313
* oplock = rsp -> OplockLevel ;
2295
2314
2296
- return ;
2315
+ return 0 ;
2297
2316
}
2298
2317
2299
2318
static int
@@ -3124,8 +3143,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
3124
3143
}
3125
3144
3126
3145
3127
- smb2_parse_contexts (server , rsp , & oparms -> fid -> epoch ,
3128
- oparms -> fid -> lease_key , oplock , buf , posix );
3146
+ rc = smb2_parse_contexts (server , & rsp_iov , & oparms -> fid -> epoch ,
3147
+ oparms -> fid -> lease_key , oplock , buf , posix );
3129
3148
creat_exit :
3130
3149
SMB2_open_free (& rqst );
3131
3150
free_rsp_buf (resp_buftype , rsp );
0 commit comments