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

cifs: Fix validation of signed data in smb2

Fixes: c713c8770fa5 ("cifs: push rfc1002 generation down the stack")

We failed to validate signed data returned by the server because
__cifs_calc_signature() now expects to sign the actual data in iov but
we were also passing down the rfc1002 length.

Fix smb3_calc_signature() to calculate signature of rfc1002 length prior
to passing only the actual data iov[1-N] to __cifs_calc_signature(). In
addition, there are a few cases where no rfc1002 length is passed so we
make sure there's one (iov_len == 4).

Signed-off-by: Paulo Alcantara <palcantara@suse.de>
Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by

Paulo Alcantara and committed by
Steve French
8de8c460 27c32b49

+24 -4
+24 -4
fs/cifs/smb2transport.c
··· 173 173 struct kvec *iov = rqst->rq_iov; 174 174 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; 175 175 struct cifs_ses *ses; 176 + struct shash_desc *shash = &server->secmech.sdeschmacsha256->shash; 177 + struct smb_rqst drqst; 176 178 177 179 ses = smb2_find_smb_ses(server, shdr->SessionId); 178 180 if (!ses) { ··· 192 190 } 193 191 194 192 rc = crypto_shash_setkey(server->secmech.hmacsha256, 195 - ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); 193 + ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); 196 194 if (rc) { 197 195 cifs_dbg(VFS, "%s: Could not update with response\n", __func__); 198 196 return rc; 199 197 } 200 198 201 - rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash); 199 + rc = crypto_shash_init(shash); 202 200 if (rc) { 203 201 cifs_dbg(VFS, "%s: Could not init sha256", __func__); 204 202 return rc; 205 203 } 206 204 207 - rc = __cifs_calc_signature(rqst, server, sigptr, 208 - &server->secmech.sdeschmacsha256->shash); 205 + /* 206 + * For SMB2+, __cifs_calc_signature() expects to sign only the actual 207 + * data, that is, iov[0] should not contain a rfc1002 length. 208 + * 209 + * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to 210 + * __cifs_calc_signature(). 211 + */ 212 + drqst = *rqst; 213 + if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) { 214 + rc = crypto_shash_update(shash, iov[0].iov_base, 215 + iov[0].iov_len); 216 + if (rc) { 217 + cifs_dbg(VFS, "%s: Could not update with payload\n", 218 + __func__); 219 + return rc; 220 + } 221 + drqst.rq_iov++; 222 + drqst.rq_nvec--; 223 + } 209 224 225 + rc = __cifs_calc_signature(&drqst, server, sigptr, shash); 210 226 if (!rc) 211 227 memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); 212 228