Looks correct. Tested with -o vers=1.0, -o vers=2.0, and -o vers=2.1. Will test using mount option vers=3.0 as soon as I find a server. Reviewed-by: Shirish Pargaonkar <shirishpargaonkar@xxxxxxxxx> Tested-by: Shirish Pargaonkar <shirishpargaonkar@xxxxxxxxx> On Sat, Apr 9, 2016 at 3:50 PM, Al Viro <viro@xxxxxxxxxxxxxxxxxx> wrote: > three practically identical copies... > > Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx> > --- > fs/cifs/cifsencrypt.c | 97 ++++++++++++++++++++++++------------------- > fs/cifs/cifsproto.h | 3 ++ > fs/cifs/smb2transport.c | 107 +++++------------------------------------------- > 3 files changed, 67 insertions(+), 140 deletions(-) > > diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c > index 4897dac..6aeb8d4 100644 > --- a/fs/cifs/cifsencrypt.c > +++ b/fs/cifs/cifsencrypt.c > @@ -66,45 +66,15 @@ cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server) > return 0; > } > > -/* > - * Calculate and return the CIFS signature based on the mac key and SMB PDU. > - * The 16 byte signature must be allocated by the caller. Note we only use the > - * 1st eight bytes and that the smb header signature field on input contains > - * the sequence number before this function is called. Also, this function > - * should be called with the server->srv_mutex held. > - */ > -static int cifs_calc_signature(struct smb_rqst *rqst, > - struct TCP_Server_Info *server, char *signature) > +int __cifs_calc_signature(struct smb_rqst *rqst, > + struct TCP_Server_Info *server, char *signature, > + struct shash_desc *shash) > { > int i; > int rc; > struct kvec *iov = rqst->rq_iov; > int n_vec = rqst->rq_nvec; > > - if (iov == NULL || signature == NULL || server == NULL) > - return -EINVAL; > - > - if (!server->secmech.sdescmd5) { > - rc = cifs_crypto_shash_md5_allocate(server); > - if (rc) { > - cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__); > - return -1; > - } > - } > - > - rc = crypto_shash_init(&server->secmech.sdescmd5->shash); > - if (rc) { > - cifs_dbg(VFS, "%s: Could not init md5\n", __func__); > - return rc; > - } > - > - rc = crypto_shash_update(&server->secmech.sdescmd5->shash, > - server->session_key.response, server->session_key.len); > - if (rc) { > - cifs_dbg(VFS, "%s: Could not update with response\n", __func__); > - return rc; > - } > - > for (i = 0; i < n_vec; i++) { > if (iov[i].iov_len == 0) > continue; > @@ -117,12 +87,10 @@ static int cifs_calc_signature(struct smb_rqst *rqst, > if (i == 0) { > if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ > break; /* nothing to sign or corrupt header */ > - rc = > - crypto_shash_update(&server->secmech.sdescmd5->shash, > + rc = crypto_shash_update(shash, > iov[i].iov_base + 4, iov[i].iov_len - 4); > } else { > - rc = > - crypto_shash_update(&server->secmech.sdescmd5->shash, > + rc = crypto_shash_update(shash, > iov[i].iov_base, iov[i].iov_len); > } > if (rc) { > @@ -134,21 +102,64 @@ static int cifs_calc_signature(struct smb_rqst *rqst, > > /* now hash over the rq_pages array */ > for (i = 0; i < rqst->rq_npages; i++) { > - struct kvec p_iov; > + void *kaddr = kmap(rqst->rq_pages[i]); > + size_t len = rqst->rq_pagesz; > + > + if (i == rqst->rq_npages - 1) > + len = rqst->rq_tailsz; > + > + crypto_shash_update(shash, kaddr, len); > > - cifs_rqst_page_to_kvec(rqst, i, &p_iov); > - crypto_shash_update(&server->secmech.sdescmd5->shash, > - p_iov.iov_base, p_iov.iov_len); > kunmap(rqst->rq_pages[i]); > } > > - rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); > + rc = crypto_shash_final(shash, signature); > if (rc) > - cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); > + cifs_dbg(VFS, "%s: Could not generate hash\n", __func__); > > return rc; > } > > +/* > + * Calculate and return the CIFS signature based on the mac key and SMB PDU. > + * The 16 byte signature must be allocated by the caller. Note we only use the > + * 1st eight bytes and that the smb header signature field on input contains > + * the sequence number before this function is called. Also, this function > + * should be called with the server->srv_mutex held. > + */ > +static int cifs_calc_signature(struct smb_rqst *rqst, > + struct TCP_Server_Info *server, char *signature) > +{ > + int rc; > + > + if (!rqst->rq_iov || !signature || !server) > + return -EINVAL; > + > + if (!server->secmech.sdescmd5) { > + rc = cifs_crypto_shash_md5_allocate(server); > + if (rc) { > + cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__); > + return -1; > + } > + } > + > + rc = crypto_shash_init(&server->secmech.sdescmd5->shash); > + if (rc) { > + cifs_dbg(VFS, "%s: Could not init md5\n", __func__); > + return rc; > + } > + > + rc = crypto_shash_update(&server->secmech.sdescmd5->shash, > + server->session_key.response, server->session_key.len); > + if (rc) { > + cifs_dbg(VFS, "%s: Could not update with response\n", __func__); > + return rc; > + } > + > + return __cifs_calc_signature(rqst, server, signature, > + &server->secmech.sdescmd5->shash); > +} > + > /* must be called with server->srv_mutex held */ > int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server, > __u32 *pexpected_response_sequence_number) > diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h > index eed7ff5..d9b4f44 100644 > --- a/fs/cifs/cifsproto.h > +++ b/fs/cifs/cifsproto.h > @@ -512,4 +512,7 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, > struct cifs_sb_info *cifs_sb, > const unsigned char *path, char *pbuf, > unsigned int *pbytes_written); > +int __cifs_calc_signature(struct smb_rqst *rqst, > + struct TCP_Server_Info *server, char *signature, > + struct shash_desc *shash); > #endif /* _CIFSPROTO_H */ > diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c > index 8732a43..bc9a7b6 100644 > --- a/fs/cifs/smb2transport.c > +++ b/fs/cifs/smb2transport.c > @@ -135,11 +135,10 @@ smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server) > int > smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) > { > - int i, rc; > + int rc; > unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; > unsigned char *sigptr = smb2_signature; > struct kvec *iov = rqst->rq_iov; > - int n_vec = rqst->rq_nvec; > struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; > struct cifs_ses *ses; > > @@ -171,53 +170,11 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) > return rc; > } > > - for (i = 0; i < n_vec; i++) { > - if (iov[i].iov_len == 0) > - continue; > - if (iov[i].iov_base == NULL) { > - cifs_dbg(VFS, "null iovec entry\n"); > - return -EIO; > - } > - /* > - * The first entry includes a length field (which does not get > - * signed that occupies the first 4 bytes before the header). > - */ > - if (i == 0) { > - if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ > - break; /* nothing to sign or corrupt header */ > - rc = > - crypto_shash_update( > - &server->secmech.sdeschmacsha256->shash, > - iov[i].iov_base + 4, iov[i].iov_len - 4); > - } else { > - rc = > - crypto_shash_update( > - &server->secmech.sdeschmacsha256->shash, > - iov[i].iov_base, iov[i].iov_len); > - } > - if (rc) { > - cifs_dbg(VFS, "%s: Could not update with payload\n", > - __func__); > - return rc; > - } > - } > - > - /* now hash over the rq_pages array */ > - for (i = 0; i < rqst->rq_npages; i++) { > - struct kvec p_iov; > - > - cifs_rqst_page_to_kvec(rqst, i, &p_iov); > - crypto_shash_update(&server->secmech.sdeschmacsha256->shash, > - p_iov.iov_base, p_iov.iov_len); > - kunmap(rqst->rq_pages[i]); > - } > - > - rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash, > - sigptr); > - if (rc) > - cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); > + rc = __cifs_calc_signature(rqst, server, sigptr, > + &server->secmech.sdeschmacsha256->shash); > > - memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE); > + if (!rc) > + memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE); > > return rc; > } > @@ -395,12 +352,10 @@ generate_smb311signingkey(struct cifs_ses *ses) > int > smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) > { > - int i; > int rc = 0; > unsigned char smb3_signature[SMB2_CMACAES_SIZE]; > unsigned char *sigptr = smb3_signature; > struct kvec *iov = rqst->rq_iov; > - int n_vec = rqst->rq_nvec; > struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; > struct cifs_ses *ses; > > @@ -431,54 +386,12 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) > cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__); > return rc; > } > + > + rc = __cifs_calc_signature(rqst, server, sigptr, > + &server->secmech.sdesccmacaes->shash); > > - for (i = 0; i < n_vec; i++) { > - if (iov[i].iov_len == 0) > - continue; > - if (iov[i].iov_base == NULL) { > - cifs_dbg(VFS, "null iovec entry"); > - return -EIO; > - } > - /* > - * The first entry includes a length field (which does not get > - * signed that occupies the first 4 bytes before the header). > - */ > - if (i == 0) { > - if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ > - break; /* nothing to sign or corrupt header */ > - rc = > - crypto_shash_update( > - &server->secmech.sdesccmacaes->shash, > - iov[i].iov_base + 4, iov[i].iov_len - 4); > - } else { > - rc = > - crypto_shash_update( > - &server->secmech.sdesccmacaes->shash, > - iov[i].iov_base, iov[i].iov_len); > - } > - if (rc) { > - cifs_dbg(VFS, "%s: Couldn't update cmac aes with payload\n", > - __func__); > - return rc; > - } > - } > - > - /* now hash over the rq_pages array */ > - for (i = 0; i < rqst->rq_npages; i++) { > - struct kvec p_iov; > - > - cifs_rqst_page_to_kvec(rqst, i, &p_iov); > - crypto_shash_update(&server->secmech.sdesccmacaes->shash, > - p_iov.iov_base, p_iov.iov_len); > - kunmap(rqst->rq_pages[i]); > - } > - > - rc = crypto_shash_final(&server->secmech.sdesccmacaes->shash, > - sigptr); > - if (rc) > - cifs_dbg(VFS, "%s: Could not generate cmac aes\n", __func__); > - > - memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE); > + if (!rc) > + memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE); > > return rc; > } > -- > 2.8.0.rc3 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html