Casefolding requires a derived key for computing the siphash. This is available for v2 policies, but not v1, so we disallow it for v1. Signed-off-by: Daniel Rosenberg <drosen@xxxxxxxxxx> --- fs/crypto/policy.c | 26 +++++++++++++++++++++++--- fs/inode.c | 8 ++++++++ include/linux/fscrypt.h | 7 +++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 96f528071bed..94d96d3212d6 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -67,9 +67,9 @@ static bool supported_iv_ino_lblk_64_policy( * fscrypt_supported_policy - check whether an encryption policy is supported * * Given an encryption policy, check whether all its encryption modes and other - * settings are supported by this kernel. (But we don't currently don't check - * for crypto API support here, so attempting to use an algorithm not configured - * into the crypto API will still fail later.) + * settings are supported by this kernel on the given inode. (But we don't + * currently don't check for crypto API support here, so attempting to use an + * algorithm not configured into the crypto API will still fail later.) * * Return: %true if supported, else %false */ @@ -97,6 +97,12 @@ bool fscrypt_supported_policy(const union fscrypt_policy *policy_u, return false; } + if (IS_CASEFOLDED(inode)) { + fscrypt_warn(inode, + "v1 policy does not support casefolded directories"); + return false; + } + return true; } case FSCRYPT_POLICY_V2: { @@ -530,3 +536,17 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child, return preload ? fscrypt_get_encryption_info(child): 0; } EXPORT_SYMBOL(fscrypt_inherit_context); + +int fscrypt_set_casefolding_allowed(struct inode *inode) +{ + union fscrypt_policy policy; + int ret = fscrypt_get_policy(inode, &policy); + + if (ret < 0) + return ret; + + if (policy.version == FSCRYPT_POLICY_V2) + return 0; + else + return -EINVAL; +} diff --git a/fs/inode.c b/fs/inode.c index fef457a42882..b615ec272a1e 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -20,6 +20,7 @@ #include <linux/ratelimit.h> #include <linux/list_lru.h> #include <linux/iversion.h> +#include <linux/fscrypt.h> #include <trace/events/writeback.h> #include "internal.h" @@ -2245,6 +2246,13 @@ int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags, !capable(CAP_LINUX_IMMUTABLE)) return -EPERM; + /* + * When a directory is encrypted, the CASEFOLD flag can only be turned + * on if the fscrypt policy supports it. + */ + if (IS_ENCRYPTED(inode) && (flags & ~oldflags & FS_CASEFOLD_FL)) + return fscrypt_set_casefolding_allowed(inode); + return 0; } EXPORT_SYMBOL(vfs_ioc_setflags_prepare); diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index e13ff68a99f0..028aed925e51 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -127,6 +127,8 @@ extern int fscrypt_ioctl_get_policy_ex(struct file *, void __user *); extern int fscrypt_has_permitted_context(struct inode *, struct inode *); extern int fscrypt_inherit_context(struct inode *, struct inode *, void *, bool); +extern int fscrypt_set_casefolding_allowed(struct inode *inode); + /* keyring.c */ extern void fscrypt_sb_free(struct super_block *sb); extern int fscrypt_ioctl_add_key(struct file *filp, void __user *arg); @@ -361,6 +363,11 @@ static inline int fscrypt_inherit_context(struct inode *parent, return -EOPNOTSUPP; } +static inline int fscrypt_set_casefolding_allowed(struct inode *inode) +{ + return 0; +} + /* keyring.c */ static inline void fscrypt_sb_free(struct super_block *sb) { -- 2.24.0.393.g34dc348eaf-goog