From patchwork Fri Mar 23 19:23:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Biggers X-Patchwork-Id: 10305493 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 D559560386 for ; Fri, 23 Mar 2018 19:31:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C42C32912B for ; Fri, 23 Mar 2018 19:31:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B87382912D; Fri, 23 Mar 2018 19:31:31 +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_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, 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 31F032912B for ; Fri, 23 Mar 2018 19:31:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752259AbeCWTb1 (ORCPT ); Fri, 23 Mar 2018 15:31:27 -0400 Received: from mail-pf0-f196.google.com ([209.85.192.196]:36283 "EHLO mail-pf0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752573AbeCWTbY (ORCPT ); Fri, 23 Mar 2018 15:31:24 -0400 Received: by mail-pf0-f196.google.com with SMTP id 68so5107311pfx.3; Fri, 23 Mar 2018 12:31:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=XPrBtGPuSdYFvYTeaUVRypIuMEFyfWvqaYYVpfbSn9M=; b=Lk3xG9axEiNgY4ly/DzjT+2RKNOgKM2TXIm7pihQJEoLBkX4ToJ625wNsQ54Azj4bx AiCjdRNHFQ+OJbVvdEMdoqQm1OSAmLo8yEEgbyqORRO8P6kX08IudWzgBoualcjaEmzc usuTObozut6Rr0d/N0mL9jasDtpm1Ca0YjYhcOtdxadmQDg6768MkGRMwDUSGoVp/XXj yhhUDX5t/UPBgpd8TN556SF7re7GSrScWzDd2G2VYi04feFxH3ZiPBeZxJCtkd5hSOU8 WjW4pTZOijb5/aWl16A0vBqD8YVuZJI+8SpLJsBjrIIe5z48rhlwKA3xvZ+8Cg8L5BR4 xmQw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=XPrBtGPuSdYFvYTeaUVRypIuMEFyfWvqaYYVpfbSn9M=; b=lUmik1Q0+7AQQKWGW+0nSFnJhNT9sMGWJHFy5cg+r3vQUuzjDqDwy8K7ne892iFKFB fBEw5bQwAbxj1Vf9kNquLdXWpLpXjldYFIOCMzsXVkVziwT3NKmQQq/jHf/KyCl6PDMN G2n6T4glpGwQODzgKBDw6FARgpHCAOromXaKGlpnmo5BJiLpmLPPiyo4oea5QMoZ5lNg CCWHQ84QcLb5b8pyx6uqbzsT3BReZntd8iqUCOQeEil80FOkDW8Erz5hJY8UMxcm8AHU o5zjMPuJ9FOvYx4vDWVfxo9dE/pZq0Xdz3YE7KgPBxMyVK7kXA6Isz85S89vXjgEp6dL ofbg== X-Gm-Message-State: AElRT7E1xpdbwSlK4kcCawWkAkVIP+6A5+MXZmB1/ZKSZTtFQ1IvNfn6 9kQZ6G+0kFvBAFKLKsBttZ9dAZF3 X-Google-Smtp-Source: AG47ELtT64e1AyAjvTWDf2eCgN9bbCYXNnUX75XtfHT4jCqMB4S6CPA5RRH8WlugSh1cKtTYfEVOWw== X-Received: by 10.98.102.131 with SMTP id s3mr18347026pfj.89.1521833483380; Fri, 23 Mar 2018 12:31:23 -0700 (PDT) Received: from ebiggers-linuxstation.kir.corp.google.com ([2620:15c:17:3:dc28:5c82:b905:e8a8]) by smtp.gmail.com with ESMTPSA id x1sm20924545pfk.144.2018.03.23.12.31.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 23 Mar 2018 12:31:22 -0700 (PDT) From: Eric Biggers To: linux-fscrypt@vger.kernel.org, "Theodore Y . Ts'o" Cc: linux-ext4@vger.kernel.org, linux-f2fs-devel@lists.sourceforge.net, linux-mtd@lists.infradead.org, Jaegeuk Kim , Eric Biggers Subject: [PATCH 13/14] fscrypt: separate key lookup from key derivation Date: Fri, 23 Mar 2018 12:23:57 -0700 Message-Id: <20180323192358.95691-14-ebiggers3@gmail.com> X-Mailer: git-send-email 2.17.0.rc0.231.g781580f067-goog In-Reply-To: <20180323192358.95691-1-ebiggers3@gmail.com> References: <20180323192358.95691-1-ebiggers3@gmail.com> Sender: linux-fscrypt-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Eric Biggers Refactor the confusingly-named function 'validate_user_key()' into a new function 'find_and_derive_key()' which first finds the keyring key, then does the key derivation. Among other benefits this avoids the strange behavior we had previously where if key derivation failed for some reason, then we would fall back to the alternate key prefix. Now, we'll only fall back to the alternate key prefix if a valid key isn't found. This patch also improves the warning messages that are logged when the keyring key's payload is invalid. Signed-off-by: Eric Biggers --- fs/crypto/keyinfo.c | 122 +++++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 48 deletions(-) diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index 477e2d1fa04e..f00bf1437c3c 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -27,7 +27,7 @@ static struct crypto_shash *essiv_hash_tfm; * * Return: Zero on success; non-zero otherwise. */ -static int derive_key_aes(u8 deriving_key[FS_KEY_DERIVATION_NONCE_SIZE], +static int derive_key_aes(const u8 deriving_key[FS_KEY_DERIVATION_NONCE_SIZE], const struct fscrypt_key *source_key, u8 derived_raw_key[FS_MAX_KEY_SIZE]) { @@ -67,52 +67,88 @@ static int derive_key_aes(u8 deriving_key[FS_KEY_DERIVATION_NONCE_SIZE], return res; } -static int validate_user_key(struct fscrypt_info *crypt_info, - struct fscrypt_context *ctx, u8 *raw_key, - const char *prefix, int min_keysize) +/* + * Search the current task's subscribed keyrings for a "logon" key with + * description prefix:descriptor, and if found acquire a read lock on it and + * return a pointer to its validated payload in *payload_ret. + */ +static struct key * +find_and_lock_process_key(const char *prefix, + const u8 descriptor[FS_KEY_DESCRIPTOR_SIZE], + unsigned int min_keysize, + const struct fscrypt_key **payload_ret) { char *description; - struct key *keyring_key; - struct fscrypt_key *master_key; + struct key *key; const struct user_key_payload *ukp; - int res; + const struct fscrypt_key *payload; description = kasprintf(GFP_NOFS, "%s%*phN", prefix, - FS_KEY_DESCRIPTOR_SIZE, - ctx->master_key_descriptor); + FS_KEY_DESCRIPTOR_SIZE, descriptor); if (!description) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - keyring_key = request_key(&key_type_logon, description, NULL); + key = request_key(&key_type_logon, description, NULL); kfree(description); - if (IS_ERR(keyring_key)) - return PTR_ERR(keyring_key); - down_read(&keyring_key->sem); - - ukp = user_key_payload_locked(keyring_key); - if (!ukp) { - /* key was revoked before we acquired its semaphore */ - res = -EKEYREVOKED; - goto out; + if (IS_ERR(key)) + return key; + + down_read(&key->sem); + ukp = user_key_payload_locked(key); + + if (!ukp) /* was the key revoked before we acquired its semaphore? */ + goto invalid; + + payload = (const struct fscrypt_key *)ukp->data; + + if (ukp->datalen != sizeof(struct fscrypt_key) || + payload->size < 1 || payload->size > FS_MAX_KEY_SIZE) { + fscrypt_warn(NULL, + "key with description '%s' has invalid payload", + key->description); + goto invalid; } - if (ukp->datalen != sizeof(struct fscrypt_key)) { - res = -EINVAL; - goto out; + + if (payload->size < min_keysize || + payload->size % AES_BLOCK_SIZE != 0) { + fscrypt_warn(NULL, + "key with description '%s' is too short or is misaligned (got %u bytes, need %u+ bytes)", + key->description, payload->size, min_keysize); + goto invalid; } - master_key = (struct fscrypt_key *)ukp->data; - if (master_key->size < min_keysize || master_key->size > FS_MAX_KEY_SIZE - || master_key->size % AES_BLOCK_SIZE != 0) { - fscrypt_warn(NULL, "key size incorrect: %u", - master_key->size); - res = -ENOKEY; - goto out; + *payload_ret = payload; + return key; + +invalid: + up_read(&key->sem); + key_put(key); + return ERR_PTR(-ENOKEY); +} + +/* Find the master key, then derive the inode's actual encryption key */ +static int find_and_derive_key(const struct inode *inode, + const struct fscrypt_context *ctx, + u8 *derived_key, unsigned int derived_keysize) +{ + struct key *key; + const struct fscrypt_key *payload; + int err; + + key = find_and_lock_process_key(FS_KEY_DESC_PREFIX, + ctx->master_key_descriptor, + derived_keysize, &payload); + if (key == ERR_PTR(-ENOKEY) && inode->i_sb->s_cop->key_prefix) { + key = find_and_lock_process_key(inode->i_sb->s_cop->key_prefix, + ctx->master_key_descriptor, + derived_keysize, &payload); } - res = derive_key_aes(ctx->nonce, master_key, raw_key); -out: - up_read(&keyring_key->sem); - key_put(keyring_key); - return res; + if (IS_ERR(key)) + return PTR_ERR(key); + err = derive_key_aes(ctx->nonce, payload, derived_key); + up_read(&key->sem); + key_put(key); + return err; } static const struct { @@ -295,20 +331,10 @@ int fscrypt_get_encryption_info(struct inode *inode) if (!raw_key) goto out; - res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX, - keysize); - if (res && inode->i_sb->s_cop->key_prefix) { - int res2 = validate_user_key(crypt_info, &ctx, raw_key, - inode->i_sb->s_cop->key_prefix, - keysize); - if (res2) { - if (res2 == -ENOKEY) - res = -ENOKEY; - goto out; - } - } else if (res) { + res = find_and_derive_key(inode, &ctx, raw_key, keysize); + if (res) goto out; - } + ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); if (IS_ERR(ctfm)) { res = PTR_ERR(ctfm);