mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 13:14:07 +08:00
fscrypt updates for 5.11
This release there are some fixes for longstanding problems, as well as some cleanups: - Fix a race condition where a duplicate filename could be created in an encrypted directory if a syscall that creates a new filename raced with the directory's encryption key being added. - Allow deleting files that use an unsupported encryption policy. - Simplify the locking for 'struct fscrypt_master_key'. - Remove kernel-internal constants from the UAPI header. As usual, all these patches have been in linux-next with no reported issues, and I've tested them with xfstests. -----BEGIN PGP SIGNATURE----- iIoEABYIADIWIQSacvsUNc7UX4ntmEPzXCl4vpKOKwUCX9bcDxQcZWJpZ2dlcnNA Z29vZ2xlLmNvbQAKCRDzXCl4vpKOK/HRAP95FGQqS47rIEh4LrvS7cohMJxb5NiX KokAyB88GgmzLQD/c4Xh+iYOxxhFX5NRgruuoec876DrzsuNbEt7WNJ6CQc= =CBoc -----END PGP SIGNATURE----- Merge tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt Pull fscrypt updates from Eric Biggers: "This release there are some fixes for longstanding problems, as well as some cleanups: - Fix a race condition where a duplicate filename could be created in an encrypted directory if a syscall that creates a new filename raced with the directory's encryption key being added. - Allow deleting files that use an unsupported encryption policy. - Simplify the locking for 'struct fscrypt_master_key'. - Remove kernel-internal constants from the UAPI header. As usual, all these patches have been in linux-next with no reported issues, and I've tested them with xfstests" * tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt: fscrypt: allow deleting files with unsupported encryption policy fscrypt: unexport fscrypt_get_encryption_info() fscrypt: move fscrypt_require_key() to fscrypt_private.h fscrypt: move body of fscrypt_prepare_setattr() out-of-line fscrypt: introduce fscrypt_prepare_readdir() ext4: don't call fscrypt_get_encryption_info() from dx_show_leaf() ubifs: remove ubifs_dir_open() f2fs: remove f2fs_dir_open() ext4: remove ext4_dir_open() fscrypt: simplify master key locking fscrypt: remove unnecessary calls to fscrypt_require_key() ubifs: prevent creating duplicate encrypted filenames f2fs: prevent creating duplicate encrypted filenames ext4: prevent creating duplicate encrypted filenames fscrypt: add fscrypt_is_nokey_name() fscrypt: remove kernel-internal constants from UAPI header
This commit is contained in:
commit
7c7fdaf6ad
@ -404,7 +404,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
||||
fname->disk_name.len = iname->len;
|
||||
return 0;
|
||||
}
|
||||
ret = fscrypt_get_encryption_info(dir);
|
||||
ret = fscrypt_get_encryption_info(dir, lookup);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -560,7 +560,11 @@ int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
return -ECHILD;
|
||||
|
||||
dir = dget_parent(dentry);
|
||||
err = fscrypt_get_encryption_info(d_inode(dir));
|
||||
/*
|
||||
* Pass allow_unsupported=true, so that files with an unsupported
|
||||
* encryption policy can be deleted.
|
||||
*/
|
||||
err = fscrypt_get_encryption_info(d_inode(dir), true);
|
||||
valid = !fscrypt_has_encryption_key(d_inode(dir));
|
||||
dput(dir);
|
||||
|
||||
|
@ -25,6 +25,9 @@
|
||||
#define FSCRYPT_CONTEXT_V1 1
|
||||
#define FSCRYPT_CONTEXT_V2 2
|
||||
|
||||
/* Keep this in sync with include/uapi/linux/fscrypt.h */
|
||||
#define FSCRYPT_MODE_MAX FSCRYPT_MODE_ADIANTUM
|
||||
|
||||
struct fscrypt_context_v1 {
|
||||
u8 version; /* FSCRYPT_CONTEXT_V1 */
|
||||
u8 contents_encryption_mode;
|
||||
@ -436,16 +439,9 @@ struct fscrypt_master_key {
|
||||
* FS_IOC_REMOVE_ENCRYPTION_KEY can be retried, or
|
||||
* FS_IOC_ADD_ENCRYPTION_KEY can add the secret again.
|
||||
*
|
||||
* Locking: protected by key->sem (outer) and mk_secret_sem (inner).
|
||||
* The reason for two locks is that key->sem also protects modifying
|
||||
* mk_users, which ranks it above the semaphore for the keyring key
|
||||
* type, which is in turn above page faults (via keyring_read). But
|
||||
* sometimes filesystems call fscrypt_get_encryption_info() from within
|
||||
* a transaction, which ranks it below page faults. So we need a
|
||||
* separate lock which protects mk_secret but not also mk_users.
|
||||
* Locking: protected by this master key's key->sem.
|
||||
*/
|
||||
struct fscrypt_master_key_secret mk_secret;
|
||||
struct rw_semaphore mk_secret_sem;
|
||||
|
||||
/*
|
||||
* For v1 policy keys: an arbitrary key descriptor which was assigned by
|
||||
@ -464,8 +460,8 @@ struct fscrypt_master_key {
|
||||
*
|
||||
* This is NULL for v1 policy keys; those can only be added by root.
|
||||
*
|
||||
* Locking: in addition to this keyrings own semaphore, this is
|
||||
* protected by the master key's key->sem, so we can do atomic
|
||||
* Locking: in addition to this keyring's own semaphore, this is
|
||||
* protected by this master key's key->sem, so we can do atomic
|
||||
* search+insert. It can also be searched without taking any locks, but
|
||||
* in that case the returned key may have already been removed.
|
||||
*/
|
||||
@ -491,9 +487,9 @@ struct fscrypt_master_key {
|
||||
* Per-mode encryption keys for the various types of encryption policies
|
||||
* that use them. Allocated and derived on-demand.
|
||||
*/
|
||||
struct fscrypt_prepared_key mk_direct_keys[__FSCRYPT_MODE_MAX + 1];
|
||||
struct fscrypt_prepared_key mk_iv_ino_lblk_64_keys[__FSCRYPT_MODE_MAX + 1];
|
||||
struct fscrypt_prepared_key mk_iv_ino_lblk_32_keys[__FSCRYPT_MODE_MAX + 1];
|
||||
struct fscrypt_prepared_key mk_direct_keys[FSCRYPT_MODE_MAX + 1];
|
||||
struct fscrypt_prepared_key mk_iv_ino_lblk_64_keys[FSCRYPT_MODE_MAX + 1];
|
||||
struct fscrypt_prepared_key mk_iv_ino_lblk_32_keys[FSCRYPT_MODE_MAX + 1];
|
||||
|
||||
/* Hash key for inode numbers. Initialized only when needed. */
|
||||
siphash_key_t mk_ino_hash_key;
|
||||
@ -507,9 +503,9 @@ is_master_key_secret_present(const struct fscrypt_master_key_secret *secret)
|
||||
/*
|
||||
* The READ_ONCE() is only necessary for fscrypt_drop_inode() and
|
||||
* fscrypt_key_describe(). These run in atomic context, so they can't
|
||||
* take ->mk_secret_sem and thus 'secret' can change concurrently which
|
||||
* would be a data race. But they only need to know whether the secret
|
||||
* *was* present at the time of check, so READ_ONCE() suffices.
|
||||
* take the key semaphore and thus 'secret' can change concurrently
|
||||
* which would be a data race. But they only need to know whether the
|
||||
* secret *was* present at the time of check, so READ_ONCE() suffices.
|
||||
*/
|
||||
return READ_ONCE(secret->size) != 0;
|
||||
}
|
||||
@ -575,6 +571,34 @@ int fscrypt_derive_dirhash_key(struct fscrypt_info *ci,
|
||||
void fscrypt_hash_inode_number(struct fscrypt_info *ci,
|
||||
const struct fscrypt_master_key *mk);
|
||||
|
||||
int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported);
|
||||
|
||||
/**
|
||||
* fscrypt_require_key() - require an inode's encryption key
|
||||
* @inode: the inode we need the key for
|
||||
*
|
||||
* If the inode is encrypted, set up its encryption key if not already done.
|
||||
* Then require that the key be present and return -ENOKEY otherwise.
|
||||
*
|
||||
* No locks are needed, and the key will live as long as the struct inode --- so
|
||||
* it won't go away from under you.
|
||||
*
|
||||
* Return: 0 on success, -ENOKEY if the key is missing, or another -errno code
|
||||
* if a problem occurred while setting up the encryption key.
|
||||
*/
|
||||
static inline int fscrypt_require_key(struct inode *inode)
|
||||
{
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
int err = fscrypt_get_encryption_info(inode, false);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
if (!fscrypt_has_encryption_key(inode))
|
||||
return -ENOKEY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* keysetup_v1.c */
|
||||
|
||||
void fscrypt_put_direct_key(struct fscrypt_direct_key *dk);
|
||||
|
@ -54,15 +54,12 @@ EXPORT_SYMBOL_GPL(fscrypt_file_open);
|
||||
int __fscrypt_prepare_link(struct inode *inode, struct inode *dir,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = fscrypt_require_key(dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* ... in case we looked up no-key name before key was added */
|
||||
if (dentry->d_flags & DCACHE_NOKEY_NAME)
|
||||
if (fscrypt_is_nokey_name(dentry))
|
||||
return -ENOKEY;
|
||||
/*
|
||||
* We don't need to separately check that the directory inode's key is
|
||||
* available, as it's implied by the dentry not being a no-key name.
|
||||
*/
|
||||
|
||||
if (!fscrypt_has_permitted_context(dir, inode))
|
||||
return -EXDEV;
|
||||
@ -75,19 +72,13 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = fscrypt_require_key(old_dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fscrypt_require_key(new_dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* ... in case we looked up no-key name(s) before key was added */
|
||||
if ((old_dentry->d_flags | new_dentry->d_flags) & DCACHE_NOKEY_NAME)
|
||||
if (fscrypt_is_nokey_name(old_dentry) ||
|
||||
fscrypt_is_nokey_name(new_dentry))
|
||||
return -ENOKEY;
|
||||
/*
|
||||
* We don't need to separately check that the directory inodes' keys are
|
||||
* available, as it's implied by the dentries not being no-key names.
|
||||
*/
|
||||
|
||||
if (old_dir != new_dir) {
|
||||
if (IS_ENCRYPTED(new_dir) &&
|
||||
@ -123,6 +114,20 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);
|
||||
|
||||
int __fscrypt_prepare_readdir(struct inode *dir)
|
||||
{
|
||||
return fscrypt_get_encryption_info(dir, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__fscrypt_prepare_readdir);
|
||||
|
||||
int __fscrypt_prepare_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
{
|
||||
if (attr->ia_valid & ATTR_SIZE)
|
||||
return fscrypt_require_key(d_inode(dentry));
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__fscrypt_prepare_setattr);
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_setflags() - prepare to change flags with FS_IOC_SETFLAGS
|
||||
* @inode: the inode on which flags are being changed
|
||||
@ -138,6 +143,7 @@ int fscrypt_prepare_setflags(struct inode *inode,
|
||||
unsigned int oldflags, unsigned int flags)
|
||||
{
|
||||
struct fscrypt_info *ci;
|
||||
struct key *key;
|
||||
struct fscrypt_master_key *mk;
|
||||
int err;
|
||||
|
||||
@ -153,13 +159,14 @@ int fscrypt_prepare_setflags(struct inode *inode,
|
||||
ci = inode->i_crypt_info;
|
||||
if (ci->ci_policy.version != FSCRYPT_POLICY_V2)
|
||||
return -EINVAL;
|
||||
mk = ci->ci_master_key->payload.data[0];
|
||||
down_read(&mk->mk_secret_sem);
|
||||
key = ci->ci_master_key;
|
||||
mk = key->payload.data[0];
|
||||
down_read(&key->sem);
|
||||
if (is_master_key_secret_present(&mk->mk_secret))
|
||||
err = fscrypt_derive_dirhash_key(ci, mk);
|
||||
else
|
||||
err = -ENOKEY;
|
||||
up_read(&mk->mk_secret_sem);
|
||||
up_read(&key->sem);
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
@ -325,7 +332,7 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
|
||||
* 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);
|
||||
err = fscrypt_get_encryption_info(inode, false);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
has_key = fscrypt_has_encryption_key(inode);
|
||||
|
@ -44,7 +44,7 @@ static void free_master_key(struct fscrypt_master_key *mk)
|
||||
|
||||
wipe_master_key_secret(&mk->mk_secret);
|
||||
|
||||
for (i = 0; i <= __FSCRYPT_MODE_MAX; i++) {
|
||||
for (i = 0; i <= FSCRYPT_MODE_MAX; i++) {
|
||||
fscrypt_destroy_prepared_key(&mk->mk_direct_keys[i]);
|
||||
fscrypt_destroy_prepared_key(&mk->mk_iv_ino_lblk_64_keys[i]);
|
||||
fscrypt_destroy_prepared_key(&mk->mk_iv_ino_lblk_32_keys[i]);
|
||||
@ -347,7 +347,6 @@ static int add_new_master_key(struct fscrypt_master_key_secret *secret,
|
||||
mk->mk_spec = *mk_spec;
|
||||
|
||||
move_master_key_secret(&mk->mk_secret, secret);
|
||||
init_rwsem(&mk->mk_secret_sem);
|
||||
|
||||
refcount_set(&mk->mk_refcount, 1); /* secret is present */
|
||||
INIT_LIST_HEAD(&mk->mk_decrypted_inodes);
|
||||
@ -427,11 +426,8 @@ static int add_existing_master_key(struct fscrypt_master_key *mk,
|
||||
}
|
||||
|
||||
/* Re-add the secret if needed. */
|
||||
if (rekey) {
|
||||
down_write(&mk->mk_secret_sem);
|
||||
if (rekey)
|
||||
move_master_key_secret(&mk->mk_secret, secret);
|
||||
up_write(&mk->mk_secret_sem);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -975,10 +971,8 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users)
|
||||
/* No user claims remaining. Go ahead and wipe the secret. */
|
||||
dead = false;
|
||||
if (is_master_key_secret_present(&mk->mk_secret)) {
|
||||
down_write(&mk->mk_secret_sem);
|
||||
wipe_master_key_secret(&mk->mk_secret);
|
||||
dead = refcount_dec_and_test(&mk->mk_refcount);
|
||||
up_write(&mk->mk_secret_sem);
|
||||
}
|
||||
up_write(&key->sem);
|
||||
if (dead) {
|
||||
|
@ -56,6 +56,8 @@ static struct fscrypt_mode *
|
||||
select_encryption_mode(const union fscrypt_policy *policy,
|
||||
const struct inode *inode)
|
||||
{
|
||||
BUILD_BUG_ON(ARRAY_SIZE(fscrypt_modes) != FSCRYPT_MODE_MAX + 1);
|
||||
|
||||
if (S_ISREG(inode->i_mode))
|
||||
return &fscrypt_modes[fscrypt_policy_contents_mode(policy)];
|
||||
|
||||
@ -168,7 +170,7 @@ static int setup_per_mode_enc_key(struct fscrypt_info *ci,
|
||||
unsigned int hkdf_infolen = 0;
|
||||
int err;
|
||||
|
||||
if (WARN_ON(mode_num > __FSCRYPT_MODE_MAX))
|
||||
if (WARN_ON(mode_num > FSCRYPT_MODE_MAX))
|
||||
return -EINVAL;
|
||||
|
||||
prep_key = &keys[mode_num];
|
||||
@ -335,11 +337,11 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
|
||||
* Find the master key, then set up the inode's actual encryption key.
|
||||
*
|
||||
* If the master key is found in the filesystem-level keyring, then the
|
||||
* corresponding 'struct key' is returned in *master_key_ret with
|
||||
* ->mk_secret_sem read-locked. This is needed to ensure that only one task
|
||||
* links the fscrypt_info into ->mk_decrypted_inodes (as multiple tasks may race
|
||||
* to create an fscrypt_info for the same inode), and to synchronize the master
|
||||
* key being removed with a new inode starting to use it.
|
||||
* corresponding 'struct key' is returned in *master_key_ret with its semaphore
|
||||
* read-locked. This is needed to ensure that only one task links the
|
||||
* fscrypt_info into ->mk_decrypted_inodes (as multiple tasks may race to create
|
||||
* an fscrypt_info for the same inode), and to synchronize the master key being
|
||||
* removed with a new inode starting to use it.
|
||||
*/
|
||||
static int setup_file_encryption_key(struct fscrypt_info *ci,
|
||||
bool need_dirhash_key,
|
||||
@ -388,7 +390,7 @@ static int setup_file_encryption_key(struct fscrypt_info *ci,
|
||||
}
|
||||
|
||||
mk = key->payload.data[0];
|
||||
down_read(&mk->mk_secret_sem);
|
||||
down_read(&key->sem);
|
||||
|
||||
/* Has the secret been removed (via FS_IOC_REMOVE_ENCRYPTION_KEY)? */
|
||||
if (!is_master_key_secret_present(&mk->mk_secret)) {
|
||||
@ -431,7 +433,7 @@ static int setup_file_encryption_key(struct fscrypt_info *ci,
|
||||
return 0;
|
||||
|
||||
out_release_key:
|
||||
up_read(&mk->mk_secret_sem);
|
||||
up_read(&key->sem);
|
||||
key_put(key);
|
||||
return err;
|
||||
}
|
||||
@ -534,9 +536,7 @@ fscrypt_setup_encryption_info(struct inode *inode,
|
||||
res = 0;
|
||||
out:
|
||||
if (master_key) {
|
||||
struct fscrypt_master_key *mk = master_key->payload.data[0];
|
||||
|
||||
up_read(&mk->mk_secret_sem);
|
||||
up_read(&master_key->sem);
|
||||
key_put(master_key);
|
||||
}
|
||||
put_crypt_info(crypt_info);
|
||||
@ -546,6 +546,11 @@ out:
|
||||
/**
|
||||
* fscrypt_get_encryption_info() - set up an inode's encryption key
|
||||
* @inode: the inode to set up the key for. Must be encrypted.
|
||||
* @allow_unsupported: if %true, treat an unsupported encryption policy (or
|
||||
* unrecognized encryption context) the same way as the key
|
||||
* being unavailable, instead of returning an error. Use
|
||||
* %false unless the operation being performed is needed in
|
||||
* order for files (or directories) to be deleted.
|
||||
*
|
||||
* Set up ->i_crypt_info, if it hasn't already been done.
|
||||
*
|
||||
@ -556,7 +561,7 @@ out:
|
||||
* encryption key is unavailable. (Use fscrypt_has_encryption_key() to
|
||||
* distinguish these cases.) Also can return another -errno code.
|
||||
*/
|
||||
int fscrypt_get_encryption_info(struct inode *inode)
|
||||
int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported)
|
||||
{
|
||||
int res;
|
||||
union fscrypt_context ctx;
|
||||
@ -567,29 +572,38 @@ int fscrypt_get_encryption_info(struct inode *inode)
|
||||
|
||||
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
|
||||
if (res < 0) {
|
||||
if (res == -ERANGE && allow_unsupported)
|
||||
return 0;
|
||||
fscrypt_warn(inode, "Error %d getting encryption context", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = fscrypt_policy_from_context(&policy, &ctx, res);
|
||||
if (res) {
|
||||
if (allow_unsupported)
|
||||
return 0;
|
||||
fscrypt_warn(inode,
|
||||
"Unrecognized or corrupt encryption context");
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!fscrypt_supported_policy(&policy, inode))
|
||||
if (!fscrypt_supported_policy(&policy, inode)) {
|
||||
if (allow_unsupported)
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = fscrypt_setup_encryption_info(inode, &policy,
|
||||
fscrypt_context_nonce(&ctx),
|
||||
IS_CASEFOLDED(inode) &&
|
||||
S_ISDIR(inode->i_mode));
|
||||
|
||||
if (res == -ENOPKG && allow_unsupported) /* Algorithm unavailable? */
|
||||
res = 0;
|
||||
if (res == -ENOKEY)
|
||||
res = 0;
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_get_encryption_info);
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_new_inode() - prepare to create a new inode in a directory
|
||||
@ -710,7 +724,7 @@ int fscrypt_drop_inode(struct inode *inode)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Note: since we aren't holding ->mk_secret_sem, the result here can
|
||||
* Note: since we aren't holding the key semaphore, the result here can
|
||||
* immediately become outdated. But there's no correctness problem with
|
||||
* unnecessarily evicting. Nor is there a correctness problem with not
|
||||
* evicting while iput() is racing with the key being removed, since
|
||||
|
@ -175,7 +175,10 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (policy->flags & ~FSCRYPT_POLICY_FLAGS_VALID) {
|
||||
if (policy->flags & ~(FSCRYPT_POLICY_FLAGS_PAD_MASK |
|
||||
FSCRYPT_POLICY_FLAG_DIRECT_KEY |
|
||||
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 |
|
||||
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) {
|
||||
fscrypt_warn(inode, "Unsupported encryption flags (0x%02x)",
|
||||
policy->flags);
|
||||
return false;
|
||||
@ -587,7 +590,7 @@ EXPORT_SYMBOL_GPL(fscrypt_ioctl_get_nonce);
|
||||
int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
|
||||
{
|
||||
union fscrypt_policy parent_policy, child_policy;
|
||||
int err;
|
||||
int err, err1, err2;
|
||||
|
||||
/* No restrictions on file types which are never encrypted */
|
||||
if (!S_ISREG(child->i_mode) && !S_ISDIR(child->i_mode) &&
|
||||
@ -617,19 +620,25 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
|
||||
* In any case, if an unexpected error occurs, fall back to "forbidden".
|
||||
*/
|
||||
|
||||
err = fscrypt_get_encryption_info(parent);
|
||||
err = fscrypt_get_encryption_info(parent, true);
|
||||
if (err)
|
||||
return 0;
|
||||
err = fscrypt_get_encryption_info(child);
|
||||
err = fscrypt_get_encryption_info(child, true);
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
err = fscrypt_get_policy(parent, &parent_policy);
|
||||
if (err)
|
||||
return 0;
|
||||
err1 = fscrypt_get_policy(parent, &parent_policy);
|
||||
err2 = fscrypt_get_policy(child, &child_policy);
|
||||
|
||||
err = fscrypt_get_policy(child, &child_policy);
|
||||
if (err)
|
||||
/*
|
||||
* Allow the case where the parent and child both have an unrecognized
|
||||
* encryption policy, so that files with an unrecognized encryption
|
||||
* policy can be deleted.
|
||||
*/
|
||||
if (err1 == -EINVAL && err2 == -EINVAL)
|
||||
return 1;
|
||||
|
||||
if (err1 || err2)
|
||||
return 0;
|
||||
|
||||
return fscrypt_policies_equal(&parent_policy, &child_policy);
|
||||
|
@ -118,11 +118,9 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
|
||||
struct buffer_head *bh = NULL;
|
||||
struct fscrypt_str fstr = FSTR_INIT(NULL, 0);
|
||||
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
err = fscrypt_get_encryption_info(inode);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
err = fscrypt_prepare_readdir(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (is_dx_dir(inode)) {
|
||||
err = ext4_dx_readdir(file, ctx);
|
||||
@ -616,13 +614,6 @@ finished:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ext4_dir_open(struct inode * inode, struct file * filp)
|
||||
{
|
||||
if (IS_ENCRYPTED(inode))
|
||||
return fscrypt_get_encryption_info(inode) ? -EACCES : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ext4_release_dir(struct inode *inode, struct file *filp)
|
||||
{
|
||||
if (filp->private_data)
|
||||
@ -664,7 +655,6 @@ const struct file_operations ext4_dir_operations = {
|
||||
.compat_ioctl = ext4_compat_ioctl,
|
||||
#endif
|
||||
.fsync = ext4_sync_file,
|
||||
.open = ext4_dir_open,
|
||||
.release = ext4_release_dir,
|
||||
};
|
||||
|
||||
|
@ -643,13 +643,7 @@ static struct stats dx_show_leaf(struct inode *dir,
|
||||
|
||||
name = de->name;
|
||||
len = de->name_len;
|
||||
if (IS_ENCRYPTED(dir))
|
||||
res = fscrypt_get_encryption_info(dir);
|
||||
if (res) {
|
||||
printk(KERN_WARNING "Error setting up"
|
||||
" fname crypto: %d\n", res);
|
||||
}
|
||||
if (!fscrypt_has_encryption_key(dir)) {
|
||||
if (!IS_ENCRYPTED(dir)) {
|
||||
/* Directory is not encrypted */
|
||||
ext4fs_dirhash(dir, de->name,
|
||||
de->name_len, &h);
|
||||
@ -1010,7 +1004,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
|
||||
EXT4_DIR_REC_LEN(0));
|
||||
/* Check if the directory is encrypted */
|
||||
if (IS_ENCRYPTED(dir)) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
err = fscrypt_prepare_readdir(dir);
|
||||
if (err < 0) {
|
||||
brelse(bh);
|
||||
return err;
|
||||
@ -2195,6 +2189,9 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
|
||||
if (!dentry->d_name.len)
|
||||
return -EINVAL;
|
||||
|
||||
if (fscrypt_is_nokey_name(dentry))
|
||||
return -ENOKEY;
|
||||
|
||||
#ifdef CONFIG_UNICODE
|
||||
if (sb_has_strict_encoding(sb) && IS_CASEFOLDED(dir) &&
|
||||
sb->s_encoding && utf8_validate(sb->s_encoding, &dentry->d_name))
|
||||
|
@ -1022,7 +1022,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
|
||||
int err = 0;
|
||||
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
err = fscrypt_get_encryption_info(inode);
|
||||
err = fscrypt_prepare_readdir(inode);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -1081,19 +1081,11 @@ out:
|
||||
return err < 0 ? err : 0;
|
||||
}
|
||||
|
||||
static int f2fs_dir_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
if (IS_ENCRYPTED(inode))
|
||||
return fscrypt_get_encryption_info(inode) ? -EACCES : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct file_operations f2fs_dir_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate_shared = f2fs_readdir,
|
||||
.fsync = f2fs_sync_file,
|
||||
.open = f2fs_dir_open,
|
||||
.unlocked_ioctl = f2fs_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = f2fs_compat_ioctl,
|
||||
|
@ -3251,6 +3251,8 @@ bool f2fs_empty_dir(struct inode *dir);
|
||||
|
||||
static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
|
||||
{
|
||||
if (fscrypt_is_nokey_name(dentry))
|
||||
return -ENOKEY;
|
||||
return f2fs_do_add_link(d_inode(dentry->d_parent), &dentry->d_name,
|
||||
inode, inode->i_ino, inode->i_mode);
|
||||
}
|
||||
|
@ -270,6 +270,15 @@ done:
|
||||
return d_splice_alias(inode, dentry);
|
||||
}
|
||||
|
||||
static int ubifs_prepare_create(struct inode *dir, struct dentry *dentry,
|
||||
struct fscrypt_name *nm)
|
||||
{
|
||||
if (fscrypt_is_nokey_name(dentry))
|
||||
return -ENOKEY;
|
||||
|
||||
return fscrypt_setup_filename(dir, &dentry->d_name, 0, nm);
|
||||
}
|
||||
|
||||
static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
bool excl)
|
||||
{
|
||||
@ -293,7 +302,7 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
|
||||
err = ubifs_prepare_create(dir, dentry, &nm);
|
||||
if (err)
|
||||
goto out_budg;
|
||||
|
||||
@ -505,7 +514,7 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
|
||||
return 0;
|
||||
|
||||
if (encrypted) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
err = fscrypt_prepare_readdir(dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -953,7 +962,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
|
||||
err = ubifs_prepare_create(dir, dentry, &nm);
|
||||
if (err)
|
||||
goto out_budg;
|
||||
|
||||
@ -1038,7 +1047,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
return err;
|
||||
}
|
||||
|
||||
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
|
||||
err = ubifs_prepare_create(dir, dentry, &nm);
|
||||
if (err) {
|
||||
kfree(dev);
|
||||
goto out_budg;
|
||||
@ -1122,7 +1131,7 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
|
||||
err = ubifs_prepare_create(dir, dentry, &nm);
|
||||
if (err)
|
||||
goto out_budg;
|
||||
|
||||
@ -1610,14 +1619,6 @@ int ubifs_getattr(const struct path *path, struct kstat *stat,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ubifs_dir_open(struct inode *dir, struct file *file)
|
||||
{
|
||||
if (IS_ENCRYPTED(dir))
|
||||
return fscrypt_get_encryption_info(dir) ? -EACCES : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct inode_operations ubifs_dir_inode_operations = {
|
||||
.lookup = ubifs_lookup,
|
||||
.create = ubifs_create,
|
||||
@ -1644,7 +1645,6 @@ const struct file_operations ubifs_dir_operations = {
|
||||
.iterate_shared = ubifs_readdir,
|
||||
.fsync = ubifs_fsync,
|
||||
.unlocked_ioctl = ubifs_ioctl,
|
||||
.open = ubifs_dir_open,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ubifs_compat_ioctl,
|
||||
#endif
|
||||
|
@ -75,7 +75,7 @@ struct fscrypt_operations {
|
||||
static inline struct fscrypt_info *fscrypt_get_info(const struct inode *inode)
|
||||
{
|
||||
/*
|
||||
* Pairs with the cmpxchg_release() in fscrypt_get_encryption_info().
|
||||
* Pairs with the cmpxchg_release() in fscrypt_setup_encryption_info().
|
||||
* I.e., another task may publish ->i_crypt_info concurrently, executing
|
||||
* a RELEASE barrier. We need to use smp_load_acquire() here to safely
|
||||
* ACQUIRE the memory the other task published.
|
||||
@ -111,6 +111,35 @@ static inline void fscrypt_handle_d_move(struct dentry *dentry)
|
||||
dentry->d_flags &= ~DCACHE_NOKEY_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_is_nokey_name() - test whether a dentry is a no-key name
|
||||
* @dentry: the dentry to check
|
||||
*
|
||||
* This returns true if the dentry is a no-key dentry. A no-key dentry is a
|
||||
* dentry that was created in an encrypted directory that hasn't had its
|
||||
* encryption key added yet. Such dentries may be either positive or negative.
|
||||
*
|
||||
* When a filesystem is asked to create a new filename in an encrypted directory
|
||||
* and the new filename's dentry is a no-key dentry, it must fail the operation
|
||||
* with ENOKEY. This includes ->create(), ->mkdir(), ->mknod(), ->symlink(),
|
||||
* ->rename(), and ->link(). (However, ->rename() and ->link() are already
|
||||
* handled by fscrypt_prepare_rename() and fscrypt_prepare_link().)
|
||||
*
|
||||
* This is necessary because creating a filename requires the directory's
|
||||
* encryption key, but just checking for the key on the directory inode during
|
||||
* the final filesystem operation doesn't guarantee that the key was available
|
||||
* during the preceding dentry lookup. And the key must have already been
|
||||
* available during the dentry lookup in order for it to have been checked
|
||||
* whether the filename already exists in the directory and for the new file's
|
||||
* dentry not to be invalidated due to it incorrectly having the no-key flag.
|
||||
*
|
||||
* Return: %true if the dentry is a no-key name
|
||||
*/
|
||||
static inline bool fscrypt_is_nokey_name(const struct dentry *dentry)
|
||||
{
|
||||
return dentry->d_flags & DCACHE_NOKEY_NAME;
|
||||
}
|
||||
|
||||
/* crypto.c */
|
||||
void fscrypt_enqueue_decrypt_work(struct work_struct *);
|
||||
|
||||
@ -171,7 +200,6 @@ int fscrypt_ioctl_remove_key_all_users(struct file *filp, void __user *arg);
|
||||
int fscrypt_ioctl_get_key_status(struct file *filp, void __user *arg);
|
||||
|
||||
/* keysetup.c */
|
||||
int fscrypt_get_encryption_info(struct inode *inode);
|
||||
int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
|
||||
bool *encrypt_ret);
|
||||
void fscrypt_put_encryption_info(struct inode *inode);
|
||||
@ -213,6 +241,8 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
unsigned int flags);
|
||||
int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct fscrypt_name *fname);
|
||||
int __fscrypt_prepare_readdir(struct inode *dir);
|
||||
int __fscrypt_prepare_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
int fscrypt_prepare_setflags(struct inode *inode,
|
||||
unsigned int oldflags, unsigned int flags);
|
||||
int fscrypt_prepare_symlink(struct inode *dir, const char *target,
|
||||
@ -244,6 +274,11 @@ static inline void fscrypt_handle_d_move(struct dentry *dentry)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool fscrypt_is_nokey_name(const struct dentry *dentry)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* crypto.c */
|
||||
static inline void fscrypt_enqueue_decrypt_work(struct work_struct *work)
|
||||
{
|
||||
@ -372,10 +407,6 @@ static inline int fscrypt_ioctl_get_key_status(struct file *filp,
|
||||
}
|
||||
|
||||
/* keysetup.c */
|
||||
static inline int fscrypt_get_encryption_info(struct inode *inode)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int fscrypt_prepare_new_inode(struct inode *dir,
|
||||
struct inode *inode,
|
||||
@ -503,6 +534,17 @@ static inline int __fscrypt_prepare_lookup(struct inode *dir,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int __fscrypt_prepare_readdir(struct inode *dir)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int __fscrypt_prepare_setattr(struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int fscrypt_prepare_setflags(struct inode *inode,
|
||||
unsigned int oldflags,
|
||||
unsigned int flags)
|
||||
@ -641,32 +683,6 @@ static inline bool fscrypt_has_encryption_key(const struct inode *inode)
|
||||
return fscrypt_get_info(inode) != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_require_key() - require an inode's encryption key
|
||||
* @inode: the inode we need the key for
|
||||
*
|
||||
* If the inode is encrypted, set up its encryption key if not already done.
|
||||
* Then require that the key be present and return -ENOKEY otherwise.
|
||||
*
|
||||
* No locks are needed, and the key will live as long as the struct inode --- so
|
||||
* it won't go away from under you.
|
||||
*
|
||||
* Return: 0 on success, -ENOKEY if the key is missing, or another -errno code
|
||||
* if a problem occurred while setting up the encryption key.
|
||||
*/
|
||||
static inline int fscrypt_require_key(struct inode *inode)
|
||||
{
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
int err = fscrypt_get_encryption_info(inode);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
if (!fscrypt_has_encryption_key(inode))
|
||||
return -ENOKEY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_link() - prepare to link an inode into a possibly-encrypted
|
||||
* directory
|
||||
@ -676,8 +692,7 @@ static inline int fscrypt_require_key(struct inode *inode)
|
||||
*
|
||||
* A new link can only be added to an encrypted directory if the directory's
|
||||
* encryption key is available --- since otherwise we'd have no way to encrypt
|
||||
* the filename. Therefore, we first set up the directory's encryption key (if
|
||||
* not already done) and return an error if it's unavailable.
|
||||
* the filename.
|
||||
*
|
||||
* We also verify that the link will not violate the constraint that all files
|
||||
* in an encrypted directory tree use the same encryption policy.
|
||||
@ -738,8 +753,9 @@ static inline int fscrypt_prepare_rename(struct inode *old_dir,
|
||||
*
|
||||
* Prepare for ->lookup() in a directory which may be encrypted by determining
|
||||
* the name that will actually be used to search the directory on-disk. If the
|
||||
* directory's encryption key is available, then the lookup is assumed to be by
|
||||
* plaintext name; otherwise, it is assumed to be by no-key name.
|
||||
* directory's encryption policy is supported by this kernel and its encryption
|
||||
* key is available, then the lookup is assumed to be by plaintext name;
|
||||
* otherwise, it is assumed to be by no-key name.
|
||||
*
|
||||
* This also installs a custom ->d_revalidate() method which will invalidate the
|
||||
* dentry if it was created without the key and the key is later added.
|
||||
@ -762,6 +778,26 @@ static inline int fscrypt_prepare_lookup(struct inode *dir,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_readdir() - prepare to read a possibly-encrypted directory
|
||||
* @dir: the directory inode
|
||||
*
|
||||
* If the directory is encrypted and it doesn't already have its encryption key
|
||||
* set up, try to set it up so that the filenames will be listed in plaintext
|
||||
* form rather than in no-key form.
|
||||
*
|
||||
* Return: 0 on success; -errno on error. Note that the encryption key being
|
||||
* unavailable is not considered an error. It is also not an error if
|
||||
* the encryption policy is unsupported by this kernel; that is treated
|
||||
* like the key being unavailable, so that files can still be deleted.
|
||||
*/
|
||||
static inline int fscrypt_prepare_readdir(struct inode *dir)
|
||||
{
|
||||
if (IS_ENCRYPTED(dir))
|
||||
return __fscrypt_prepare_readdir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_setattr() - prepare to change a possibly-encrypted inode's
|
||||
* attributes
|
||||
@ -783,8 +819,8 @@ static inline int fscrypt_prepare_lookup(struct inode *dir,
|
||||
static inline int fscrypt_prepare_setattr(struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
if (attr->ia_valid & ATTR_SIZE)
|
||||
return fscrypt_require_key(d_inode(dentry));
|
||||
if (IS_ENCRYPTED(d_inode(dentry)))
|
||||
return __fscrypt_prepare_setattr(dentry, attr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
#define FSCRYPT_POLICY_FLAG_DIRECT_KEY 0x04
|
||||
#define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 0x08
|
||||
#define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 0x10
|
||||
#define FSCRYPT_POLICY_FLAGS_VALID 0x1F
|
||||
|
||||
/* Encryption algorithms */
|
||||
#define FSCRYPT_MODE_AES_256_XTS 1
|
||||
@ -28,7 +27,7 @@
|
||||
#define FSCRYPT_MODE_AES_128_CBC 5
|
||||
#define FSCRYPT_MODE_AES_128_CTS 6
|
||||
#define FSCRYPT_MODE_ADIANTUM 9
|
||||
#define __FSCRYPT_MODE_MAX 9
|
||||
/* If adding a mode number > 9, update FSCRYPT_MODE_MAX in fscrypt_private.h */
|
||||
|
||||
/*
|
||||
* Legacy policy version; ad-hoc KDF and no key verification.
|
||||
@ -177,7 +176,7 @@ struct fscrypt_get_key_status_arg {
|
||||
#define FS_POLICY_FLAGS_PAD_32 FSCRYPT_POLICY_FLAGS_PAD_32
|
||||
#define FS_POLICY_FLAGS_PAD_MASK FSCRYPT_POLICY_FLAGS_PAD_MASK
|
||||
#define FS_POLICY_FLAG_DIRECT_KEY FSCRYPT_POLICY_FLAG_DIRECT_KEY
|
||||
#define FS_POLICY_FLAGS_VALID FSCRYPT_POLICY_FLAGS_VALID
|
||||
#define FS_POLICY_FLAGS_VALID 0x07 /* contains old flags only */
|
||||
#define FS_ENCRYPTION_MODE_INVALID 0 /* never used */
|
||||
#define FS_ENCRYPTION_MODE_AES_256_XTS FSCRYPT_MODE_AES_256_XTS
|
||||
#define FS_ENCRYPTION_MODE_AES_256_GCM 2 /* never used */
|
||||
|
Loading…
Reference in New Issue
Block a user