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 smb3+

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
27c32b49 696e420b

+25 -6
+25 -6
fs/cifs/smb2transport.c
··· 408 408 int 409 409 smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) 410 410 { 411 - int rc = 0; 411 + int rc; 412 412 unsigned char smb3_signature[SMB2_CMACAES_SIZE]; 413 413 unsigned char *sigptr = smb3_signature; 414 414 struct kvec *iov = rqst->rq_iov; 415 415 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; 416 416 struct cifs_ses *ses; 417 + struct shash_desc *shash = &server->secmech.sdesccmacaes->shash; 418 + struct smb_rqst drqst; 417 419 418 420 ses = smb2_find_smb_ses(server, shdr->SessionId); 419 421 if (!ses) { ··· 427 425 memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); 428 426 429 427 rc = crypto_shash_setkey(server->secmech.cmacaes, 430 - ses->smb3signingkey, SMB2_CMACAES_SIZE); 431 - 428 + ses->smb3signingkey, SMB2_CMACAES_SIZE); 432 429 if (rc) { 433 430 cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__); 434 431 return rc; ··· 438 437 * so unlike smb2 case we do not have to check here if secmech are 439 438 * initialized 440 439 */ 441 - rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash); 440 + rc = crypto_shash_init(shash); 442 441 if (rc) { 443 442 cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__); 444 443 return rc; 445 444 } 446 445 447 - rc = __cifs_calc_signature(rqst, server, sigptr, 448 - &server->secmech.sdesccmacaes->shash); 446 + /* 447 + * For SMB2+, __cifs_calc_signature() expects to sign only the actual 448 + * data, that is, iov[0] should not contain a rfc1002 length. 449 + * 450 + * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to 451 + * __cifs_calc_signature(). 452 + */ 453 + drqst = *rqst; 454 + if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) { 455 + rc = crypto_shash_update(shash, iov[0].iov_base, 456 + iov[0].iov_len); 457 + if (rc) { 458 + cifs_dbg(VFS, "%s: Could not update with payload\n", 459 + __func__); 460 + return rc; 461 + } 462 + drqst.rq_iov++; 463 + drqst.rq_nvec--; 464 + } 449 465 466 + rc = __cifs_calc_signature(&drqst, server, sigptr, shash); 450 467 if (!rc) 451 468 memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); 452 469