From patchwork Tue Dec 6 22:02:32 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Shilovskiy X-Patchwork-Id: 9463337 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A0BB160231 for ; Tue, 6 Dec 2016 22:18:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 90DED284F0 for ; Tue, 6 Dec 2016 22:18:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 83C65284F4; Tue, 6 Dec 2016 22:18:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6FB08284F0 for ; Tue, 6 Dec 2016 22:18:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752357AbcLFWS0 (ORCPT ); Tue, 6 Dec 2016 17:18:26 -0500 Received: from mail-by2nam01on0111.outbound.protection.outlook.com ([104.47.34.111]:12416 "EHLO NAM01-BY2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752295AbcLFWSZ (ORCPT ); Tue, 6 Dec 2016 17:18:25 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=EbxeEdpYthQjjuSuYbBVFcCOldWr953jYdwlgbKxE0k=; b=jMDshrip3TImds1sAjfN5JahiuoxleofxgDknsdT6i/EVRxU1LX/cadc/Z2E0rc7QoypM8jaIQV92wzhSvXwP9vCKsqwlOYVywRKhkEFzG+tyPkPsHAJDGs/sLtqVM6GeWcUTM2JLEjtfVsT+/Z/7seS3I46C7v6vAtikI8zUaI= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=pshilov@microsoft.com; Received: from ubuntu-vm.corp.microsoft.com (2001:4898:80e8:2::63b) by CY4PR03MB2549.namprd03.prod.outlook.com (10.173.41.148) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.761.9; Tue, 6 Dec 2016 22:02:48 +0000 From: Pavel Shilovsky To: linux-cifs@vger.kernel.org Subject: [PATCH 09/15] CIFS: Encrypt SMB3 requests before sending Date: Tue, 6 Dec 2016 14:02:32 -0800 Message-Id: <1481061758-52020-10-git-send-email-pshilov@microsoft.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1481061758-52020-1-git-send-email-pshilov@microsoft.com> References: <1481061758-52020-1-git-send-email-pshilov@microsoft.com> MIME-Version: 1.0 X-Originating-IP: [2001:4898:80e8:2::63b] X-ClientProxiedBy: CY1PR17CA0004.namprd17.prod.outlook.com (10.163.68.14) To CY4PR03MB2549.namprd03.prod.outlook.com (10.173.41.148) X-MS-Office365-Filtering-Correlation-Id: fe09594f-670e-4ee3-18d9-08d41e239e03 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001); SRVR:CY4PR03MB2549; X-Microsoft-Exchange-Diagnostics: 1; CY4PR03MB2549; 3:0MqsXJU9NVZEZfFmorvLYDX4LYxHwaKkDm0DtsVuZPqO+XPCglzMgbO4lWGBiCbuaAqCrOBgdy1hushafA0JB0teTmpfrWa1dl2Kccf4XgN/UNd8j1ocVs+i8yjl3bdaOvDKTHSTzePsWNANvE3nGCkoK5VxGE1OJ55h70t8Wjqu7tX+z0uz/2FSUxsBRZE3S+qiiyfljIpsGw8slWvx+Ktzg0gVmuE8QVb19NBvnANIZ9/fRwD/qVD4frvMUKJjt9DVPOXnhWoOoWkoMiXnwg== X-Microsoft-Exchange-Diagnostics: 1; CY4PR03MB2549; 25:BuF+loBCgmjbQ1vwQaMdfvyf17NJb11ek+O8lu/PYzTiqWiO8MqRbXxBL3b2KQHAWJf4EWWxi8i1iCKIWkx6sE+hePleCmhx7AkvQ2LQMO8wqLou8yDI89u3Zveimxa7+DX+e8nnSoblIpnRInIfZux9FVtY0MZwypiJp/HRkD+VlX0OAONeW/fcB7OiCBeDYGRh6uZkLQCA/2BoPB5BDy/vroSDrcmj9oABRfMN4V0gEDJn6m7WBKz1DTl4r15kuMpmjdrjoIV6i8ZIioksaHNtA+hSuGTB3r8Jej+N32UNS8bke7aPiFzAhxCsQW39FciPVvLd1dkrF++ToL0frTocjn2Np83Ryiqd7n1+iZaIsPXRgdfirPcFWzYhgNDznzcOhz7P8RMy6GSADL3HCYqH/DwTyaZn4kveNP5WvcLUiCxuQcivS2SPAAY0NNE8vIHD7WMS/45a1xgrJS077R4xTDwz6h9d7ueQVpEc5lKQ/L8ogKvgCs9WDSSmtmEmREml59d6T4GNDommPQfmzumohUBkKiGQkwrFaFaGcak7OiqboKICy0aZeadpRMD9T9QrRm91rXgzHh+z41b9kl4xitWfultUeaTrBtN+qUIAdvsK/B/vOOP4BOX+3kFU+2abZCZhaeb56E0XzfDj/a9TSs0YDtB7dU8CpKiHegjH71EPB0TIGLL/rJo6W3emsCt94gLeYt0apGRhtFPQS/Z4bfTn9pPo2qLP7DdnFjae/kfWYV+Z9wvrCrSpJTsUpPzIE7KDq1YZtrS7Sn/Gy8JLu2+Ce6xbGPhl9Qm9O0KsA5XuC48HDfPUq+bkL1aL X-Microsoft-Exchange-Diagnostics: 1; CY4PR03MB2549; 31:UFRpf/WuxX7kJtKAX0IUH7iatCQWii1N8ti35mEEud/J8iFwJM96T/7ivx4HKt0M8hnt4KVZ4ZPhLsJovDjCCdzvdoN/zwV6vNq0DorMCdE1PZ/hCXpqPLxCOiDdRAKIsabUC8xAHxJQUZHiDFjOQ1n3J3VmgopKKCn1vll3vC71n3gheN4uPhNi8M1qUFcsgt3sOYJhT0y9aKT4Vx8OKuKDilthQy8xl0Arajn9H2nksom9sxkbkQK7OZP9WrhkFC7/BPDKRa9cXurSy0+N0w==; 20:IuIz+0GHmngk/d2pjuIe1lfmQk1j2HSUDPRx5vbs2fBLjXWFyiw2IKSvgy/VWggVkNUmV35t+RX0wncpnS4u8bTGjtMfVCFaVkIlZi8c048fdLLMHZ8YY/v/6IhECNlLb8VZ4rFR21N1y7z1plNIR1CAAUTslX+unA1KPpQmJyq98HLfeA2lW+BZubZQUsQP+lGDU3xvtj8ER7NzmV+ynMpFLC2vj5OxJ0xwvtBUD5LXkhYdZAv3IVElpe3fhNr2bjgCAbZ41TSiV3TeLPtnc2s71FG3Dpf7cz5R1pX3bAyTb6yIdfTfgnPYt5z+2XdnZrD9x+IhMG7tnZ3X9pV4G8aWsLsOL4uAoEQ7b5dP0BE+kU19jyIOQvU4ApB1nvw1Qe3g1Yr7WRSo/W4slEV+dTDpvlZerte45SP0xDRrcaA/bxI+g4FN3LuxbH6Gfrl2HQppf7eVuSEOw+fuZq/R8OevzQUg3TrT9XtT7yhDbmxbCbxY1QnHtb3pAYnaaVJd X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(158342451672863); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040375)(601004)(2401047)(5005006)(8121501046)(3002001)(10201501046)(6055026)(6041248)(20161123560025)(20161123562025)(20161123564025)(20161123555025)(6047074)(6072148); SRVR:CY4PR03MB2549; BCL:0; PCL:0; RULEID:; SRVR:CY4PR03MB2549; X-Microsoft-Exchange-Diagnostics: 1; CY4PR03MB2549; 4:EcR5z46fCxa7PhQdILepIjcS7BYzUJD3tErony0rsOg8kICaZsOmBjzljgVxI37f8Z8vPbA/B9cidJxKtKJPwOH3y2Lys49LZC6NL/KnyO3RiSva8XCnVgkviuUQDqotnZYEiWgvbjen3LvEomMOt3NNO+Q7XUk1LNtzlfyPJiF6FAbJhRebTgFsIJuJWz/O+UpGWq5c52B3ASpn+zWIhlFTGCe97NZxRIBNbHKckaLcfzLSU8WjnbbrTukFJEIfLIEKZ6yQrLhQ8y/UpHrRt9sYh2QjsTaQkgVcIfGSiERn6e2Rr0SdlgRyDLS29mQjcnLUreYtkDR+xJ/LdaiIgMFyrWUJaWRXEG/0fWocqpF8o+tPVayh1GW/vk4gPcnVZyRkinzEAihc7CVkNCP8+qmXafEt1YroP2e6CmaWCBLxfSNcivPkSsocr16QwbbP9tb/Smskf36LimvoWMyR/Fb14vAZUdkvYKGSXiaiW+8cxJWtc6L8WuN7PMBhgNgDLGEtfmWJ9PwmXCJFZrR0FzR6YaKqWUHn8tuepq60Hj/XnvsrfTND69ghPOqZCW09xffx2NeHgWBIeZNUT6iMTqw+gBcVCcVA5z2XPfjM5yeJ5wFwllu3tTcr7PSwAye00xy2yf6hmtHcWee4eqqAlfsD7ijzqzv+OWR+43wdvrY= X-Forefront-PRVS: 01480965DA X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(4630300001)(6009001)(7916002)(69234005)(199003)(189002)(50466002)(92566002)(101416001)(86362001)(33646002)(47776003)(48376002)(2950100002)(6916009)(106356001)(575784001)(105586002)(6666003)(50986999)(42186005)(39860400001)(39850400001)(39840400001)(86612001)(76176999)(2361001)(110136003)(2351001)(450100001)(189998001)(5660300001)(10090500001)(5003940100001)(10290500002)(38730400001)(5005710100001)(8676002)(6116002)(36756003)(107886002)(39410400001)(733004)(7846002)(2906002)(39450400002)(6486002)(7736002)(50226002)(68736007)(305945005)(81156014)(97736004)(81166006); DIR:OUT; SFP:1102; SCL:1; SRVR:CY4PR03MB2549; H:ubuntu-vm.corp.microsoft.com; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: microsoft.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; CY4PR03MB2549; 23:oHU02YpEIKmi3O5VbjXtz5Ge/wpkCHhu+AJPlBc81?= =?us-ascii?Q?vR2CDKpqxy9wwUkLuZrvvdntYIYvHnXHrkK7stM3hnKVezQeasATX3jYe2gM?= =?us-ascii?Q?ZSe7EvDI4+pXBx+L0rrjhOCV57BGYMN3/4ucl9KxJNootTglcsGT57q9YpAE?= =?us-ascii?Q?la59Mw8lYRqRv1gSMfMusJc957XcjVOSFez/yNtZq+VFHBIpHAwa8Zniaosl?= =?us-ascii?Q?jFQHgif/WnCAkboTAE4MRVvPJ2W8nWZU6Xpy+JTbh+EkvMQLA+ZZMiqiWqHy?= =?us-ascii?Q?Ut9ubQGxw+eVXgPxNKhjvUHjwcXUheL8yPkY9qfQAqbTxv/4/7c2f0tIjvI5?= =?us-ascii?Q?CANpagSqePhfDJpu9Wgwe/DyE3cfhI9lDFn8x5ixLofF9NbUI9pOT/0/4ikR?= =?us-ascii?Q?w7Ex1Pcyp5FuEBKlBvznCuwLJr54psn2IVWeLAdzXulegPULpmydnnmPIZNy?= =?us-ascii?Q?W0QDvkJ3Ok/eNxau18zZxsgnmMib5hso22dLWVzbflnaq1Se17ayXUR+5brz?= =?us-ascii?Q?xnwIj5kUM76n47VKd8d4MJm66GPpfleUfzEmbdDuBlkGJfsQTJl8348GOiBH?= =?us-ascii?Q?/6YxGrkB0yHXGg6FuvoWVB35FJePE+303+sNOqusLgfprkt1xRNeHB6JfcVm?= =?us-ascii?Q?l0LixfwojzlNZRyHcCgdZHHLrpnC1BHaOL+8QCGPN/4oPAzdBGqVhD30/aaD?= =?us-ascii?Q?8o2pA1b+2DpItGwLbPsYa58lSbCTmjgUKysbw1OBh7HJ7nt/EzcBQIOtfL+w?= =?us-ascii?Q?4b9FqrEhYSZXVoe+IMTaSQTgHkoVM+E8EAdORLR+CPkUSkxbJCLUvOWAiBFL?= =?us-ascii?Q?fQzjyQFV+mDn+6tK/3nPygwlNUz8PGpUDigGmUbK2v5ZS+rzffmuFrrHdTRG?= =?us-ascii?Q?HoR5OQeF2j46iiA+ma8kKUYeQdnAvUo+1Ob4iB02sKUzvaNGMTctHDt2C6KL?= =?us-ascii?Q?tnPyRAmboAjawhxwnyQlvL3M3f9AODkTJHEwYh6W3XMgbJydw9SIU1Le4fBt?= =?us-ascii?Q?9dViO+qFXVzcIaOEyM0zbRHmsVQuQQucwgS6fzjQFTjd9Yc6YxU4w4zMzYAM?= =?us-ascii?Q?tXSXTz/JsaACo6YCtNAp6o6WprAjXoZb+9Ja75aQhYF2U9Uhk8iJM7BtbJau?= =?us-ascii?Q?Naw1cYdL/f68Xi//ETdb8ST5bYveIriQ5xDlla9CAUMsd9wVV1Y7I2buGW/n?= =?us-ascii?Q?2MVli7vJ79k+RVGwpT5L+UCtGiWSYEFm9KHWNEYy9aJB6sA7vQ7D86kdyo6s?= =?us-ascii?Q?qBdjCVHqC2iCF7h1ClUF+1Z5S52sTmLZDHO3uRO0czZZw6h9qp8znYaFAWwY?= =?us-ascii?Q?V4x7b5HUAAbK3aOxleETf0Y0DuD+mzqL+69RTB6myUr?= X-Microsoft-Exchange-Diagnostics: 1; CY4PR03MB2549; 6:7dX6kGD51s9iO1ukhiYug1tDmKRBrHTCbhTyPZiAUzpzthz2eQtZ7TblpIYneqpCEF/aAuws4DejeSg8Z5qf+VRfStWfRIgN89YBIn6hzkktmRTjUGVHo/mv9kRYrNYXPmTwy/bXDm4i9hhUr57vFRyi4oeZmu6Zv34TUw4nPD9qfKE4DMWd2eJCqYVu/Xei7qXr6nx8HnzjVL0XL54osMaT0lVYQBtxyDqkaKKaDTYeMEggHvjJsofDbs4rOyiWTol4vUDeA9kf/s/2/AiuvgnI5CrEu6SmE2FRja3hT9gWDYNZyqL5uQ2LiPWKU6RuZYvcqc2ZWZdMoc5rzWJgbc8L5nS6VPsRuAvlUWmzNdIFR2xbfj3ni3R5O7YlhRICXqMVWbsRCF25XetiwPew8IA6P/Cwh/zmVvAUc5EefnpaUoKkEUMBRTyB71mvjdU3rP97Hb/9kymLZ9Gh0jEWFw==; 5:RVdQ0nk4RgDmSty1wOkdYIKPy2R7lCTmLQepg4nW5nCHPOOBIAxqgfuE21ypSXEO/w7NXwrPCxaotPIUzpUOo67kkT1Cy2hqqnKV808GP7yCAgiNYhF0oQTPp9alzBp6nQF3Ugs0lFFdhp25l1KIAnX72/6xQejmu7sLHPf3UOc=; 24:4S8VXa89a0VpfFpJCmb1Y/Mny1IOldHpxUM8fMnQk6zTht9hp3Lf3odmW5dwcraMu5kB6eCLz+U4uFl64qL2+scYvJ3yMSU6WkZv9uztGh4= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; CY4PR03MB2549; 7:RVIQa1ImTbU0yvQqlYB/DFzPgwwGRQadmkDzIA1pOv/LQdgZJffNiEaYPwPgok1Ggp1Fo85gWOqFSolx45rxsvvuuv5nLe0WIkthkT32Obv2T5LwzCSTpYliQSsH3RujCaYLjX2KWiV3P8vKFNuL97CzsZ5i4DZsro/y3X9s7bzsP0voiaylhXAxwdy14E5Z7hnwu1f1U3bjHFkMaAyDsSMGFpOCloe3buTeqHn5/c2HZdg+gUdgoMRnpg9SzUxlkFike2QHklpJa4CIhlYuYXaRfDZO2HIawMuabnxN6LO2qN21uMEcXEkaA472Wsa1AoBz/H41KpS0EV9GGwmh7VJWrHGppJoYzdkWoiwy6exUQBOmZ20uD3qyqyvuAfSSdLFdOga5eKv45S4Jvw5FOThmoph7t1UzHR6lVowGmth3xu3RG+8t/rQFWrAIus+M39j4QGKTEDOEjEVrP59Mqw== X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 06 Dec 2016 22:02:48.8923 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR03MB2549 Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This change allows to encrypt packets if it is required by a server for SMB sessions or tree connections. Signed-off-by: Pavel Shilovsky --- fs/cifs/cifsencrypt.c | 13 ++- fs/cifs/cifsglob.h | 2 + fs/cifs/cifsproto.h | 2 +- fs/cifs/connect.c | 4 +- fs/cifs/smb2ops.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.h | 5 +- fs/cifs/smb2proto.h | 3 + fs/cifs/smb2transport.c | 41 +++++++- 8 files changed, 317 insertions(+), 10 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 3a0aaf0..96e8a75 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -34,6 +34,7 @@ #include #include #include +#include static int cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server) @@ -870,7 +871,7 @@ calc_seckey(struct cifs_ses *ses) } void -cifs_crypto_shash_release(struct TCP_Server_Info *server) +cifs_crypto_secmech_release(struct TCP_Server_Info *server) { if (server->secmech.cmacaes) { crypto_free_shash(server->secmech.cmacaes); @@ -892,6 +893,16 @@ cifs_crypto_shash_release(struct TCP_Server_Info *server) server->secmech.hmacmd5 = NULL; } + if (server->secmech.ccmaesencrypt) { + crypto_free_aead(server->secmech.ccmaesencrypt); + server->secmech.ccmaesencrypt = NULL; + } + + if (server->secmech.ccmaesdecrypt) { + crypto_free_aead(server->secmech.ccmaesdecrypt); + server->secmech.ccmaesdecrypt = NULL; + } + kfree(server->secmech.sdesccmacaes); server->secmech.sdesccmacaes = NULL; kfree(server->secmech.sdeschmacsha256); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 8ec9e1a..9433a9b 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -136,6 +136,8 @@ struct cifs_secmech { struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */ struct sdesc *sdeschmacsha256; /* ctxt to generate smb2 signature */ struct sdesc *sdesccmacaes; /* ctxt to generate smb3 signature */ + struct crypto_aead *ccmaesencrypt; /* smb3 encryption aead */ + struct crypto_aead *ccmaesdecrypt; /* smb3 decryption aead */ }; /* per smb session structure/fields */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index f87d1d6..117d1df 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -444,7 +444,7 @@ extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *, const struct nls_table *); extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *); extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); -extern void cifs_crypto_shash_release(struct TCP_Server_Info *); +extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server); extern int calc_seckey(struct cifs_ses *); extern int generate_smb30signingkey(struct cifs_ses *); extern int generate_smb311signingkey(struct cifs_ses *); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5aaf7b1..46124a0 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2148,7 +2148,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) server->tcpStatus = CifsExiting; spin_unlock(&GlobalMid_Lock); - cifs_crypto_shash_release(server); + cifs_crypto_secmech_release(server); cifs_fscache_release_client_cookie(server); kfree(server->session_key.response); @@ -2267,7 +2267,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) return tcp_ses; out_err_crypto_release: - cifs_crypto_shash_release(tcp_ses); + cifs_crypto_secmech_release(tcp_ses); put_net(cifs_net_ns(tcp_ses)); diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index ef8b2a8..eda9d4c 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "cifsglob.h" #include "smb2pdu.h" #include "smb2proto.h" @@ -1547,6 +1549,256 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile) return !cfile->invalidHandle; } +static void +fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq) +{ + struct smb2_sync_hdr *shdr = + (struct smb2_sync_hdr *)old_rq->rq_iov[1].iov_base; + unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base); + + memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr)); + tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM; + tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len); + tr_hdr->Flags = cpu_to_le16(0x01); + get_random_bytes(&tr_hdr->Nonce, SMB3_AES128CMM_NONCE); + memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8); + inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - 4); + inc_rfc1001_len(tr_hdr, orig_len); +} + +static struct scatterlist * +init_sg(struct smb_rqst *rqst, u8 *sign) +{ + unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1; + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24; + struct scatterlist *sg; + unsigned int i; + unsigned int j; + + sg = kmalloc_array(sg_len, sizeof(struct scatterlist), GFP_KERNEL); + if (!sg) + return NULL; + + sg_init_table(sg, sg_len); + sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len); + for (i = 1; i < rqst->rq_nvec; i++) + sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base, + rqst->rq_iov[i].iov_len); + for (j = 0; i < sg_len - 1; i++, j++) { + unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz + : rqst->rq_tailsz; + sg_set_page(&sg[i], rqst->rq_pages[j], len, 0); + } + sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE); + return sg; +} + +struct cifs_crypt_result { + int err; + struct completion completion; +}; + +static void cifs_crypt_complete(struct crypto_async_request *req, int err) +{ + struct cifs_crypt_result *res = req->data; + + if (err == -EINPROGRESS) + return; + + res->err = err; + complete(&res->completion); +} + +/* + * Encrypt or decrypt @rqst message. @rqst has the following format: + * iov[0] - transform header (associate data), + * iov[1-N] and pages - data to encrypt. + * On success return encrypted data in iov[1-N] and pages, leave iov[0] + * untouched. + */ +static int +crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) +{ + struct smb2_transform_hdr *tr_hdr = + (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base; + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24; + struct cifs_ses *ses; + int rc = 0; + struct scatterlist *sg; + u8 sign[SMB2_SIGNATURE_SIZE] = {}; + struct aead_request *req; + char *iv; + unsigned int iv_len; + struct cifs_crypt_result result = {0, }; + struct crypto_aead *tfm; + unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize); + + init_completion(&result.completion); + + ses = smb2_find_smb_ses(server, tr_hdr->SessionId); + if (!ses) { + cifs_dbg(VFS, "%s: Could not find session\n", __func__); + return 0; + } + + rc = smb3_crypto_aead_allocate(server); + if (rc) { + cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); + return rc; + } + + tfm = enc ? server->secmech.ccmaesencrypt : + server->secmech.ccmaesdecrypt; + rc = crypto_aead_setkey(tfm, enc ? ses->smb3encryptionkey : + ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE); + if (rc) { + cifs_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc); + return rc; + } + + rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE); + if (rc) { + cifs_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc); + return rc; + } + + req = aead_request_alloc(tfm, GFP_KERNEL); + if (!req) { + cifs_dbg(VFS, "%s: Failed to alloc aead request", __func__); + return -ENOMEM; + } + + if (!enc) { + memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE); + crypt_len += SMB2_SIGNATURE_SIZE; + } + + sg = init_sg(rqst, sign); + if (!sg) { + cifs_dbg(VFS, "%s: Failed to init sg %d", __func__, rc); + goto free_req; + } + + iv_len = crypto_aead_ivsize(tfm); + iv = kzalloc(iv_len, GFP_KERNEL); + if (!iv) { + cifs_dbg(VFS, "%s: Failed to alloc IV", __func__); + goto free_sg; + } + iv[0] = 3; + memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES128CMM_NONCE); + + aead_request_set_crypt(req, sg, sg, crypt_len, iv); + aead_request_set_ad(req, assoc_data_len); + + aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + cifs_crypt_complete, &result); + + rc = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req); + + if (rc == -EINPROGRESS || rc == -EBUSY) { + wait_for_completion(&result.completion); + rc = result.err; + } + + if (!rc && enc) + memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE); + + kfree(iv); +free_sg: + kfree(sg); +free_req: + kfree(req); + return rc; +} + +static int +smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, + struct smb_rqst *old_rq) +{ + struct kvec *iov; + struct page **pages; + struct smb2_transform_hdr *tr_hdr; + unsigned int npages = old_rq->rq_npages; + int i; + int rc = -ENOMEM; + + pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); + if (!pages) + return rc; + + new_rq->rq_pages = pages; + new_rq->rq_npages = old_rq->rq_npages; + new_rq->rq_pagesz = old_rq->rq_pagesz; + new_rq->rq_tailsz = old_rq->rq_tailsz; + + for (i = 0; i < npages; i++) { + pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); + if (!pages[i]) + goto err_free_pages; + } + + iov = kmalloc_array(old_rq->rq_nvec, sizeof(struct kvec), GFP_KERNEL); + if (!iov) + goto err_free_pages; + + /* copy all iovs from the old except the 1st one (rfc1002 length) */ + memcpy(&iov[1], &old_rq->rq_iov[1], + sizeof(struct kvec) * (old_rq->rq_nvec - 1)); + new_rq->rq_iov = iov; + new_rq->rq_nvec = old_rq->rq_nvec; + + tr_hdr = kmalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL); + if (!tr_hdr) + goto err_free_iov; + + /* fill the 1st iov with a transform header */ + fill_transform_hdr(tr_hdr, old_rq); + new_rq->rq_iov[0].iov_base = tr_hdr; + new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr); + + /* copy pages form the old */ + for (i = 0; i < npages; i++) { + char *dst = kmap(new_rq->rq_pages[i]); + char *src = kmap(old_rq->rq_pages[i]); + unsigned int len = (i < npages - 1) ? new_rq->rq_pagesz : + new_rq->rq_tailsz; + memcpy(dst, src, len); + kunmap(new_rq->rq_pages[i]); + kunmap(old_rq->rq_pages[i]); + } + + rc = crypt_message(server, new_rq, 1); + cifs_dbg(FYI, "encrypt message returned %d", rc); + if (rc) + goto err_free_tr_hdr; + + return rc; + +err_free_tr_hdr: + kfree(tr_hdr); +err_free_iov: + kfree(iov); +err_free_pages: + for (i = i - 1; i >= 0; i--) + put_page(pages[i]); + kfree(pages); + return rc; +} + +static void +smb3_free_transform_rq(struct smb_rqst *rqst) +{ + int i = rqst->rq_npages - 1; + + for (; i >= 0; i--) + put_page(rqst->rq_pages[i]); + kfree(rqst->rq_pages); + /* free transform header */ + kfree(rqst->rq_iov[0].iov_base); + kfree(rqst->rq_iov); +} + struct smb_version_operations smb20_operations = { .compare_fids = smb2_compare_fids, .setup_request = smb2_setup_request, @@ -1793,6 +2045,8 @@ struct smb_version_operations smb30_operations = { .dir_needs_close = smb2_dir_needs_close, .fallocate = smb3_fallocate, .enum_snapshots = smb3_enum_snapshots, + .init_transform_rq = smb3_init_transform_rq, + .free_transform_rq = smb3_free_transform_rq, }; #ifdef CONFIG_CIFS_SMB311 @@ -1881,6 +2135,9 @@ struct smb_version_operations smb311_operations = { .dir_needs_close = smb2_dir_needs_close, .fallocate = smb3_fallocate, .enum_snapshots = smb3_enum_snapshots, + .init_transform_rq = smb3_init_transform_rq, + .free_transform_rq = smb3_free_transform_rq, +}; }; #endif /* CIFS_SMB311 */ diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 35ff9fa..c03b252 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -134,11 +134,14 @@ struct smb2_pdu { __le16 StructureSize2; /* size of wct area (varies, request specific) */ } __packed; +#define SMB3_AES128CMM_NONCE 11 +#define SMB3_AES128GCM_NONCE 12 + struct smb2_transform_hdr { __be32 smb2_buf_length; /* big endian on wire */ /* length is only two or three bytes - with one or two byte type preceding it that MBZ */ - __u8 ProtocolId[4]; /* 0xFD 'S' 'M' 'B' */ + __le32 ProtocolId; /* 0xFD 'S' 'M' 'B' */ __u8 Signature[16]; __u8 Nonce[16]; __le32 OriginalMessageSize; diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index f2d511a..7d30b75 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -56,6 +56,8 @@ 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, struct TCP_Server_Info *srv); +extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server, + __u64 ses_id); extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src); @@ -97,6 +99,7 @@ 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); /* * SMB2 Worker functions - most of protocol specific implementation details diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 93b2775..3caa11d 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "smb2pdu.h" #include "cifsglob.h" #include "cifsproto.h" @@ -114,14 +115,14 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server) return 0; } -static struct cifs_ses * -smb2_find_smb_ses(struct smb2_sync_hdr *shdr, struct TCP_Server_Info *server) +struct cifs_ses * +smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id) { struct cifs_ses *ses; spin_lock(&cifs_tcp_ses_lock); list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { - if (ses->Suid != shdr->SessionId) + if (ses->Suid != ses_id) continue; spin_unlock(&cifs_tcp_ses_lock); return ses; @@ -141,7 +142,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base; struct cifs_ses *ses; - ses = smb2_find_smb_ses(shdr, server); + ses = smb2_find_smb_ses(server, shdr->SessionId); if (!ses) { cifs_dbg(VFS, "%s: Could not find session\n", __func__); return 0; @@ -358,7 +359,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base; struct cifs_ses *ses; - ses = smb2_find_smb_ses(shdr, server); + ses = smb2_find_smb_ses(server, shdr->SessionId); if (!ses) { cifs_dbg(VFS, "%s: Could not find session\n", __func__); return 0; @@ -618,3 +619,33 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) return mid; } + +int +smb3_crypto_aead_allocate(struct TCP_Server_Info *server) +{ + struct crypto_aead *tfm; + + if (!server->secmech.ccmaesencrypt) { + tfm = crypto_alloc_aead("ccm(aes)", 0, 0); + if (IS_ERR(tfm)) { + cifs_dbg(VFS, "%s: Failed to alloc encrypt aead\n", + __func__); + return PTR_ERR(tfm); + } + server->secmech.ccmaesencrypt = tfm; + } + + if (!server->secmech.ccmaesdecrypt) { + tfm = crypto_alloc_aead("ccm(aes)", 0, 0); + if (IS_ERR(tfm)) { + crypto_free_aead(server->secmech.ccmaesencrypt); + server->secmech.ccmaesencrypt = NULL; + cifs_dbg(VFS, "%s: Failed to alloc decrypt aead\n", + __func__); + return PTR_ERR(tfm); + } + server->secmech.ccmaesdecrypt = tfm; + } + + return 0; +}