From patchwork Mon Oct 23 21:40:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Biggers X-Patchwork-Id: 10023177 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 83D46603FA for ; Mon, 23 Oct 2017 21:42:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 75BCC2894F for ; Mon, 23 Oct 2017 21:42:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6A9062893D; Mon, 23 Oct 2017 21:42:44 +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.3 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=unavailable 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 D36E928938 for ; Mon, 23 Oct 2017 21:42:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932253AbdJWVmn (ORCPT ); Mon, 23 Oct 2017 17:42:43 -0400 Received: from mail-it0-f67.google.com ([209.85.214.67]:44226 "EHLO mail-it0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932148AbdJWVmZ (ORCPT ); Mon, 23 Oct 2017 17:42:25 -0400 Received: by mail-it0-f67.google.com with SMTP id n195so6818241itg.1; Mon, 23 Oct 2017 14:42: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=4fk93GRnVqCBDf1H2gOV6iWZyAWe9dS54rgSGmwqAXM=; b=pLvt1dOGDpggKyTDMdVd70KKoDZFtldFssI//VPvuHYNWj3HVjWH3Loqvvgqo2E2dL kH/jlYD58xtuzhB0ACU2q4SDXPjP5tRKNCoENhWSaqH2ZTtdarHl7MHSTWn0IXmtZHFi Tn+/dilPkhNL8e7A+A6+DTBMYr4HRNu/rHqXvqDk2dajZiQEE5p0H9gsWtOpnJ1MTrBh cY9vPkT8Gjkcanuxeuq50w1Km8eF7Ymho9DMFh9EYq2Nhz/GSonCUFIxnyLcsCAph7+f eTsqXgBr4B9z3XN9TnPaZYYoHNA1GjcnVNDpab2qse1TBS1e/ZNmMfIvR8i/6HgYmRHL 8P7g== 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=4fk93GRnVqCBDf1H2gOV6iWZyAWe9dS54rgSGmwqAXM=; b=Wlk4agmB/jI25vg8hcTro3az69jDM+P//hFDorzaPiJ0LSt20KQPoHgiX1FPhGEN3w vKo1C1rtYSPAFo5WnB+NygSVDckhJJ9dQnCNeTRMNw26i4HvwBbBp8zDoshJclfsNwAD 89dDkZkD+Gdh+6ni6QZcwn0ahdoUHWvjrSGdfOKDvydoTUGuvqqHigE/70P8gmxKWbOY 34VhWJNp7Z7cZF+AWS3sYJy3Y9EC5XKm+OE6Ltt+ALoKte9dsDDDEUGXvU/5QTdsOESo yG9aMvrYObVUFIJShb52Z076inx+WlUZ+14/6yq/LTQRa9lwI0UK+/LJ9NFIWpruAZ3y PtFw== X-Gm-Message-State: AMCzsaVFOhaxM+I5eeB0JdjB2h8Io7p3X1+mI0FGOwFyIbukXlXf9N17 +FX85Urz2fPtS7rkl8O9IeTJIM2n X-Google-Smtp-Source: ABhQp+TNQdKeR5heSfEVv/atoiJJ15KMNOPZCI1va3YqPUNGI4lnWa2LHZPjRMIsgM2PpxZrLm6kbw== X-Received: by 10.36.54.210 with SMTP id l201mr11073461itl.0.1508794944157; Mon, 23 Oct 2017 14:42:24 -0700 (PDT) Received: from ebiggers-linuxstation.kir.corp.google.com ([100.66.175.88]) by smtp.gmail.com with ESMTPSA id i63sm3558482ioi.68.2017.10.23.14.42.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 14:42:23 -0700 (PDT) From: Eric Biggers To: linux-fscrypt@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org, linux-f2fs-devel@lists.sourceforge.net, linux-mtd@lists.infradead.org, linux-api@vger.kernel.org, keyrings@vger.kernel.org, "Theodore Y . Ts'o" , Jaegeuk Kim , Gwendal Grignou , Ryo Hashimoto , Sarthak Kukreti , Nick Desaulniers , Michael Halcrow , Eric Biggers Subject: [RFC PATCH 11/25] fscrypt: add FS_IOC_GET_ENCRYPTION_KEY_STATUS ioctl Date: Mon, 23 Oct 2017 14:40:44 -0700 Message-Id: <20171023214058.128121-12-ebiggers3@gmail.com> X-Mailer: git-send-email 2.15.0.rc0.271.g36b669edcc-goog In-Reply-To: <20171023214058.128121-1-ebiggers3@gmail.com> References: <20171023214058.128121-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 Add a new ioctl, FS_IOC_GET_ENCRYPTION_KEY_STATUS. Given a key specified by 'struct fscrypt_key_specifier' (the same way a key is specified for the ioctls which add and remove keys), it returns status information in a 'struct fscrypt_get_key_status_args'. The main motivation for this is that applications need to be able to check whether an encrypted directory is "unlocked" or not, so that they can add the key if it is not, and avoid adding the key (which may involve prompting the user for a passphrase) if it already is. It's possible to use some workarounds such as checking whether opening a regular file fails with ENOKEY, or checking whether the filenames "look like gibberish" or not. However, no workaround is usable in all cases. It's also not a simple matter of locked/unlocked anymore because we also have a partially locked state, where FS_IOC_REMOVE_ENCRYPTION_KEY has removed the secret but some encrypted files are still in use. This difference can be important for applications. Moreover, after later patches some applications will also need a way to determine whether a key was added by the current user vs. by some other user. Ideally we'd have been able to use keyctl_search() to check whether a key is present or not, rather than introducing a new ioctl. However, even if the keyrings permission system was fixed to allow granting read-only access to a keyring (currently the "Search" permission allows keyctl_invalidate()), it still wouldn't work out because the fscrypt master keys can be in states other than just present/absent, as described above. Moreover, we'd still have to at least add an ioctl which retrieves the ID of ->s_master_keys. /proc/keys cannot really be the API either, since reading /proc/keys involves iterating through all keys on the system and is primarily meant as a debugging interface. We also don't necessarily want to grant everyone VIEW access to all the fscrypt keys as that would imply everyone being able to list them as well. Therefore, a new ioctl to get an fscrypt key's status seems like the best solution. It is also consistent with the ioctls to add and remove keys. Signed-off-by: Eric Biggers --- fs/crypto/keyinfo.c | 64 +++++++++++++++++++++++++++++++++++++++++ include/linux/fscrypt_notsupp.h | 6 ++++ include/linux/fscrypt_supp.h | 1 + include/uapi/linux/fscrypt.h | 17 +++++++++++ 4 files changed, 88 insertions(+) diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index dc2697cf9114..4052030a4c96 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -566,6 +566,70 @@ int fscrypt_ioctl_remove_key(struct file *filp, const void __user *uarg) } EXPORT_SYMBOL_GPL(fscrypt_ioctl_remove_key); +/* + * Retrieve the status of an fscrypt master encryption key. + * + * We set ->status to indicate whether the key is absent, present, or + * incompletely removed. "Incompletely removed" means that the master key + * secret has been removed, but some files which had been unlocked with it are + * still in use. This field allows applications to easily determine the state + * of an encrypted directory without using a hack such as trying to open a + * regular file in it (which can confuse the "incompletely removed" state with + * absent or present). + * + * Note: this ioctl only works with keys added to the filesystem-level keyring. + * It does *not* work with keys added via the old mechanism which involved + * process-subscribed keyrings. + */ +int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg) +{ + struct super_block *sb = file_inode(filp)->i_sb; + struct fscrypt_get_key_status_args arg; + struct key *key; + struct fscrypt_master_key *mk; + int err; + + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + + if (memchr_inv(arg.reserved1, 0, sizeof(arg.reserved1))) + return -EINVAL; + + if (!valid_key_spec(&arg.key_spec)) + return -EINVAL; + + arg.reserved2 = 0; + memset(arg.reserved3, 0, sizeof(arg.reserved3)); + + key = find_master_key(sb, &arg.key_spec); + if (IS_ERR(key)) { + if (key != ERR_PTR(-ENOKEY)) + return PTR_ERR(key); + arg.status = FSCRYPT_KEY_STATUS_ABSENT; + err = 0; + goto out; + } + mk = key->payload.data[0]; + down_read(&key->sem); + + if (!is_master_key_secret_present(&mk->mk_secret)) { + arg.status = FSCRYPT_KEY_STATUS_INCOMPLETELY_REMOVED; + err = 0; + goto out_release_key; + } + + arg.status = FSCRYPT_KEY_STATUS_PRESENT; + err = 0; +out_release_key: + up_read(&key->sem); + key_put(key); +out: + if (!err && copy_to_user(uarg, &arg, sizeof(arg))) + err = -EFAULT; + return err; +} +EXPORT_SYMBOL_GPL(fscrypt_ioctl_get_key_status); + static void derive_crypt_complete(struct crypto_async_request *req, int rc) { struct fscrypt_completion_result *ecr = req->data; diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h index 92616bfdc294..bd60f951b06a 100644 --- a/include/linux/fscrypt_notsupp.h +++ b/include/linux/fscrypt_notsupp.h @@ -95,6 +95,12 @@ static inline int fscrypt_ioctl_remove_key(struct file *filp, return -EOPNOTSUPP; } +static inline int fscrypt_ioctl_get_key_status(struct file *filp, + void __user *arg) +{ + return -EOPNOTSUPP; +} + static inline int fscrypt_get_encryption_info(struct inode *inode) { return -EOPNOTSUPP; diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index 620ca4f1bafe..ace278056dbe 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -44,6 +44,7 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *, /* keyinfo.c */ extern int fscrypt_ioctl_add_key(struct file *filp, void __user *arg); extern int fscrypt_ioctl_remove_key(struct file *filp, const void __user *arg); +extern int fscrypt_ioctl_get_key_status(struct file *filp, void __user *arg); extern int fscrypt_get_encryption_info(struct inode *); extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *); diff --git a/include/uapi/linux/fscrypt.h b/include/uapi/linux/fscrypt.h index 5d02f138668c..9da153df238a 100644 --- a/include/uapi/linux/fscrypt.h +++ b/include/uapi/linux/fscrypt.h @@ -72,11 +72,28 @@ struct fscrypt_remove_key_args { struct fscrypt_key_specifier key_spec; }; +/* Struct passed to FS_IOC_GET_ENCRYPTION_KEY_STATUS */ +struct fscrypt_get_key_status_args { + /* input */ + __u64 reserved1[3]; + struct fscrypt_key_specifier key_spec; + + /* output */ + __u32 status; +#define FSCRYPT_KEY_STATUS_ABSENT 1 +#define FSCRYPT_KEY_STATUS_PRESENT 2 +#define FSCRYPT_KEY_STATUS_INCOMPLETELY_REMOVED 3 + __u32 reserved2; + + __u64 reserved3[7]; +}; + #define FS_IOC_SET_ENCRYPTION_POLICY _IOR( 'f', 19, struct fscrypt_policy) #define FS_IOC_GET_ENCRYPTION_PWSALT _IOW( 'f', 20, __u8[16]) #define FS_IOC_GET_ENCRYPTION_POLICY _IOW( 'f', 21, struct fscrypt_policy) #define FS_IOC_ADD_ENCRYPTION_KEY _IOWR('f', 22, struct fscrypt_add_key_args) #define FS_IOC_REMOVE_ENCRYPTION_KEY _IOR( 'f', 23, struct fscrypt_remove_key_args) +#define FS_IOC_GET_ENCRYPTION_KEY_STATUS _IOWR('f',24, struct fscrypt_get_key_status_args) /**********************************************************************/