From patchwork Fri Jan 5 18:45:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Biggers X-Patchwork-Id: 10146945 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 484816137B for ; Fri, 5 Jan 2018 18:57:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 33CFF28537 for ; Fri, 5 Jan 2018 18:57:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 28BA82893A; Fri, 5 Jan 2018 18:57:39 +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 AC31F28939 for ; Fri, 5 Jan 2018 18:57:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752636AbeAES5h (ORCPT ); Fri, 5 Jan 2018 13:57:37 -0500 Received: from mail-it0-f67.google.com ([209.85.214.67]:45154 "EHLO mail-it0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752623AbeAES5f (ORCPT ); Fri, 5 Jan 2018 13:57:35 -0500 Received: by mail-it0-f67.google.com with SMTP id z6so2621092iti.4; Fri, 05 Jan 2018 10:57:34 -0800 (PST) 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=jhUukQPmTd3Zzwi4q5J8oYHS4KvEkxWzEKMFOc4BtgI=; b=LAS6c7agkRqaaeI47Cyk+HeIW8ye854J37cHqidjmpjFCjjApfk0+2f0MLH377Fs3d muBNdtYscD370PetSPnLl8BMcNlf5G+jnfiTFe/aRNEvwTKt/Hdx1I963rUrP6Ral9vV 2TFuhUZWy85B7Uep2LgO4uA07tEgqNuErIMFMGj53JZd8UOfEGJpSBbppH7KgaCYnE4o xIJBPrzRmIW37pgtywlVtEJGSylv3OASI0gdj9U++nzkJ42z1vs5rijZhYlL5jFZCwsl fOkFkA0WGA2ZNcL6wG4nPCaOqaSD0CgDOAtqNZtUxLmVjyODri72uUJCBo+s1yNMCCZ9 E6Ow== 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=jhUukQPmTd3Zzwi4q5J8oYHS4KvEkxWzEKMFOc4BtgI=; b=ZrMGZo/I8qrG/4OgAwOIVufW7ueZvAeNRS01eBzoeqHGQh9xGVlbOeIaFa0/IzaHgF sSrjgjhb83qmtzCBb1CO6Lspbl/55Of4d7s3t/Dh/6O20F2hWkwzkYD0g+4EcOKzOYM1 RE2baIo4nSFpSu0jEuEybq7eGKbZqtQ/aV7Ay2Uqoafbi4BmD4OzmO3cVu7yQDQYT1aZ fXMvdlnPS3On40jaFXAVlghhr/3sEH9Xy2fhC8OSKgXQSTuc7+66P2o7jLgvc7vAN4mB 7hG/sq9f8mR85N6D0dWBjBg23qQd9My1HRp0IVWH7bIxXuIB/RDuTCI4J8587gqLMbl1 BCWg== X-Gm-Message-State: AKGB3mLr1bHA4OTwvMlqwynOcTo7AW7Oj9E+3CKWkLU3ltDZib6aGU+h 5kqTITEiM5G25F/I9SjJFN9vszuA X-Google-Smtp-Source: ACJfBosC/u9WCCxy00GjDQVMb0Ndy/5UCFLfBxrY/aiOs5fM72NnfSCN/v8uwMNf3Iv7hOdjev6CqA== X-Received: by 10.36.61.19 with SMTP id n19mr3694163itn.93.1515178654106; Fri, 05 Jan 2018 10:57:34 -0800 (PST) Received: from ebiggers-linuxstation.kir.corp.google.com ([100.66.175.88]) by smtp.gmail.com with ESMTPSA id j68sm3863899iod.53.2018.01.05.10.57.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 05 Jan 2018 10:57:33 -0800 (PST) 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, linux-fsdevel@vger.kernel.org, Eric Biggers Subject: [PATCH v2 11/11] fscrypt: new helper function - fscrypt_get_symlink() Date: Fri, 5 Jan 2018 10:45:02 -0800 Message-Id: <20180105184502.48473-12-ebiggers3@gmail.com> X-Mailer: git-send-email 2.16.0.rc0.223.g4a4ac83678-goog In-Reply-To: <20180105184502.48473-1-ebiggers3@gmail.com> References: <20180105184502.48473-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 Filesystems also have duplicate code to support ->get_link() on encrypted symlinks. Factor it out into a new function fscrypt_get_symlink(). It takes in the contents of the encrypted symlink on-disk and provides the target (decrypted or encoded) that should be returned from ->get_link(). Signed-off-by: Eric Biggers --- fs/crypto/hooks.c | 73 +++++++++++++++++++++++++++++++++++++++++ include/linux/fscrypt_notsupp.h | 8 +++++ include/linux/fscrypt_supp.h | 3 ++ 3 files changed, 84 insertions(+) diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c index 4b83e4af2e41..8900e348ba6e 100644 --- a/fs/crypto/hooks.c +++ b/fs/crypto/hooks.c @@ -200,3 +200,76 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, return 0; } EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink); + +/** + * fscrypt_get_symlink - get the target of an encrypted symlink + * @inode: the symlink inode + * @caddr: the on-disk contents of the symlink + * @max_size: size of @caddr buffer + * @done: if successful, will be set up to free the returned target + * + * If the symlink's encryption key is available, we decrypt its target. + * Otherwise, we encode its target for presentation. + * + * This may sleep, so the filesystem must have dropped out of RCU mode already. + * + * Return: the presentable symlink target or an ERR_PTR() + */ +const char *fscrypt_get_symlink(struct inode *inode, const void *caddr, + unsigned int max_size, + struct delayed_call *done) +{ + const struct fscrypt_symlink_data *sd; + struct fscrypt_str cstr, pstr; + int err; + + /* This is for encrypted symlinks only */ + if (WARN_ON(!IS_ENCRYPTED(inode))) + return ERR_PTR(-EINVAL); + + /* + * Try to set up the symlink's encryption key, but we can continue + * regardless of whether the key is available or not. + */ + err = fscrypt_get_encryption_info(inode); + if (err) + return ERR_PTR(err); + + /* + * For historical reasons, encrypted symlink targets are prefixed with + * the ciphertext length, even though this is redundant with i_size. + */ + + if (max_size < sizeof(*sd)) + return ERR_PTR(-EUCLEAN); + sd = caddr; + cstr.name = (unsigned char *)sd->encrypted_path; + cstr.len = le16_to_cpu(sd->len); + + if (cstr.len == 0) + return ERR_PTR(-EUCLEAN); + + if (cstr.len + sizeof(*sd) - 1 > max_size) + return ERR_PTR(-EUCLEAN); + + err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); + if (err) + return ERR_PTR(err); + + err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); + if (err) + goto err_kfree; + + err = -EUCLEAN; + if (pstr.name[0] == '\0') + goto err_kfree; + + pstr.name[pstr.len] = '\0'; + set_delayed_call(done, kfree_link, pstr.name); + return pstr.name; + +err_kfree: + kfree(pstr.name); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(fscrypt_get_symlink); diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h index 02ec0aa894d8..dd106640c6ea 100644 --- a/include/linux/fscrypt_notsupp.h +++ b/include/linux/fscrypt_notsupp.h @@ -239,4 +239,12 @@ static inline int __fscrypt_encrypt_symlink(struct inode *inode, return -EOPNOTSUPP; } +static inline const char *fscrypt_get_symlink(struct inode *inode, + const void *caddr, + unsigned int max_size, + struct delayed_call *done) +{ + return ERR_PTR(-EOPNOTSUPP); +} + #endif /* _LINUX_FSCRYPT_NOTSUPP_H */ diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index 7e0b67ccd816..dc2babf3f7d3 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -211,5 +211,8 @@ extern int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len, extern int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, unsigned int len, struct fscrypt_str *disk_link); +extern const char *fscrypt_get_symlink(struct inode *inode, const void *caddr, + unsigned int max_size, + struct delayed_call *done); #endif /* _LINUX_FSCRYPT_SUPP_H */