fscrypt: handle test_dummy_encryption in more logical way
The behavior of the test_dummy_encryption mount option is that when a
new file (or directory or symlink) is created in an unencrypted
directory, it's automatically encrypted using a dummy encryption policy.
That's it; in particular, the encryption (or lack thereof) of existing
files (or directories or symlinks) doesn't change.
Unfortunately the implementation of test_dummy_encryption is a bit weird
and confusing. When test_dummy_encryption is enabled and a file is
being created in an unencrypted directory, we set up an encryption key
(->i_crypt_info) for the directory. This isn't actually used to do any
encryption, however, since the directory is still unencrypted! Instead,
->i_crypt_info is only used for inheriting the encryption policy.
One consequence of this is that the filesystem ends up providing a
"dummy context" (policy + nonce) instead of a "dummy policy". In
commit ed318a6cc0
("fscrypt: support test_dummy_encryption=v2"), I
mistakenly thought this was required. However, actually the nonce only
ends up being used to derive a key that is never used.
Another consequence of this implementation is that it allows for
'inode->i_crypt_info != NULL && !IS_ENCRYPTED(inode)', which is an edge
case that can be forgotten about. For example, currently
FS_IOC_GET_ENCRYPTION_POLICY on an unencrypted directory may return the
dummy encryption policy when the filesystem is mounted with
test_dummy_encryption. That seems like the wrong thing to do, since
again, the directory itself is not actually encrypted.
Therefore, switch to a more logical and maintainable implementation
where the dummy encryption policy inheritance is done without setting up
keys for unencrypted directories. This involves:
- Adding a function fscrypt_policy_to_inherit() which returns the
encryption policy to inherit from a directory. This can be a real
policy, a dummy policy, or no policy.
- Replacing struct fscrypt_dummy_context, ->get_dummy_context(), etc.
with struct fscrypt_dummy_policy, ->get_dummy_policy(), etc.
- Making fscrypt_fname_encrypted_size() take an fscrypt_policy instead
of an inode.
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Acked-by: Jeff Layton <jlayton@kernel.org>
Link: https://lore.kernel.org/r/20200917041136.178600-13-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
|
||||
#define FS_CRYPTO_BLOCK_SIZE 16
|
||||
|
||||
union fscrypt_context;
|
||||
union fscrypt_policy;
|
||||
struct fscrypt_info;
|
||||
struct seq_file;
|
||||
|
||||
@@ -62,8 +62,7 @@ struct fscrypt_operations {
|
||||
int (*get_context)(struct inode *inode, void *ctx, size_t len);
|
||||
int (*set_context)(struct inode *inode, const void *ctx, size_t len,
|
||||
void *fs_data);
|
||||
const union fscrypt_context *(*get_dummy_context)(
|
||||
struct super_block *sb);
|
||||
const union fscrypt_policy *(*get_dummy_policy)(struct super_block *sb);
|
||||
bool (*empty_dir)(struct inode *inode);
|
||||
unsigned int max_namelen;
|
||||
bool (*has_stable_inodes)(struct super_block *sb);
|
||||
@@ -101,14 +100,6 @@ static inline bool fscrypt_needs_contents_encryption(const struct inode *inode)
|
||||
return IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode);
|
||||
}
|
||||
|
||||
static inline const union fscrypt_context *
|
||||
fscrypt_get_dummy_context(struct super_block *sb)
|
||||
{
|
||||
if (!sb->s_cop->get_dummy_context)
|
||||
return NULL;
|
||||
return sb->s_cop->get_dummy_context(sb);
|
||||
}
|
||||
|
||||
/*
|
||||
* When d_splice_alias() moves a directory's encrypted alias to its decrypted
|
||||
* alias as a result of the encryption key being added, DCACHE_ENCRYPTED_NAME
|
||||
@@ -158,20 +149,21 @@ int fscrypt_ioctl_get_nonce(struct file *filp, void __user *arg);
|
||||
int fscrypt_has_permitted_context(struct inode *parent, struct inode *child);
|
||||
int fscrypt_set_context(struct inode *inode, void *fs_data);
|
||||
|
||||
struct fscrypt_dummy_context {
|
||||
const union fscrypt_context *ctx;
|
||||
struct fscrypt_dummy_policy {
|
||||
const union fscrypt_policy *policy;
|
||||
};
|
||||
|
||||
int fscrypt_set_test_dummy_encryption(struct super_block *sb,
|
||||
const substring_t *arg,
|
||||
struct fscrypt_dummy_context *dummy_ctx);
|
||||
int fscrypt_set_test_dummy_encryption(
|
||||
struct super_block *sb,
|
||||
const substring_t *arg,
|
||||
struct fscrypt_dummy_policy *dummy_policy);
|
||||
void fscrypt_show_test_dummy_encryption(struct seq_file *seq, char sep,
|
||||
struct super_block *sb);
|
||||
static inline void
|
||||
fscrypt_free_dummy_context(struct fscrypt_dummy_context *dummy_ctx)
|
||||
fscrypt_free_dummy_policy(struct fscrypt_dummy_policy *dummy_policy)
|
||||
{
|
||||
kfree(dummy_ctx->ctx);
|
||||
dummy_ctx->ctx = NULL;
|
||||
kfree(dummy_policy->policy);
|
||||
dummy_policy->policy = NULL;
|
||||
}
|
||||
|
||||
/* keyring.c */
|
||||
@@ -250,12 +242,6 @@ static inline bool fscrypt_needs_contents_encryption(const struct inode *inode)
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline const union fscrypt_context *
|
||||
fscrypt_get_dummy_context(struct super_block *sb)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void fscrypt_handle_d_move(struct dentry *dentry)
|
||||
{
|
||||
}
|
||||
@@ -346,7 +332,7 @@ static inline int fscrypt_set_context(struct inode *inode, void *fs_data)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
struct fscrypt_dummy_context {
|
||||
struct fscrypt_dummy_policy {
|
||||
};
|
||||
|
||||
static inline void fscrypt_show_test_dummy_encryption(struct seq_file *seq,
|
||||
@@ -356,7 +342,7 @@ static inline void fscrypt_show_test_dummy_encryption(struct seq_file *seq,
|
||||
}
|
||||
|
||||
static inline void
|
||||
fscrypt_free_dummy_context(struct fscrypt_dummy_context *dummy_ctx)
|
||||
fscrypt_free_dummy_policy(struct fscrypt_dummy_policy *dummy_policy)
|
||||
{
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user