From patchwork Thu Sep 29 17:56:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Enzo Matsumiya X-Patchwork-Id: 12994517 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AC14FC433FE for ; Thu, 29 Sep 2022 17:57:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234707AbiI2R5R (ORCPT ); Thu, 29 Sep 2022 13:57:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60000 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235022AbiI2R5P (ORCPT ); Thu, 29 Sep 2022 13:57:15 -0400 Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6D5E73ED6D for ; Thu, 29 Sep 2022 10:57:10 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 06E711F8E0; Thu, 29 Sep 2022 17:57:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1664474229; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=FE8faHRIDTsKTZSDrOt6GsQ+qIQAPE69Tn+Ko8mVHPI=; b=qL0kgkOY6IPC2HeTVSRE/+muj5iucONw/OYiLKX8wSKx+BuauL8kOlMigg4g+7bsmnbKNa aEj47RlBIV7KV0VV7xdJ7FuvzsNAqMq9bdJ+XyRTX/K/rd50B44u37NaRtg8CGMm8CISIV PLQ/zDB79EN4J7tCDMlaTC8ZAfKonjA= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1664474229; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=FE8faHRIDTsKTZSDrOt6GsQ+qIQAPE69Tn+Ko8mVHPI=; b=d7fop/AcVQOxUWAtGmSldc5jfYsi1J058RHRUO2Gzw/V5mGFel6Dm5eRWMZ5mgBKqSiPOx 9sT0HnOYsMs1mECQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 7C2551348E; Thu, 29 Sep 2022 17:57:08 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id JKTND3TcNWPYFQAAMHmgww (envelope-from ); Thu, 29 Sep 2022 17:57:08 +0000 From: Enzo Matsumiya To: linux-cifs@vger.kernel.org Cc: smfrench@gmail.com, pc@cjr.nz, ronniesahlberg@gmail.com, nspmangalore@gmail.com, tom@talpey.com, metze@samba.org Subject: [PATCH v4 3/8] cifs: allocate ephemeral secmechs only on demand Date: Thu, 29 Sep 2022 14:56:52 -0300 Message-Id: <20220929175655.6906-1-ematsumiya@suse.de> X-Mailer: git-send-email 2.35.3 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Reduce memory usage a bit by removing some secmechs as they are only briefly used on session setup, and not needed anymore throughout a server's object lifetime. Allocate and free them on demand now. HMAC-SHA256 is an exception because it's used both for SMB2 signatures as for generating SMB3+ signatures, so allocate/free a dedicated one in generate_key() too to keep things separated. smb3*_crypto_shash_allocate functions are removed since we're now calling cifs_alloc_hash() directly and especifically. Also move smb3_crypto_aead_allocate() call to generate_key(), right after when crypto keys are generated. Signed-off-by: Enzo Matsumiya --- v4: fix checkpatch errors (thanks to Steve) fs/cifs/cifsencrypt.c | 73 +++++++++++++++--------------------- fs/cifs/cifsglob.h | 2 - fs/cifs/misc.c | 2 +- fs/cifs/sess.c | 12 ------ fs/cifs/smb2misc.c | 18 ++++----- fs/cifs/smb2ops.c | 8 ++-- fs/cifs/smb2pdu.c | 19 ++++++++++ fs/cifs/smb2proto.h | 1 - fs/cifs/smb2transport.c | 83 ++++++++++++----------------------------- 9 files changed, 86 insertions(+), 132 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 30ece0c58c71..ed25ac811f05 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -401,7 +401,8 @@ find_timestamp(struct cifs_ses *ses) } static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, - const struct nls_table *nls_cp) + const struct nls_table *nls_cp, + struct shash_desc *hmacmd5) { int rc = 0; int len; @@ -410,7 +411,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, wchar_t *domain; wchar_t *server; - if (!ses->server->secmech.hmacmd5) { + if (!hmacmd5) { cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__); return -1; } @@ -418,14 +419,13 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, /* calculate md4 hash of password */ E_md4hash(ses->password, nt_hash, nls_cp); - rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm, nt_hash, - CIFS_NTHASH_SIZE); + rc = crypto_shash_setkey(hmacmd5->tfm, nt_hash, CIFS_NTHASH_SIZE); if (rc) { cifs_dbg(VFS, "%s: Could not set NT Hash as a key\n", __func__); return rc; } - rc = crypto_shash_init(ses->server->secmech.hmacmd5); + rc = crypto_shash_init(hmacmd5); if (rc) { cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__); return rc; @@ -446,8 +446,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, memset(user, '\0', 2); } - rc = crypto_shash_update(ses->server->secmech.hmacmd5, - (char *)user, 2 * len); + rc = crypto_shash_update(hmacmd5, (char *)user, 2 * len); kfree(user); if (rc) { cifs_dbg(VFS, "%s: Could not update with user\n", __func__); @@ -465,9 +464,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, } len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len, nls_cp); - rc = - crypto_shash_update(ses->server->secmech.hmacmd5, - (char *)domain, 2 * len); + rc = crypto_shash_update(hmacmd5, (char *)domain, 2 * len); kfree(domain); if (rc) { cifs_dbg(VFS, "%s: Could not update with domain\n", @@ -485,9 +482,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, } len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len, nls_cp); - rc = - crypto_shash_update(ses->server->secmech.hmacmd5, - (char *)server, 2 * len); + rc = crypto_shash_update(hmacmd5, (char *)server, 2 * len); kfree(server); if (rc) { cifs_dbg(VFS, "%s: Could not update with server\n", @@ -496,8 +491,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, } } - rc = crypto_shash_final(ses->server->secmech.hmacmd5, - ntlmv2_hash); + rc = crypto_shash_final(hmacmd5, ntlmv2_hash); if (rc) cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); @@ -505,7 +499,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, } static int -CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash) +CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash, + struct shash_desc *hmacmd5) { int rc; struct ntlmv2_resp *ntlmv2 = (struct ntlmv2_resp *) @@ -516,20 +511,19 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash) hash_len = ses->auth_key.len - (CIFS_SESS_KEY_SIZE + offsetof(struct ntlmv2_resp, challenge.key[0])); - if (!ses->server->secmech.hmacmd5) { + if (!hmacmd5) { cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__); return -1; } - rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm, - ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); + rc = crypto_shash_setkey(hmacmd5->tfm, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); if (rc) { cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n", __func__); return rc; } - rc = crypto_shash_init(ses->server->secmech.hmacmd5); + rc = crypto_shash_init(hmacmd5); if (rc) { cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__); return rc; @@ -541,16 +535,14 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash) else memcpy(ntlmv2->challenge.key, ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); - rc = crypto_shash_update(ses->server->secmech.hmacmd5, - ntlmv2->challenge.key, hash_len); + rc = crypto_shash_update(hmacmd5, ntlmv2->challenge.key, hash_len); if (rc) { cifs_dbg(VFS, "%s: Could not update with response\n", __func__); return rc; } /* Note that the MD5 digest over writes anon.challenge_key.key */ - rc = crypto_shash_final(ses->server->secmech.hmacmd5, - ntlmv2->ntlmv2_hash); + rc = crypto_shash_final(hmacmd5, ntlmv2->ntlmv2_hash); if (rc) cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); @@ -567,6 +559,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) char ntlmv2_hash[16]; unsigned char *tiblob = NULL; /* target info blob */ __le64 rsp_timestamp; + struct shash_desc *hmacmd5 = NULL; if (nls_cp == NULL) { cifs_dbg(VFS, "%s called with nls_cp==NULL\n", __func__); @@ -625,53 +618,51 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) cifs_server_lock(ses->server); - rc = cifs_alloc_hash("hmac(md5)", &ses->server->secmech.hmacmd5); + rc = cifs_alloc_hash("hmac(md5)", &hmacmd5); if (rc) { goto unlock; } /* calculate ntlmv2_hash */ - rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp); + rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp, hmacmd5); if (rc) { cifs_dbg(VFS, "Could not get v2 hash rc %d\n", rc); - goto unlock; + goto out_free_hash; } /* calculate first part of the client response (CR1) */ - rc = CalcNTLMv2_response(ses, ntlmv2_hash); + rc = CalcNTLMv2_response(ses, ntlmv2_hash, hmacmd5); if (rc) { cifs_dbg(VFS, "Could not calculate CR1 rc: %d\n", rc); - goto unlock; + goto out_free_hash; } /* now calculate the session key for NTLMv2 */ - rc = crypto_shash_setkey(ses->server->secmech.hmacmd5->tfm, - ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); + rc = crypto_shash_setkey(hmacmd5->tfm, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); if (rc) { cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n", __func__); - goto unlock; + goto out_free_hash; } - rc = crypto_shash_init(ses->server->secmech.hmacmd5); + rc = crypto_shash_init(hmacmd5); if (rc) { cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__); - goto unlock; + goto out_free_hash; } - rc = crypto_shash_update(ses->server->secmech.hmacmd5, - ntlmv2->ntlmv2_hash, - CIFS_HMAC_MD5_HASH_SIZE); + rc = crypto_shash_update(hmacmd5, ntlmv2->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); if (rc) { cifs_dbg(VFS, "%s: Could not update with response\n", __func__); - goto unlock; + goto out_free_hash; } - rc = crypto_shash_final(ses->server->secmech.hmacmd5, - ses->auth_key.response); + rc = crypto_shash_final(hmacmd5, ses->auth_key.response); if (rc) cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); +out_free_hash: + cifs_free_hash(&hmacmd5); unlock: cifs_server_unlock(ses->server); setup_ntlmv2_rsp_ret: @@ -717,8 +708,6 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server) cifs_free_hash(&server->secmech.aes_cmac); cifs_free_hash(&server->secmech.hmacsha256); cifs_free_hash(&server->secmech.md5); - cifs_free_hash(&server->secmech.sha512); - cifs_free_hash(&server->secmech.hmacmd5); if (server->secmech.enc) { crypto_free_aead(server->secmech.enc); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index ea76f4d7ef62..5da71d946012 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -155,10 +155,8 @@ struct session_key { /* crypto hashing related structure/fields, not specific to a sec mech */ struct cifs_secmech { - struct shash_desc *hmacmd5; /* hmacmd5 hash function, for NTLMv2/CR1 hashes */ struct shash_desc *md5; /* md5 hash function, for CIFS/SMB1 signatures */ struct shash_desc *hmacsha256; /* hmac-sha256 hash function, for SMB2 signatures */ - struct shash_desc *sha512; /* sha512 hash function, for SMB3.1.1 preauth hash */ struct shash_desc *aes_cmac; /* block-cipher based MAC function, for SMB3 signatures */ struct crypto_aead *enc; /* smb3 encryption AEAD TFM (AES-CCM and AES-GCM) */ diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 535dbe6ff994..c7eade06e2de 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -1093,7 +1093,7 @@ cifs_alloc_hash(const char *name, struct shash_desc **sdesc) return rc; } - *sdesc = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(alg), GFP_KERNEL); + *sdesc = kzalloc(sizeof(struct shash_desc) + crypto_shash_descsize(alg), GFP_KERNEL); if (*sdesc == NULL) { cifs_dbg(VFS, "no memory left to allocate shash TFM '%s'\n", name); crypto_free_shash(alg); diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 3af3b05b6c74..d59dec7a2a55 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -454,18 +454,6 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, spin_unlock(&ses->chan_lock); mutex_lock(&ses->session_mutex); - /* - * We need to allocate the server crypto now as we will need - * to sign packets before we generate the channel signing key - * (we sign with the session key) - */ - rc = smb311_crypto_shash_allocate(chan->server); - if (rc) { - cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); - mutex_unlock(&ses->session_mutex); - goto out; - } - rc = cifs_negotiate_protocol(xid, ses, chan->server); if (!rc) rc = cifs_setup_session(xid, ses, chan->server, cifs_sb->local_nls); diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 7db5c09ecceb..39a9fc60eb9e 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -897,22 +897,21 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server, return 0; ok: - rc = smb311_crypto_shash_allocate(server); + rc = cifs_alloc_hash("sha512", &sha512); if (rc) return rc; - sha512 = server->secmech.sha512; rc = crypto_shash_init(sha512); if (rc) { cifs_dbg(VFS, "%s: Could not init sha512 shash\n", __func__); - return rc; + goto out_free_hash; } rc = crypto_shash_update(sha512, ses->preauth_sha_hash, SMB2_PREAUTH_HASH_SIZE); if (rc) { cifs_dbg(VFS, "%s: Could not update sha512 shash\n", __func__); - return rc; + goto out_free_hash; } for (i = 0; i < nvec; i++) { @@ -920,16 +919,15 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server, if (rc) { cifs_dbg(VFS, "%s: Could not update sha512 shash\n", __func__); - return rc; + goto out_free_hash; } } rc = crypto_shash_final(sha512, ses->preauth_sha_hash); - if (rc) { + if (rc) cifs_dbg(VFS, "%s: Could not finalize sha512 shash\n", __func__); - return rc; - } - - return 0; +out_free_hash: + cifs_free_hash(&sha512); + return rc; } diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index d1528755f330..34dea8aa854b 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -4338,10 +4338,10 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst, return rc; } - rc = smb3_crypto_aead_allocate(server); - if (rc) { - cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__); - return rc; + /* sanity check -- TFMs were allocated after negotiate protocol */ + if (unlikely(!server->secmech.enc || !server->secmech.dec)) { + cifs_server_dbg(VFS, "%s: crypto TFMs are NULL\n", __func__); + return -EIO; } tfm = enc ? server->secmech.enc : server->secmech.dec; diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 6352ab32c7e7..60cfaa131c31 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -927,6 +927,16 @@ SMB2_negotiate(const unsigned int xid, else req->SecurityMode = 0; + if (req->SecurityMode) { + /* + * Allocate HMAC-SHA256 regardless of dialect requested, change to AES-CMAC later, + * if SMB3+ is negotiated + */ + rc = cifs_alloc_hash("hmac(sha256)", &server->secmech.hmacsha256); + if (rc) + goto neg_exit; + } + req->Capabilities = cpu_to_le32(server->vals->req_capabilities); if (ses->chan_max > 1) req->Capabilities |= cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL); @@ -1071,6 +1081,15 @@ SMB2_negotiate(const unsigned int xid, rc = cifs_enable_signing(server, ses->sign); if (rc) goto neg_exit; + + if (server->sign && server->dialect >= SMB30_PROT_ID) { + /* free HMAC-SHA256 allocated earlier for negprot */ + cifs_free_hash(&server->secmech.hmacsha256); + rc = cifs_alloc_hash("cmac(aes)", &server->secmech.aes_cmac); + if (rc) + goto neg_exit; + } + if (blob_length) { rc = decode_negTokenInit(security_blob, blob_length, server); if (rc == 1) diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 3f740f24b96a..a975144c63bf 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -267,7 +267,6 @@ extern int smb2_validate_and_copy_iov(unsigned int offset, extern void smb2_copy_fs_info_to_kstatfs( struct smb2_fs_full_size_info *pfs_inf, struct kstatfs *kst); -extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server); extern int smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server, struct kvec *iov, int nvec); diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index dfcbcc0b86e4..2dca2c255239 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -26,53 +26,6 @@ #include "smb2status.h" #include "smb2glob.h" -static int -smb3_crypto_shash_allocate(struct TCP_Server_Info *server) -{ - struct cifs_secmech *p = &server->secmech; - int rc; - - rc = cifs_alloc_hash("hmac(sha256)", &p->hmacsha256); - if (rc) - goto err; - - rc = cifs_alloc_hash("cmac(aes)", &p->aes_cmac); - if (rc) - goto err; - - return 0; -err: - cifs_free_hash(&p->hmacsha256); - return rc; -} - -int -smb311_crypto_shash_allocate(struct TCP_Server_Info *server) -{ - struct cifs_secmech *p = &server->secmech; - int rc = 0; - - rc = cifs_alloc_hash("hmac(sha256)", &p->hmacsha256); - if (rc) - return rc; - - rc = cifs_alloc_hash("cmac(aes)", &p->aes_cmac); - if (rc) - goto err; - - rc = cifs_alloc_hash("sha512", &p->sha512); - if (rc) - goto err; - - return 0; - -err: - cifs_free_hash(&p->aes_cmac); - cifs_free_hash(&p->hmacsha256); - return rc; -} - - static int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) { @@ -215,7 +168,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, struct kvec *iov = rqst->rq_iov; struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base; struct cifs_ses *ses; - struct shash_desc *shash; + struct shash_desc *shash = NULL; struct smb_rqst drqst; ses = smb2_find_smb_ses(server, le64_to_cpu(shdr->SessionId)); @@ -297,48 +250,50 @@ static int generate_key(struct cifs_ses *ses, struct kvec label, unsigned char prfhash[SMB2_HMACSHA256_SIZE]; unsigned char *hashptr = prfhash; struct TCP_Server_Info *server = ses->server; + struct shash_desc *hmac_sha256 = NULL; memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); memset(key, 0x0, key_size); - rc = smb3_crypto_shash_allocate(server); + /* do not reuse the server's secmech TFM */ + rc = cifs_alloc_hash("hmac(sha256)", &hmac_sha256); if (rc) { cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_setkey(server->secmech.hmacsha256->tfm, - ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); + rc = crypto_shash_setkey(hmac_sha256->tfm, ses->auth_key.response, + SMB2_NTLMV2_SESSKEY_SIZE); if (rc) { cifs_server_dbg(VFS, "%s: Could not set with session key\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_init(server->secmech.hmacsha256); + rc = crypto_shash_init(hmac_sha256); if (rc) { cifs_server_dbg(VFS, "%s: Could not init sign hmac\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_update(server->secmech.hmacsha256, i, 4); + rc = crypto_shash_update(hmac_sha256, i, 4); if (rc) { cifs_server_dbg(VFS, "%s: Could not update with n\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_update(server->secmech.hmacsha256, label.iov_base, label.iov_len); + rc = crypto_shash_update(hmac_sha256, label.iov_base, label.iov_len); if (rc) { cifs_server_dbg(VFS, "%s: Could not update with label\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_update(server->secmech.hmacsha256, &zero, 1); + rc = crypto_shash_update(hmac_sha256, &zero, 1); if (rc) { cifs_server_dbg(VFS, "%s: Could not update with zero\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_update(server->secmech.hmacsha256, context.iov_base, context.iov_len); + rc = crypto_shash_update(hmac_sha256, context.iov_base, context.iov_len); if (rc) { cifs_server_dbg(VFS, "%s: Could not update with context\n", __func__); goto smb3signkey_ret; @@ -346,16 +301,16 @@ static int generate_key(struct cifs_ses *ses, struct kvec label, if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) || (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) { - rc = crypto_shash_update(server->secmech.hmacsha256, L256, 4); + rc = crypto_shash_update(hmac_sha256, L256, 4); } else { - rc = crypto_shash_update(server->secmech.hmacsha256, L128, 4); + rc = crypto_shash_update(hmac_sha256, L128, 4); } if (rc) { cifs_server_dbg(VFS, "%s: Could not update with L\n", __func__); goto smb3signkey_ret; } - rc = crypto_shash_final(server->secmech.hmacsha256, hashptr); + rc = crypto_shash_final(hmac_sha256, hashptr); if (rc) { cifs_server_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); goto smb3signkey_ret; @@ -364,6 +319,7 @@ static int generate_key(struct cifs_ses *ses, struct kvec label, memcpy(key, hashptr, key_size); smb3signkey_ret: + cifs_free_hash(&hmac_sha256); return rc; } @@ -428,12 +384,19 @@ generate_smb3signingkey(struct cifs_ses *ses, ptriplet->encryption.context, ses->smb3encryptionkey, SMB3_ENC_DEC_KEY_SIZE); + if (rc) + return rc; + rc = generate_key(ses, ptriplet->decryption.label, ptriplet->decryption.context, ses->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE); if (rc) return rc; + + rc = smb3_crypto_aead_allocate(server); + if (rc) + return rc; } if (rc) @@ -535,7 +498,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, unsigned char *sigptr = smb3_signature; struct kvec *iov = rqst->rq_iov; struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base; - struct shash_desc *shash; + struct shash_desc *shash = NULL; struct smb_rqst drqst; u8 key[SMB3_SIGN_KEY_SIZE]; From patchwork Thu Sep 29 17:56:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Enzo Matsumiya X-Patchwork-Id: 12994518 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 873F1C433F5 for ; Thu, 29 Sep 2022 17:57:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234990AbiI2R5S (ORCPT ); Thu, 29 Sep 2022 13:57:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59998 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232380AbiI2R5Q (ORCPT ); Thu, 29 Sep 2022 13:57:16 -0400 Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D047B1CD10D for ; Thu, 29 Sep 2022 10:57:13 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 82CE81F8E1; Thu, 29 Sep 2022 17:57:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1664474232; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cIEmlbh9t24yA4izzWMSkCaAuoARMITGcwonkfW7FnI=; b=dsFRJak7eS0rCCqXMCknPnh0ukf/67DkNpZb5Gz2UihA62XrERAfZ6+aLU1wC5zKgzCExm 5kiT4qjW1UoCwbWsmhAbHfLh3tsd30COVnxcAX32cbWRX5b1vvOuGzYnoFEJxplx6Pth7K 6LkN7G0/E2JHCIZzn5uJYPVbhjlngAw= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1664474232; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cIEmlbh9t24yA4izzWMSkCaAuoARMITGcwonkfW7FnI=; b=4p73OkQem5BKCWGYuMtSs6P0g1tmPf+x7tndF0wGaTv2X+zYrOteZjZYB52y8w9Y47XdMB VhyeAXrTwRC9E9Bg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id C51C61348E; Thu, 29 Sep 2022 17:57:11 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id mOdLInfcNWPhFQAAMHmgww (envelope-from ); Thu, 29 Sep 2022 17:57:11 +0000 From: Enzo Matsumiya To: linux-cifs@vger.kernel.org Cc: smfrench@gmail.com, pc@cjr.nz, ronniesahlberg@gmail.com, nspmangalore@gmail.com, tom@talpey.com, metze@samba.org Subject: [PATCH v4 5/8] cifs: introduce AES-GMAC signing support for SMB 3.1.1 Date: Thu, 29 Sep 2022 14:56:53 -0300 Message-Id: <20220929175655.6906-2-ematsumiya@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20220929175655.6906-1-ematsumiya@suse.de> References: <20220929175655.6906-1-ematsumiya@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Implement support for AES-GMAC message signing, as specified in MS-SMB2 3.1.4.1 "Signing An Outgoing Message". The core function is smb311_calc_aes_gmac(), which will be used as the ->calc_signature op when SIGNING_ALG_AES_GMAC has been negotiated with the server. If "enable_negotiate_signing" is false (default) or if SIGNING_ALG_AES_GMAC was not negotiated, use AES-CMAC. Changes: - convert cifs_secmech sign/verify to unions, where .aead is for AES-GMAC TFM and .shash for all the others signing algorithms - init_sg(): rename to smb3_init_sg(), make it non-static, remove skip variable. This makes it fit for both crypt_message() and smb311_calc_signature() - crypt_message(): advance the 20 bytes of rqst[0].rq_iov[0] that are not part of the encrypted blob before calling smb3_init_sg(). Rewind it back right after the call. (this was done in init_sg() via the skip variable) - needed to move the ->calc_signature op to inside secmech since changing it within the smb_version_operations struct would make it incompatible with multiple connections with different algorithms or dialects Other smaller modifications: - smb2_setup_request(): check if the request has a transform header as we must not sign an encrypted message (MS-SMB2 3.2.4.1.1) - smb2_verify_signature(): * check if MessageId is 0xFFFFFFFFFFFFFFFF or if status is STATUS_PENDING (MS-SMB2 3.2.5.1.3) * remove extra call to zero the header signature as this is already done by all ->calc_signature implementations * remove useless call to check for "BSRSPYL" signature (SMB1 only), and from smb2_sign_rqst() as well Signed-off-by: Enzo Matsumiya --- v4: - rename smb311_calc_signature to smb311_calc_aes_gmac, and use SMB3_AES_GCM_NONCE instead of hardcoded '12' (suggested by metze) - update commit message to include the reasoning to move ->calc_signature op fs/cifs/cifsencrypt.c | 23 ++- fs/cifs/cifsglob.h | 40 +++-- fs/cifs/smb2ops.c | 38 ++--- fs/cifs/smb2pdu.c | 81 +++++----- fs/cifs/smb2proto.h | 9 +- fs/cifs/smb2transport.c | 331 ++++++++++++++++++++++++++++++---------- 6 files changed, 355 insertions(+), 167 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 4ae58ab29458..3a78efc45a23 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -23,6 +23,7 @@ #include #include "../smbfs_common/arc4.h" #include +#include "smb2proto.h" int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, char *signature, @@ -105,9 +106,9 @@ static int cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *se return -EINVAL; if (verify) - shash = server->secmech.verify; + shash = server->secmech.verify.shash; else - shash = server->secmech.sign; + shash = server->secmech.sign.shash; rc = crypto_shash_init(shash); if (rc) { @@ -703,16 +704,14 @@ calc_seckey(struct cifs_ses *ses) void cifs_crypto_secmech_release(struct TCP_Server_Info *server) { - cifs_free_hash(&server->secmech.sign); - cifs_free_hash(&server->secmech.verify); - - if (server->secmech.enc) { - crypto_free_aead(server->secmech.enc); - server->secmech.enc = NULL; + if (server->signing_algorithm == SIGNING_ALG_AES_GMAC) { + smb3_crypto_aead_free(&server->secmech.sign.aead); + smb3_crypto_aead_free(&server->secmech.verify.aead); + } else { + cifs_free_hash(&server->secmech.sign.shash); + cifs_free_hash(&server->secmech.verify.shash); } - if (server->secmech.dec) { - crypto_free_aead(server->secmech.dec); - server->secmech.dec = NULL; - } + smb3_crypto_aead_free(&server->secmech.enc); + smb3_crypto_aead_free(&server->secmech.dec); } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 30b3fadb4b06..81a8eff06467 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -153,24 +153,48 @@ struct session_key { char *response; }; +struct smb_rqst; +struct TCP_Server_Info; /** * cifs_secmech - Crypto hashing related structure/fields, not specific to one mechanism - * @sign: SHASH descriptor to allocate a hashing TFM for signing requests - * @verify: SHASH descriptor to allocate a hashing TFM for verifying requests' signatures + * @sign.shash: SHASH descriptor for signing TFM + * @sign.aead: AEAD TFM for signing + * @sign_wait: Completion struct for signing operations + * @verify.shash: SHASH descriptor for verifying TFM + * @verify.aead: AEAD TFM for verifying + * @verify_wait: Completion struct for verifying operations + * @calc_signature: Signature calculation function to be used. * @enc: AEAD TFM for SMB3+ encryption * @dec: AEAD TFM for SMB3+ decryption * - * @sign and @verify are allocated per-server, and the negotiated connection dialect will dictate - * which algorithm to use: + * @sign and @verify TFMs are allocated per-server, and the negotiated dialect will dictate which + * algorithm to use: * - MD5 for SMB1 * - HMAC-SHA256 for SMB2 * - AES-CMAC for SMB3 + * - AES-GMAC for SMB3.1.1 + * + * The completion structs @sign_wait and @verify_wait are required so that we can serialize access + * to the AEAD TFMs, since they're asynchronous by design. Using a stack-allocated structure could + * cause concurrent access to the TFMs to overwrite the completion status of a previous operation. * - * @enc and @dec holds the encryption/decryption TFMs, where it'll be either AES-CCM or AES-GCM. + * @enc and @dec holds the encryption/decryption TFMs, also allocated per server, where each will + * be either AES-CCM or AES-GCM. */ struct cifs_secmech { - struct shash_desc *sign; - struct shash_desc *verify; + union { + struct shash_desc *shash; + struct crypto_aead *aead; + } sign; + struct crypto_wait sign_wait; + + union { + struct shash_desc *shash; + struct crypto_aead *aead; + } verify; + struct crypto_wait verify_wait; + + int (*calc_signature)(struct smb_rqst *rqst, struct TCP_Server_Info *server, bool verify); struct crypto_aead *enc; struct crypto_aead *dec; @@ -445,8 +469,6 @@ struct smb_version_operations { void (*new_lease_key)(struct cifs_fid *); int (*generate_signingkey)(struct cifs_ses *ses, struct TCP_Server_Info *server); - int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *, - bool allocate_crypto); int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon, struct cifsFileInfo *src_file); int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon, diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 0aaad18e1ec8..e08065103b61 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -4234,21 +4234,14 @@ static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf, sg_set_page(sg, addr, buflen, offset_in_page(buf)); } -/* Assumes the first rqst has a transform header as the first iov. - * I.e. - * rqst[0].rq_iov[0] is transform header - * rqst[0].rq_iov[1+] data to be encrypted/decrypted - * rqst[1+].rq_iov[0+] data to be encrypted/decrypted - */ -static struct scatterlist * -init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign) +struct scatterlist * +smb3_init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign) { unsigned int sg_len; struct scatterlist *sg; unsigned int i; unsigned int j; unsigned int idx = 0; - int skip; sg_len = 1; for (i = 0; i < num_rqst; i++) @@ -4261,15 +4254,10 @@ init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign) sg_init_table(sg, sg_len); for (i = 0; i < num_rqst; i++) { for (j = 0; j < rqst[i].rq_nvec; j++) { - /* - * The first rqst has a transform header where the - * first 20 bytes are not part of the encrypted blob - */ - skip = (i == 0) && (j == 0) ? 20 : 0; smb2_sg_set_buf(&sg[idx++], - rqst[i].rq_iov[j].iov_base + skip, - rqst[i].rq_iov[j].iov_len - skip); - } + rqst[i].rq_iov[j].iov_base, + rqst[i].rq_iov[j].iov_len); + } for (j = 0; j < rqst[i].rq_npages; j++) { unsigned int len, offset; @@ -4325,7 +4313,17 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst, crypt_len += SMB2_SIGNATURE_SIZE; } - sg = init_sg(num_rqst, rqst, sign); + /* + * Skip the first 20 bytes of the first iov of the first request as they're not part of the + * encrypted blob + */ + rqst[0].rq_iov[0].iov_base += 20; + rqst[0].rq_iov[0].iov_len -= 20; + sg = smb3_init_sg(num_rqst, rqst, sign); + /* Rewind those 20 bytes before going any further */ + rqst[0].rq_iov[0].iov_base -= 20; + rqst[0].rq_iov[0].iov_len += 20; + if (!sg) { cifs_server_dbg(VFS, "%s: Failed to init sg\n", __func__); rc = -ENOMEM; @@ -5213,7 +5211,6 @@ struct smb_version_operations smb20_operations = { .get_lease_key = smb2_get_lease_key, .set_lease_key = smb2_set_lease_key, .new_lease_key = smb2_new_lease_key, - .calc_signature = smb2_calc_signature, .is_read_op = smb2_is_read_op, .set_oplock_level = smb2_set_oplock_level, .create_lease_buf = smb2_create_lease_buf, @@ -5314,7 +5311,6 @@ struct smb_version_operations smb21_operations = { .get_lease_key = smb2_get_lease_key, .set_lease_key = smb2_set_lease_key, .new_lease_key = smb2_new_lease_key, - .calc_signature = smb2_calc_signature, .is_read_op = smb21_is_read_op, .set_oplock_level = smb21_set_oplock_level, .create_lease_buf = smb2_create_lease_buf, @@ -5421,7 +5417,6 @@ struct smb_version_operations smb30_operations = { .set_lease_key = smb2_set_lease_key, .new_lease_key = smb2_new_lease_key, .generate_signingkey = generate_smb30signingkey, - .calc_signature = smb2_calc_signature, .set_integrity = smb3_set_integrity, .is_read_op = smb21_is_read_op, .set_oplock_level = smb3_set_oplock_level, @@ -5535,7 +5530,6 @@ struct smb_version_operations smb311_operations = { .set_lease_key = smb2_set_lease_key, .new_lease_key = smb2_new_lease_key, .generate_signingkey = generate_smb311signingkey, - .calc_signature = smb2_calc_signature, .set_integrity = smb3_set_integrity, .is_read_op = smb21_is_read_op, .set_oplock_level = smb3_set_oplock_level, diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index e5939c374c35..d7d6cbe6ba3b 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -460,7 +460,7 @@ static unsigned int build_signing_ctxt(struct smb2_signing_capabilities *pneg_ctxt) { unsigned int ctxt_len = sizeof(struct smb2_signing_capabilities); - unsigned short num_algs = 1; /* number of signing algorithms sent */ + unsigned short num_algs = 2; /* number of signing algorithms sent */ pneg_ctxt->ContextType = SMB2_SIGNING_CAPABILITIES; /* @@ -471,12 +471,18 @@ build_signing_ctxt(struct smb2_signing_capabilities *pneg_ctxt) sizeof(struct smb2_neg_context) + (num_algs * 2 /* sizeof u16 */), 8) * 8); pneg_ctxt->SigningAlgorithmCount = cpu_to_le16(num_algs); - pneg_ctxt->SigningAlgorithms[0] = cpu_to_le16(SIGNING_ALG_AES_CMAC); + + /* + * Set AES-GMAC as preferred, but will fall back to AES-CMAC if server doesn't support it. + * MS-SMB2 2.2.3.1.7 + */ + pneg_ctxt->SigningAlgorithms[0] = SIGNING_ALG_AES_GMAC_LE; + pneg_ctxt->SigningAlgorithms[1] = SIGNING_ALG_AES_CMAC_LE; + /* SMB 3.1.1 doesn't accept HMAC-SHA256, so no need to send it */ ctxt_len += 2 /* sizeof le16 */ * num_algs; ctxt_len = DIV_ROUND_UP(ctxt_len, 8) * 8; return ctxt_len; - /* TBD add SIGNING_ALG_AES_GMAC and/or SIGNING_ALG_HMAC_SHA256 */ } static void @@ -927,22 +933,6 @@ SMB2_negotiate(const unsigned int xid, else req->SecurityMode = 0; - if (req->SecurityMode) { - /* - * Allocate HMAC-SHA256 regardless of dialect requested, change to AES-CMAC later, - * if SMB3+ is negotiated - */ - rc = cifs_alloc_hash("hmac(sha256)", &server->secmech.sign); - if (rc) - goto neg_exit; - - rc = cifs_alloc_hash("hmac(sha256)", &server->secmech.verify); - if (rc) { - cifs_free_hash(&server->secmech.sign); - goto neg_exit; - } - } - req->Capabilities = cpu_to_le32(server->vals->req_capabilities); if (ses->chan_max > 1) req->Capabilities |= cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL); @@ -1087,22 +1077,6 @@ SMB2_negotiate(const unsigned int xid, rc = cifs_enable_signing(server, ses->sign); if (rc) goto neg_exit; - - if (server->sign && server->dialect >= SMB30_PROT_ID) { - /* free HMAC-SHA256 allocated earlier for negprot */ - cifs_free_hash(&server->secmech.sign); - cifs_free_hash(&server->secmech.verify); - rc = cifs_alloc_hash("cmac(aes)", &server->secmech.sign); - if (rc) - goto neg_exit; - - rc = cifs_alloc_hash("cmac(aes)", &server->secmech.verify); - if (rc) { - cifs_free_hash(&server->secmech.sign); - goto neg_exit; - } - } - if (blob_length) { rc = decode_negTokenInit(security_blob, blob_length, server); if (rc == 1) @@ -1112,12 +1086,34 @@ SMB2_negotiate(const unsigned int xid, } if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) { + server->signing_algorithm = SIGNING_ALG_AES_CMAC; + server->signing_negotiated = false; + if (rsp->NegotiateContextCount) rc = smb311_decode_neg_context(rsp, server, rsp_iov.iov_len); else cifs_server_dbg(VFS, "Missing expected negotiate contexts\n"); + + /* + * Some servers will not send a SMB2_SIGNING_CAPABILITIES context response (*), + * so use AES-CMAC signing algorithm as it is expected to be accepted. + * See MS-SMB2 note <125> Section 3.2.4.2.2.2 + */ + if (!server->signing_negotiated) + cifs_dbg(VFS, "signing capabilities were not negotiated, using AES-CMAC for message signing\n"); + } else if (server->dialect >= SMB30_PROT_ID) { + server->signing_algorithm = SIGNING_ALG_AES_CMAC; + } else if (server->dialect >= SMB20_PROT_ID) { + server->signing_algorithm = SIGNING_ALG_HMAC_SHA256; } + + rc = smb2_init_secmechs(server); + if (rc) { + cifs_dbg(VFS, "Failed to initialize secmechs, rc=%d\n", rc); + goto neg_exit; + } + neg_exit: free_rsp_buf(resp_buftype, rsp); return rc; @@ -1677,18 +1673,13 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data) goto out; if (ses->server->dialect < SMB30_PROT_ID) { - rc = crypto_shash_setkey(server->secmech.sign->tfm, - ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); - if (rc) { - cifs_dbg(VFS, "%s: Failed to set HMAC-SHA256 signing key, rc=%d\n", - __func__, rc); - goto out; - } - - rc = crypto_shash_setkey(server->secmech.verify->tfm, + rc = crypto_shash_setkey(server->secmech.sign.shash->tfm, ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); + if (!rc) + rc = crypto_shash_setkey(server->secmech.verify.shash->tfm, + ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); if (rc) { - cifs_dbg(VFS, "%s: Failed to set HMAC-SHA256 verify key, rc=%d\n", + cifs_dbg(VFS, "%s: Failed to set HMAC-SHA256 signing keys, rc=%d\n", __func__, rc); goto out; } diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 33af35b6e586..cc38e1784a97 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -14,6 +14,7 @@ struct statfs; struct smb_rqst; +struct crypto_aead; /* ***************************************************************** @@ -37,6 +38,7 @@ extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst); extern struct mid_q_entry *smb2_setup_async_request( struct TCP_Server_Info *server, struct smb_rqst *rqst); +extern int smb2_init_secmechs(struct TCP_Server_Info *server); extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id); extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server, @@ -44,6 +46,10 @@ extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server, extern int smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, bool verify); +extern int smb311_calc_aes_gmac(struct smb_rqst *rqst, + struct TCP_Server_Info *server, + bool verify); +extern struct scatterlist *smb3_init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign); extern void smb2_echo_request(struct work_struct *work); extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode); extern bool smb2_is_valid_oplock_break(char *buffer, @@ -99,7 +105,8 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, const unsigned int xid); extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile); extern void smb2_reconnect_server(struct work_struct *work); -extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server); +extern int smb3_crypto_aead_allocate(const char *name, struct crypto_aead **tfm); +extern void smb3_crypto_aead_free(struct crypto_aead **tfm); extern unsigned long smb_rqst_len(struct TCP_Server_Info *server, struct smb_rqst *rqst); extern void smb2_set_next_command(struct cifs_tcon *tcon, diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index cf319fc25161..df2fcd798bbc 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -26,6 +26,63 @@ #include "smb2status.h" #include "smb2glob.h" +int +smb2_init_secmechs(struct TCP_Server_Info *server) +{ + int rc = 0; + + if (server->dialect >= SMB30_PROT_ID && + (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) { + if (server->cipher_type == SMB2_ENCRYPTION_AES128_GCM || + server->cipher_type == SMB2_ENCRYPTION_AES256_GCM) { + rc = smb3_crypto_aead_allocate("gcm(aes)", &server->secmech.enc); + if (!rc) + rc = smb3_crypto_aead_allocate("gcm(aes)", &server->secmech.dec); + } else { + rc = smb3_crypto_aead_allocate("ccm(aes)", &server->secmech.enc); + if (!rc) + rc = smb3_crypto_aead_allocate("ccm(aes)", &server->secmech.dec); + } + + if (rc) + return rc; + } + + if (server->signing_algorithm == SIGNING_ALG_AES_GMAC) { + cifs_free_hash(&server->secmech.sign.shash); + cifs_free_hash(&server->secmech.verify.shash); + + rc = smb3_crypto_aead_allocate("gcm(aes)", &server->secmech.sign.aead); + if (!rc) + rc = smb3_crypto_aead_allocate("gcm(aes)", &server->secmech.verify.aead); + if (rc) { + smb3_crypto_aead_free(&server->secmech.sign.aead); + return rc; + } + + server->secmech.calc_signature = smb311_calc_aes_gmac; + } else { + char *shash_alg; + + if (server->dialect >= SMB30_PROT_ID) + shash_alg = "cmac(aes)"; + else + shash_alg = "hmac(sha256)"; + + rc = cifs_alloc_hash(shash_alg, &server->secmech.sign.shash); + if (!rc) + rc = cifs_alloc_hash(shash_alg, &server->secmech.verify.shash); + if (rc) { + cifs_free_hash(&server->secmech.sign.shash); + return rc; + } + + server->secmech.calc_signature = smb2_calc_signature; + } + + return rc; +} + static int smb3_setup_keys(struct TCP_Server_Info *server, u8 *sign_key, u8 *enc_key, u8 *dec_key) { @@ -42,44 +99,51 @@ smb3_setup_keys(struct TCP_Server_Info *server, u8 *sign_key, u8 *enc_key, u8 *d crypt_keylen = SMB3_GCM128_CRYPTKEY_SIZE; rc = crypto_aead_setkey(server->secmech.enc, enc_key, crypt_keylen); + if (!rc) + rc = crypto_aead_setkey(server->secmech.dec, dec_key, crypt_keylen); if (rc) { - cifs_server_dbg(VFS, "%s: Failed to set AEAD encryption key, rc=%d\n", + cifs_server_dbg(VFS, "%s: Failed to set encryption/decryption key, rc=%d\n", __func__, rc); return rc; } rc = crypto_aead_setauthsize(server->secmech.enc, SMB2_SIGNATURE_SIZE); + if (!rc) + rc = crypto_aead_setauthsize(server->secmech.dec, SMB2_SIGNATURE_SIZE); if (rc) { - cifs_server_dbg(VFS, "%s: Failed to set AEAD encryption authsize, rc=%d\n", - __func__, rc); - return rc; - } - - rc = crypto_aead_setkey(server->secmech.dec, dec_key, crypt_keylen); - if (rc) { - cifs_server_dbg(VFS, "%s: Failed to set AEAD decryption key, rc=%d\n", - __func__, rc); - return rc; - } - - rc = crypto_aead_setauthsize(server->secmech.dec, SMB2_SIGNATURE_SIZE); - if (rc) { - cifs_server_dbg(VFS, "%s: Failed to set AEAD decryption authsize, rc=%d\n", + cifs_server_dbg(VFS, "%s: Failed to set encryption/decryption authsize, rc=%d\n", __func__, rc); return rc; } setup_sign: - rc = crypto_shash_setkey(server->secmech.sign->tfm, sign_key, SMB3_SIGN_KEY_SIZE); - if (rc) { - cifs_server_dbg(VFS, "%s: Failed to set AES-CMAC signing key, rc=%d\n", - __func__, rc); - return rc; - } + if (server->signing_algorithm == SIGNING_ALG_AES_GMAC) { + rc = crypto_aead_setkey(server->secmech.sign.aead, sign_key, SMB3_SIGN_KEY_SIZE); + if (!rc) + rc = crypto_aead_setkey(server->secmech.verify.aead, sign_key, + SMB3_SIGN_KEY_SIZE); + if (rc) { + cifs_server_dbg(VFS, "%s: Failed to set AES-GMAC key, rc=%d\n", + __func__, rc); + return rc; + } - rc = crypto_shash_setkey(server->secmech.verify->tfm, sign_key, SMB3_SIGN_KEY_SIZE); - if (rc) - cifs_server_dbg(VFS, "%s: Failed to set AES-CMAC verify key, rc=%d\n", - __func__, rc); + rc = crypto_aead_setauthsize(server->secmech.sign.aead, SMB2_SIGNATURE_SIZE); + if (!rc) + rc = crypto_aead_setauthsize(server->secmech.verify.aead, + SMB2_SIGNATURE_SIZE); + if (rc) + cifs_server_dbg(VFS, "%s: Failed to set AES-GMAC authsize, rc=%d\n", + __func__, rc); + } else { + rc = crypto_shash_setkey(server->secmech.sign.shash->tfm, sign_key, + SMB3_SIGN_KEY_SIZE); + if (!rc) + rc = crypto_shash_setkey(server->secmech.verify.shash->tfm, sign_key, + SMB3_SIGN_KEY_SIZE); + if (rc) + cifs_server_dbg(VFS, "%s: Failed to set %s signing key, rc=%d\n", __func__, + crypto_shash_alg_name(server->secmech.sign.shash->tfm), rc); + } return rc; } @@ -171,9 +235,9 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, bool memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); if (verify) - shash = server->secmech.verify; + shash = server->secmech.verify.shash; else - shash = server->secmech.sign; + shash = server->secmech.sign.shash; rc = crypto_shash_init(shash); if (rc) { @@ -360,10 +424,6 @@ generate_smb3signingkey(struct cifs_ses *ses, if (rc) goto out_zero_keys; - rc = smb3_crypto_aead_allocate(server); - if (rc) - goto out_zero_keys; - rc = smb3_setup_keys(ses->server, sign_key, enc_key, dec_key); if (rc) goto out_zero_keys; @@ -471,6 +531,125 @@ generate_smb311signingkey(struct cifs_ses *ses, return generate_smb3signingkey(ses, server, &triplet); } +/* + * This function implements AES-GMAC signing for SMB2 messages as described in MS-SMB2 + * specification. This algorithm is only supported on SMB 3.1.1. + * + * Note: even though Microsoft mentions RFC4543 in MS-SMB2, the mechanism used _must_ be the "raw" + * AES-128-GCM ("gcm(aes)"); RFC4543 is designed for IPsec and trying to use "rfc4543(gcm(aes)))" + * will fail the signature computation. + * + * MS-SMB2 3.1.4.1 + */ +int +smb311_calc_aes_gmac(struct smb_rqst *rqst, struct TCP_Server_Info *server, bool verify) +{ + union { + struct { + /* for MessageId (8 bytes) */ + __le64 mid; + /* for role (client or server) and if SMB2 CANCEL (4 bytes) */ + __le32 role; + }; + u8 buffer[SMB3_AES_GCM_NONCE]; + } __packed nonce; + u8 sig[SMB2_SIGNATURE_SIZE] = { 0 }; + struct aead_request *aead_req = NULL; + struct crypto_aead *tfm = NULL; + struct scatterlist *sg = NULL; + unsigned long assoclen; + struct smb2_hdr *shdr = NULL; + struct crypto_wait *wait; + unsigned int save_npages = 0; + int rc = 0; + + if (verify) { + wait = &server->secmech.verify_wait; + tfm = server->secmech.verify.aead; + } else { + wait = &server->secmech.sign_wait; + tfm = server->secmech.sign.aead; + } + + if (completion_done(&wait->completion)) + reinit_completion(&wait->completion); + + shdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base; + + memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE); + memset(&nonce, 0, SMB3_AES_GCM_NONCE); + + /* note that nonce must always be little endian */ + nonce.mid = shdr->MessageId; + /* request is coming from the server, set LSB */ + nonce.role |= shdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR; + /* set penultimate LSB if SMB2_CANCEL command */ + if (shdr->Command == SMB2_CANCEL) + nonce.role |= cpu_to_le32(1UL << 1); + + aead_req = aead_request_alloc(tfm, GFP_KERNEL); + if (!aead_req) { + cifs_dbg(VFS, "%s: Failed to alloc AEAD request\n", __func__); + return -ENOMEM; + } + + /* skip page data if non-success error status, as it will compute an invalid signature */ + if (shdr->Status != 0 && rqst->rq_npages > 0) { + save_npages = rqst->rq_npages; + rqst->rq_npages = 0; + } + + assoclen = smb_rqst_len(server, rqst); + + sg = smb3_init_sg(1, rqst, sig); + if (!sg) { + cifs_dbg(VFS, "%s: Failed to init SG\n", __func__); + goto out_free_req; + } + + /* cryptlen == 0 because we're not encrypting anything */ + aead_request_set_crypt(aead_req, sg, sg, 0, nonce.buffer); + aead_request_set_ad(aead_req, assoclen); + aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, crypto_req_done, wait); + + /* + * Reminder: we must always use the encrypt function, as AES-GCM decrypt will internally + * try to match the authentication codes, where we pass a zeroed buffer, and the operation + * will fail with -EBADMSG (expectedly). + * + * Also note we can't use crypto_wait_req() here since it's not interruptible. + */ + rc = crypto_aead_encrypt(aead_req); + if (!rc) + goto out; + + if (rc == -EINPROGRESS || rc == -EBUSY) { + rc = wait_for_completion_interruptible(&wait->completion); + if (!rc) + /* wait->err is set by crypto_req_done callback above */ + rc = wait->err; + } + + if (rc) { + cifs_server_dbg(VFS, "%s: Failed to compute AES-GMAC signature, rc=%d\n", + __func__, rc); + goto out_free_sg; + } + +out: + memcpy(&shdr->Signature, sig, SMB2_SIGNATURE_SIZE); +out_free_sg: + kfree(sg); +out_free_req: + kfree(aead_req); + + /* restore rq_npages for further processing */ + if (shdr->Status != 0 && save_npages > 0) + rqst->rq_npages = save_npages; + + return rc; +} + /* must be called with server->srv_mutex held */ static int smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) @@ -497,12 +676,10 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) return 0; } spin_unlock(&server->srv_lock); - if (!is_binding && !server->session_estab) { - strncpy(shdr->Signature, "BSRSPYL", 8); + if (!is_binding && !server->session_estab) return 0; - } - rc = server->ops->calc_signature(rqst, server, false); + rc = server->secmech.calc_signature(rqst, server, false); return rc; } @@ -518,6 +695,8 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) if ((shdr->Command == SMB2_NEGOTIATE) || (shdr->Command == SMB2_SESSION_SETUP) || (shdr->Command == SMB2_OPLOCK_BREAK) || + (shdr->MessageId == cpu_to_le64(0xFFFFFFFFFFFFFFFF)) || + (shdr->Status == STATUS_PENDING) || server->ignore_signature || (!server->session_estab)) return 0; @@ -527,20 +706,13 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) * server does not send one? BB */ - /* Do not need to verify session setups with signature "BSRSPYL " */ - if (memcmp(shdr->Signature, "BSRSPYL ", 8) == 0) - cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n", - shdr->Command); - /* * Save off the origiginal signature so we can modify the smb and check * our calculated signature against what the server sent. */ memcpy(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE); - memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE); - - rc = server->ops->calc_signature(rqst, server, true); + rc = server->secmech.calc_signature(rqst, server, true); if (rc) return rc; @@ -693,6 +865,8 @@ smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server, int rc; struct smb2_hdr *shdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base; + struct smb2_transform_hdr *trhdr = + (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base; struct mid_q_entry *mid; smb2_seq_num_into_buf(server, shdr); @@ -703,11 +877,22 @@ smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server, return ERR_PTR(rc); } - rc = smb2_sign_rqst(rqst, server); - if (rc) { - revert_current_mid_from_hdr(server, shdr); - delete_mid(mid); - return ERR_PTR(rc); + /* + * Client must not sign the request if it's encrypted. + * + * Note: we can't rely on SMB2_SESSION_FLAG_ENCRYPT_DATA or SMB2_GLOBAL_CAP_ENCRYPTION + * here because they might be set, but not being actively used (e.g. not mounted with + * "seal"), so just check if header is a transform header. + * + * MS-SMB2 3.2.4.1.1 + */ + if (trhdr->ProtocolId != SMB2_TRANSFORM_PROTO_NUM) { + rc = smb2_sign_rqst(rqst, server); + if (rc) { + revert_current_mid_from_hdr(server, shdr); + delete_mid(mid); + return ERR_PTR(rc); + } } return mid; @@ -748,39 +933,29 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) } int -smb3_crypto_aead_allocate(struct TCP_Server_Info *server) +smb3_crypto_aead_allocate(const char *name, struct crypto_aead **tfm) { - struct crypto_aead *tfm; + if (unlikely(!tfm)) + return -EIO; - if (!server->secmech.enc) { - if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) || - (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) - tfm = crypto_alloc_aead("gcm(aes)", 0, 0); - else - tfm = crypto_alloc_aead("ccm(aes)", 0, 0); - if (IS_ERR(tfm)) { - cifs_server_dbg(VFS, "%s: Failed alloc encrypt aead\n", - __func__); - return PTR_ERR(tfm); - } - server->secmech.enc = tfm; - } + if (*tfm) + return 0; - if (!server->secmech.dec) { - if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) || - (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) - tfm = crypto_alloc_aead("gcm(aes)", 0, 0); - else - tfm = crypto_alloc_aead("ccm(aes)", 0, 0); - if (IS_ERR(tfm)) { - crypto_free_aead(server->secmech.enc); - server->secmech.enc = NULL; - cifs_server_dbg(VFS, "%s: Failed to alloc decrypt aead\n", - __func__); - return PTR_ERR(tfm); - } - server->secmech.dec = tfm; + *tfm = crypto_alloc_aead(name, CRYPTO_ALG_TYPE_AEAD, 0); + if (IS_ERR(*tfm)) { + cifs_dbg(VFS, "%s: Failed to alloc %s crypto TFM, rc=%ld\n", + __func__, name, PTR_ERR(*tfm)); + return PTR_ERR(*tfm); } return 0; } + +void smb3_crypto_aead_free(struct crypto_aead **tfm) +{ + if (!tfm || !*tfm) + return; + + crypto_free_aead(*tfm); + *tfm = NULL; +} From patchwork Thu Sep 29 17:56:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Enzo Matsumiya X-Patchwork-Id: 12994519 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 72C39C433FE for ; Thu, 29 Sep 2022 17:57:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235024AbiI2R5V (ORCPT ); Thu, 29 Sep 2022 13:57:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60162 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235011AbiI2R5S (ORCPT ); Thu, 29 Sep 2022 13:57:18 -0400 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C6DCCF50B5 for ; Thu, 29 Sep 2022 10:57:17 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 15DD01F8E0; Thu, 29 Sep 2022 17:57:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1664474236; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pyYFV0GURIhmZ2KViTBUZMXRtS4strsrdpTJyfb+JE0=; b=G44p40algeW7mU067J5nLKy9yDmD4hQ6YEmxRJWMVGGEZyBRMGMnYi7o01sBuGtNQ/SPuW fibZp3W2wa34djezQABNtu+pPrcLDPlaYZTlToCQT2I2XJhYeevTqktSTVZaPhAkf/eaLB llu6FD/voob6Gu5OYqwjI0J/lTjqLRI= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1664474236; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pyYFV0GURIhmZ2KViTBUZMXRtS4strsrdpTJyfb+JE0=; b=EPapUyrxoDM9Y7TD4CuuIHs1OjrE6T2It8C2Fjf7CchgVM6yRdp5ULymPzpZeCUo4bQYHo cDQFT3n/TXxjKUCw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 83A161348E; Thu, 29 Sep 2022 17:57:15 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id RazGEHvcNWPqFQAAMHmgww (envelope-from ); Thu, 29 Sep 2022 17:57:15 +0000 From: Enzo Matsumiya To: linux-cifs@vger.kernel.org Cc: smfrench@gmail.com, pc@cjr.nz, ronniesahlberg@gmail.com, nspmangalore@gmail.com, tom@talpey.com, metze@samba.org Subject: [PATCH v4 6/8] cifs: deprecate 'enable_negotiate_signing' module param Date: Thu, 29 Sep 2022 14:56:54 -0300 Message-Id: <20220929175655.6906-3-ematsumiya@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20220929175655.6906-1-ematsumiya@suse.de> References: <20220929175655.6906-1-ematsumiya@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Deprecate enable_negotiate_signing module parameter as it's irrelevant since the requested dialect and server support will dictate which algorithm will actually be used. Send a negotiate signing context on every SMB 3.1.1 negotiation now. AES-CMAC will still be used instead, iff, SMB 3.0.x negotiated or SMB 3.1.1 negotiated, but server doesn't support AES-GMAC. Warn the user if, for whatever reason, the module was loaded with 'enable_negotiate_signing=0'. Signed-off-by: Enzo Matsumiya --- v4: fix checkpatch errors (thanks to Steve) fs/cifs/cifsfs.c | 14 +++++++++++--- fs/cifs/cifsglob.h | 5 ++++- fs/cifs/smb2pdu.c | 11 ++++------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8042d7280dec..c46dc9edf6ec 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -65,7 +65,7 @@ bool lookupCacheEnabled = true; bool disable_legacy_dialects; /* false by default */ bool enable_gcm_256 = true; bool require_gcm_256; /* false by default */ -bool enable_negotiate_signing; /* false by default */ +bool enable_negotiate_signing = true; /* deprecated -- always true now */ unsigned int global_secflags = CIFSSEC_DEF; /* unsigned int ntlmv2_support = 0; */ unsigned int sign_CIFS_PDUs = 1; @@ -133,8 +133,12 @@ MODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encr module_param(require_gcm_256, bool, 0644); MODULE_PARM_DESC(require_gcm_256, "Require strongest (256 bit) GCM encryption. Default: n/N/0"); -module_param(enable_negotiate_signing, bool, 0644); -MODULE_PARM_DESC(enable_negotiate_signing, "Enable negotiating packet signing algorithm with server. Default: n/N/0"); +/* XXX: remove this at some point */ +module_param(enable_negotiate_signing, bool, 0); +MODULE_PARM_DESC(enable_negotiate_signing, + "(deprecated) Enable negotiating packet signing algorithm with the server. " + "This parameter is ignored as cifs.ko will always try to negotiate the signing " + "algorithm on SMB 3.1.1 mounts."); module_param(disable_legacy_dialects, bool, 0644); MODULE_PARM_DESC(disable_legacy_dialects, "To improve security it may be " @@ -1712,6 +1716,10 @@ init_cifs(void) goto out_init_cifs_idmap; } + if (!enable_negotiate_signing) + pr_warn_once("ignoring deprecated module parameter 'enable_negotiate_signing=0', " + "will try to negotiate signing capabilities anyway...\n"); + return 0; out_init_cifs_idmap: diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 81a8eff06467..49561e325412 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -2031,7 +2031,10 @@ extern unsigned int global_secflags; /* if on, session setup sent extern unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ extern bool enable_gcm_256; /* allow optional negotiate of strongest signing (aes-gcm-256) */ extern bool require_gcm_256; /* require use of strongest signing (aes-gcm-256) */ -extern bool enable_negotiate_signing; /* request use of faster (GMAC) signing if available */ +extern bool enable_negotiate_signing; /* + * request use of faster (GMAC) signing if available + * XXX: deprecated, remove it at some point + */ extern bool linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/ extern unsigned int CIFSMaxBufSize; /* max size not including hdr */ extern unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index d7d6cbe6ba3b..785465873422 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -609,13 +609,10 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, neg_context_count++; } - if (enable_negotiate_signing) { - ctxt_len = build_signing_ctxt((struct smb2_signing_capabilities *) - pneg_ctxt); - *total_len += ctxt_len; - pneg_ctxt += ctxt_len; - neg_context_count++; - } + ctxt_len = build_signing_ctxt((struct smb2_signing_capabilities *)pneg_ctxt); + *total_len += ctxt_len; + pneg_ctxt += ctxt_len; + neg_context_count++; /* check for and add transport_capabilities and signing capabilities */ req->NegotiateContextCount = cpu_to_le16(neg_context_count); From patchwork Thu Sep 29 17:56:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Enzo Matsumiya X-Patchwork-Id: 12994520 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A62E1C433FE for ; Thu, 29 Sep 2022 17:57:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230114AbiI2R50 (ORCPT ); Thu, 29 Sep 2022 13:57:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60368 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235083AbiI2R5W (ORCPT ); Thu, 29 Sep 2022 13:57:22 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 456631E05E0 for ; Thu, 29 Sep 2022 10:57:20 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 85D5821BBD; Thu, 29 Sep 2022 17:57:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1664474239; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=l36NagjY4i3eUkSR7rZMTVuIGsNsf+5xjTAjof7bQ5M=; b=pFsgjFsrj5y7Yj21Cn5VGMrEC6HH/BaHij/YYTfGBhgHOsMQ+it5wKoL6d2s5lw5mWCJgg /HNl3iXUNn8FaNY62lAR0skdcdaKtrfYh5h6jVqa9BqBmr/AlNFxrnlxBIFkt+4I9hHDx8 X370/NVZyYpoYW2ASP8Q3dtiMCfCj/4= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1664474239; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=l36NagjY4i3eUkSR7rZMTVuIGsNsf+5xjTAjof7bQ5M=; b=vyn+aFq2OhDTtr0Y4tbljPvVZFYoDxGOulJAaiVPbzr7t4uGIwwOqdQI7aoMUAw1oo32Ga exatH8gG323NuXAQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 0A58B1348E; Thu, 29 Sep 2022 17:57:18 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id gj/QL37cNWP0FQAAMHmgww (envelope-from ); Thu, 29 Sep 2022 17:57:18 +0000 From: Enzo Matsumiya To: linux-cifs@vger.kernel.org Cc: smfrench@gmail.com, pc@cjr.nz, ronniesahlberg@gmail.com, nspmangalore@gmail.com, tom@talpey.com, metze@samba.org Subject: [PATCH v4 8/8] cifs: use MAX_CIFS_SMALL_BUFFER_SIZE-8 as padding buffer Date: Thu, 29 Sep 2022 14:56:55 -0300 Message-Id: <20220929175655.6906-4-ematsumiya@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20220929175655.6906-1-ematsumiya@suse.de> References: <20220929175655.6906-1-ematsumiya@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org AES-GMAC is more picky about buffers locality, alignment, and size, so we can't use a stack-allocated buffer as padding (smb2_padding). This commit drops smb2_padding and "reserves" the 8 last bytes of each small buffer, which are slab-allocated, as the padding buffer space. Introduce SMB2_PADDING_BUF(buf) macro to easily grab the padding buffer. For now, only used by smb2_set_next_command(). Signed-off-by: Enzo Matsumiya --- v4: - move SMB2_PADDING_BUF to smb2glob.h - check if iov is SMB2_PADDING_BUF in the free functions where smb2_padding was previously used (pointed out by metze) fs/cifs/smb2glob.h | 5 +++++ fs/cifs/smb2ops.c | 4 +--- fs/cifs/smb2pdu.c | 9 +++++++-- fs/cifs/smb2pdu.h | 2 -- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h index 3a3e81b1b8cb..f3dd39c9be97 100644 --- a/fs/cifs/smb2glob.h +++ b/fs/cifs/smb2glob.h @@ -41,6 +41,11 @@ #define END_OF_CHAIN 4 #define RELATED_REQUEST 8 +/* + * Use the last 8 bytes of the small buf as the padding buffer, when necessary + */ +#define SMB2_PADDING_BUF(buf) (buf + MAX_CIFS_SMALL_BUFFER_SIZE - 8) + static inline const char *smb2_signing_algo_str(u16 algo) { switch (algo) { diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index e08065103b61..571961ca61ff 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2323,8 +2323,6 @@ smb2_set_related(struct smb_rqst *rqst) shdr->Flags |= SMB2_FLAGS_RELATED_OPERATIONS; } -char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0}; - void smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst) { @@ -2352,7 +2350,7 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst) * If we do not have encryption then we can just add an extra * iov for the padding. */ - rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding; + rqst->rq_iov[rqst->rq_nvec].iov_base = SMB2_PADDING_BUF(rqst->rq_iov[0].iov_base); rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding; rqst->rq_nvec++; len += num_padding; diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 97dac970cd52..a4da04472377 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -362,6 +362,9 @@ fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon, /* * smaller than SMALL_BUFFER_SIZE but bigger than fixed area of * largest operations (Create) + * + * Note that the last 8 bytes of the small buffer are reserved for padding when required + * (see SMB2_PADDING_BUF in smb2ops.c) */ memset(buf, 0, 256); @@ -2992,7 +2995,8 @@ SMB2_open_free(struct smb_rqst *rqst) if (rqst && rqst->rq_iov) { cifs_small_buf_release(rqst->rq_iov[0].iov_base); for (i = 1; i < rqst->rq_nvec; i++) - if (rqst->rq_iov[i].iov_base != smb2_padding) + if (rqst->rq_iov[i].iov_base != + SMB2_PADDING_BUF(rqst->rq_iov[0].iov_base)) kfree(rqst->rq_iov[i].iov_base); } } @@ -3186,7 +3190,8 @@ SMB2_ioctl_free(struct smb_rqst *rqst) if (rqst && rqst->rq_iov) { cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */ for (i = 1; i < rqst->rq_nvec; i++) - if (rqst->rq_iov[i].iov_base != smb2_padding) + if (rqst->rq_iov[i].iov_base != + SMB2_PADDING_BUF(rqst->rq_iov[0].iov_base)) kfree(rqst->rq_iov[i].iov_base); } } diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index f57881b8464f..689973a3acbb 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -371,8 +371,6 @@ struct smb2_file_id_extd_directory_info { char FileName[1]; } __packed; /* level 60 */ -extern char smb2_padding[7]; - /* equivalent of the contents of SMB3.1.1 POSIX open context response */ struct create_posix_rsp { u32 nlink;