@@ -1987,17 +1987,18 @@ parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *info,
1987
1987
posix -> nlink , posix -> mode , posix -> reparse_tag );
1988
1988
}
1989
1989
1990
- void
1991
- smb2_parse_contexts ( struct TCP_Server_Info * server ,
1992
- struct smb2_create_rsp * rsp ,
1993
- unsigned int * epoch , char * lease_key , __u8 * oplock ,
1994
- struct smb2_file_all_info * buf ,
1995
- struct create_posix_rsp * posix )
1990
+ int smb2_parse_contexts ( struct TCP_Server_Info * server ,
1991
+ struct kvec * rsp_iov ,
1992
+ unsigned int * epoch ,
1993
+ char * lease_key , __u8 * oplock ,
1994
+ struct smb2_file_all_info * buf ,
1995
+ struct create_posix_rsp * posix )
1996
1996
{
1997
- char * data_offset ;
1997
+ struct smb2_create_rsp * rsp = rsp_iov -> iov_base ;
1998
1998
struct create_context * cc ;
1999
- unsigned int next ;
2000
- unsigned int remaining ;
1999
+ size_t rem , off , len ;
2000
+ size_t doff , dlen ;
2001
+ size_t noff , nlen ;
2001
2002
char * name ;
2002
2003
static const char smb3_create_tag_posix [] = {
2003
2004
0x93 , 0xAD , 0x25 , 0x50 , 0x9C ,
@@ -2006,45 +2007,63 @@ smb2_parse_contexts(struct TCP_Server_Info *server,
2006
2007
};
2007
2008
2008
2009
* oplock = 0 ;
2009
- data_offset = (char * )rsp + le32_to_cpu (rsp -> CreateContextsOffset );
2010
- remaining = le32_to_cpu (rsp -> CreateContextsLength );
2011
- cc = (struct create_context * )data_offset ;
2010
+
2011
+ off = le32_to_cpu (rsp -> CreateContextsOffset );
2012
+ rem = le32_to_cpu (rsp -> CreateContextsLength );
2013
+ if (check_add_overflow (off , rem , & len ) || len > rsp_iov -> iov_len )
2014
+ return - EINVAL ;
2015
+ cc = (struct create_context * )((u8 * )rsp + off );
2012
2016
2013
2017
/* Initialize inode number to 0 in case no valid data in qfid context */
2014
2018
if (buf )
2015
2019
buf -> IndexNumber = 0 ;
2016
2020
2017
- while (remaining >= sizeof (struct create_context )) {
2018
- name = le16_to_cpu (cc -> NameOffset ) + (char * )cc ;
2019
- if (le16_to_cpu (cc -> NameLength ) == 4 &&
2020
- strncmp (name , SMB2_CREATE_REQUEST_LEASE , 4 ) == 0 )
2021
- * oplock = server -> ops -> parse_lease_buf (cc , epoch ,
2022
- lease_key );
2023
- else if (buf && (le16_to_cpu (cc -> NameLength ) == 4 ) &&
2024
- strncmp (name , SMB2_CREATE_QUERY_ON_DISK_ID , 4 ) == 0 )
2025
- parse_query_id_ctxt (cc , buf );
2026
- else if ((le16_to_cpu (cc -> NameLength ) == 16 )) {
2027
- if (posix &&
2028
- memcmp (name , smb3_create_tag_posix , 16 ) == 0 )
2021
+ while (rem >= sizeof (* cc )) {
2022
+ doff = le16_to_cpu (cc -> DataOffset );
2023
+ dlen = le32_to_cpu (cc -> DataLength );
2024
+ if (check_add_overflow (doff , dlen , & len ) || len > rem )
2025
+ return - EINVAL ;
2026
+
2027
+ noff = le16_to_cpu (cc -> NameOffset );
2028
+ nlen = le16_to_cpu (cc -> NameLength );
2029
+ if (noff + nlen >= doff )
2030
+ return - EINVAL ;
2031
+
2032
+ name = (char * )cc + noff ;
2033
+ switch (nlen ) {
2034
+ case 4 :
2035
+ if (!strncmp (name , SMB2_CREATE_REQUEST_LEASE , 4 )) {
2036
+ * oplock = server -> ops -> parse_lease_buf (cc , epoch ,
2037
+ lease_key );
2038
+ } else if (buf &&
2039
+ !strncmp (name , SMB2_CREATE_QUERY_ON_DISK_ID , 4 )) {
2040
+ parse_query_id_ctxt (cc , buf );
2041
+ }
2042
+ break ;
2043
+ case 16 :
2044
+ if (posix && !memcmp (name , smb3_create_tag_posix , 16 ))
2029
2045
parse_posix_ctxt (cc , buf , posix );
2046
+ break ;
2047
+ default :
2048
+ cifs_dbg (FYI , "%s: unhandled context (nlen=%zu dlen=%zu)\n" ,
2049
+ __func__ , nlen , dlen );
2050
+ if (IS_ENABLED (CONFIG_CIFS_DEBUG2 ))
2051
+ cifs_dump_mem ("context data: " , cc , dlen );
2052
+ break ;
2030
2053
}
2031
- /* else {
2032
- cifs_dbg(FYI, "Context not matched with len %d\n",
2033
- le16_to_cpu(cc->NameLength));
2034
- cifs_dump_mem("Cctxt name: ", name, 4);
2035
- } */
2036
-
2037
- next = le32_to_cpu (cc -> Next );
2038
- if (!next )
2054
+
2055
+ off = le32_to_cpu (cc -> Next );
2056
+ if (!off )
2039
2057
break ;
2040
- remaining -= next ;
2041
- cc = (struct create_context * )((char * )cc + next );
2058
+ if (check_sub_overflow (rem , off , & rem ))
2059
+ return - EINVAL ;
2060
+ cc = (struct create_context * )((u8 * )cc + off );
2042
2061
}
2043
2062
2044
2063
if (rsp -> OplockLevel != SMB2_OPLOCK_LEVEL_LEASE )
2045
2064
* oplock = rsp -> OplockLevel ;
2046
2065
2047
- return ;
2066
+ return 0 ;
2048
2067
}
2049
2068
2050
2069
static int
@@ -2911,8 +2930,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
2911
2930
}
2912
2931
2913
2932
2914
- smb2_parse_contexts (server , rsp , & oparms -> fid -> epoch ,
2915
- oparms -> fid -> lease_key , oplock , buf , posix );
2933
+ rc = smb2_parse_contexts (server , & rsp_iov , & oparms -> fid -> epoch ,
2934
+ oparms -> fid -> lease_key , oplock , buf , posix );
2916
2935
creat_exit :
2917
2936
SMB2_open_free (& rqst );
2918
2937
free_rsp_buf (resp_buftype , rsp );
0 commit comments