From patchwork Mon Apr 9 16:18:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve French X-Patchwork-Id: 896357 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="oBxaPCH7"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40Kb980r9dz9s1p for ; Tue, 10 Apr 2018 02:19:24 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752965AbeDIQTW (ORCPT ); Mon, 9 Apr 2018 12:19:22 -0400 Received: from mail-pg0-f43.google.com ([74.125.83.43]:36256 "EHLO mail-pg0-f43.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752790AbeDIQTU (ORCPT ); Mon, 9 Apr 2018 12:19:20 -0400 Received: by mail-pg0-f43.google.com with SMTP id 201so437634pgg.3 for ; Mon, 09 Apr 2018 09:19:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=w54/T28ibZR5BqJnXa24c0q6XMy6sxGGwxiXeI43s8k=; b=oBxaPCH76lar5WZCL2Zioxc5tlRj8CmZwaxfmITJFRHM+Xs4B2sFSDvdf187ef4XzI C7cJCvmT60K93gQR6Q9d1E1zgIGIYhM5g/h/FT9hR7sSlQH721aY0SRMaGJ72pAsddUP Tg0xW35EVz2m8Vb5ceVPrytaD9lMGGFm82kDC9yqwHkPcZ/1kMj+Yyblq2M29wVe8OOd qOxysYwKIpfB/oDRZQE9EEh0z2AzWocY5DlEOyk9y6LzFGixW7PQjsa/DDlCNaXa/4sa cz2oNQG+wIGC0gS04m6GumU4aQOyik+6ehTS4y4RnTjB15LCyVZiV/UJOlLiIviAUwmD YgnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=w54/T28ibZR5BqJnXa24c0q6XMy6sxGGwxiXeI43s8k=; b=e6aj9pgBH3VcNX0x99jDJ7Gy/wAsYoLRxq/I+bo97jj+9gRlqXJNXGF4amQybCwHs6 +w1DZbZ7JgjDfFmxXIfFCfZFYgG25o7rdy3gEQQHearrspsgbMn7c9kUcBOrxHIB8nQV BfvpSk7SivDu4v5ysPke5SngEPnzfny+ZdT0e0jYstKMMefDX1v++mkXqR9JA8m+vvfc +YLWUreDBOhPx7vBJBPeGDOjQBTR9jIwtF+fZl37cx/uFJ2I+XZVz37MoBxsuMwlMNZA UUnrZB+/4NinzeIO0drLOwA0l5ecQNu6QmMQp/sZIk9LYJBIqAOerRUMc7af0ozvtyTs 3yXA== X-Gm-Message-State: AElRT7E54voHG76gzk+P/z20FA+ZOt0+pC9vMz8yyk+N0z1VqJBgPUWr HKSMUXpsDy0SwInZRyXyRTkLyOPc70Dzk0dQQUdCy4VT X-Google-Smtp-Source: AIpwx4+HOrxfS16jrpPjeDf6fzHK/xotkUAdCVosvs2elHdszIsrLWEDIUnS3kT7kn/fBoVfyPvngstSk2yimKqBU7Q= X-Received: by 10.99.130.199 with SMTP id w190mr25749645pgd.15.1523290758670; Mon, 09 Apr 2018 09:19:18 -0700 (PDT) MIME-Version: 1.0 Received: by 10.100.152.97 with HTTP; Mon, 9 Apr 2018 09:18:57 -0700 (PDT) From: Steve French Date: Mon, 9 Apr 2018 11:18:57 -0500 Message-ID: Subject: [PATCH][SMB311] Improve checking of negotiate security contexts To: CIFS Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org SMB3.11 crypto and hash contexts were not being checked strictly enough. Add parsing and validity checking for the security contexts in the SMB3.11 negotiate response. Patch attached. From 843c6f2ed716a2e061a28bc2455a96876947f6c0 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 9 Apr 2018 10:47:14 -0500 Subject: [PATCH] SMB311: Improve checking of negotiate security contexts SMB3.11 crypto and hash contexts were not being checked strictly enough. Add parsing and validity checking for the security contexts in the SMB3.11 negotiate response. Signed-off-by: Steve French CC: Stable --- fs/cifs/cifsglob.h | 1 + fs/cifs/smb2pdu.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.h | 3 ++ 3 files changed, 106 insertions(+) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 2282562e78a1..56fee0330afc 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -676,6 +676,7 @@ struct TCP_Server_Info { unsigned int max_read; unsigned int max_write; #ifdef CONFIG_CIFS_SMB311 + __le16 cipher_type; /* save initital negprot hash */ __u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE]; #endif /* 3.1.1 */ diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 6c2910e6c984..e01be06d588e 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -406,6 +406,99 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, *total_len += 4 + sizeof(struct smb2_preauth_neg_context) + sizeof(struct smb2_encryption_neg_context); } + +static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt) +{ + unsigned int len = le16_to_cpu(ctxt->DataLength); + + /* If invalid preauth context warn but use what we requested, SHA-512 */ + if (len < MIN_PREAUTH_CTXT_DATA_LEN) { + printk_once(KERN_WARNING "server sent bad preauth context\n"); + return; + } + if (le16_to_cpu(ctxt->HashAlgorithmCount) != 1) + printk_once(KERN_WARNING "illegal SMB3 hash algorithm count\n"); + if (ctxt->HashAlgorithms != SMB2_PREAUTH_INTEGRITY_SHA512) + printk_once(KERN_WARNING "unknown SMB3 hash algorithm\n"); +} + +static int decode_encrypt_ctx(struct TCP_Server_Info *server, + struct smb2_encryption_neg_context *ctxt) +{ + unsigned int len = le16_to_cpu(ctxt->DataLength); + + cifs_dbg(FYI, "decode SMB3.11 encryption neg context of len %d\n", len); + if (len < MIN_ENCRYPT_CTXT_DATA_LEN) { + printk_once(KERN_WARNING "server sent bad crypto ctxt len\n"); + return -EINVAL; + } + + if (le16_to_cpu(ctxt->CipherCount) != 1) { + printk_once(KERN_WARNING "illegal SMB3.11 cipher count\n"); + return -EINVAL; + } + cifs_dbg(FYI, "SMB311 cipher type:%d\n", le16_to_cpu(ctxt->Ciphers[0])); + if ((ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES128_CCM) && + (ctxt->Ciphers[0] != SMB2_ENCRYPTION_AES128_GCM)) { + printk_once(KERN_WARNING "invalid SMB3.11 cipher returned\n"); + return -EINVAL; + } + server->cipher_type = ctxt->Ciphers[0]; + return 0; +} + +static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp, + struct TCP_Server_Info *server) +{ + struct smb2_neg_context *pctx; + unsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset); + unsigned int ctxt_cnt = le16_to_cpu(rsp->NegotiateContextCount); + unsigned int len_of_smb = be32_to_cpu(rsp->hdr.smb2_buf_length); + unsigned int len_of_ctxts, i; + int rc = 0; + + cifs_dbg(FYI, "decoding %d negotiate contexts\n", ctxt_cnt); + if (len_of_smb <= offset) { + cifs_dbg(VFS, "Invalid response: negotiate context offset\n"); + return -EINVAL; + } + + len_of_ctxts = len_of_smb - offset; + + for (i = 0; i < ctxt_cnt; i++) { + int clen; + /* check that offset is not beyond end of SMB */ + if (len_of_ctxts == 0) + break; + + if (len_of_ctxts < sizeof(struct smb2_neg_context)) + break; + + pctx = (struct smb2_neg_context *)(offset + 4 + (char *)rsp); + clen = le16_to_cpu(pctx->DataLength); + if (clen > len_of_ctxts) + break; + + if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) + decode_preauth_context( + (struct smb2_preauth_neg_context *)pctx); + else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) + rc = decode_encrypt_ctx(server, + (struct smb2_encryption_neg_context *)pctx); + else + cifs_dbg(VFS, "unknown negcontext of type %d ignored\n", + le16_to_cpu(pctx->ContextType)); + + if (rc) + break; + /* offsets must be 8 byte aligned */ + clen = (clen + 7) & ~0x7; + offset += clen + sizeof(struct smb2_neg_context); + len_of_ctxts -= clen; + } + return rc; +} + #else static void assemble_neg_contexts(struct smb2_negotiate_req *req, unsigned int *total_len) @@ -619,6 +712,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) else if (rc == 0) rc = -EIO; } + +#ifdef CONFIG_CIFS_SMB311 + if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) { + if (rsp->NegotiateContextCount) + rc = smb311_decode_neg_context(rsp, server); + else + cifs_dbg(VFS, "Missing expected negotiate contexts\n"); + } +#endif /* CONFIG_CIFS_SMB311 */ neg_exit: free_rsp_buf(resp_buftype, rsp); return rc; diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 0e0a0af89e4d..6093e5142b2b 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -275,6 +275,7 @@ struct smb2_neg_context { #define SMB2_PREAUTH_INTEGRITY_SHA512 cpu_to_le16(0x0001) #define SMB2_PREAUTH_HASH_SIZE 64 +#define MIN_PREAUTH_CTXT_DATA_LEN (SMB311_SALT_SIZE + 6) struct smb2_preauth_neg_context { __le16 ContextType; /* 1 */ __le16 DataLength; @@ -289,6 +290,8 @@ struct smb2_preauth_neg_context { #define SMB2_ENCRYPTION_AES128_CCM cpu_to_le16(0x0001) #define SMB2_ENCRYPTION_AES128_GCM cpu_to_le16(0x0002) +/* Min encrypt context data is one cipher so 2 bytes + 2 byte count field */ +#define MIN_ENCRYPT_CTXT_DATA_LEN 4 struct smb2_encryption_neg_context { __le16 ContextType; /* 2 */ __le16 DataLength; -- 2.14.1