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:
parent
31114726b6
commit
ac4acb1f4b
@ -242,11 +242,11 @@ static int base64_decode(const char *src, int len, u8 *dst)
|
|||||||
return cp - dst;
|
return cp - dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
|
bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
|
||||||
u32 max_len, u32 *encrypted_len_ret)
|
u32 orig_len, u32 max_len,
|
||||||
|
u32 *encrypted_len_ret)
|
||||||
{
|
{
|
||||||
const struct fscrypt_info *ci = inode->i_crypt_info;
|
int padding = 4 << (fscrypt_policy_flags(policy) &
|
||||||
int padding = 4 << (fscrypt_policy_flags(&ci->ci_policy) &
|
|
||||||
FSCRYPT_POLICY_FLAGS_PAD_MASK);
|
FSCRYPT_POLICY_FLAGS_PAD_MASK);
|
||||||
u32 encrypted_len;
|
u32 encrypted_len;
|
||||||
|
|
||||||
@ -418,7 +418,8 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (fscrypt_has_encryption_key(dir)) {
|
if (fscrypt_has_encryption_key(dir)) {
|
||||||
if (!fscrypt_fname_encrypted_size(dir, iname->len,
|
if (!fscrypt_fname_encrypted_size(&dir->i_crypt_info->ci_policy,
|
||||||
|
iname->len,
|
||||||
dir->i_sb->s_cop->max_namelen,
|
dir->i_sb->s_cop->max_namelen,
|
||||||
&fname->crypto_buf.len))
|
&fname->crypto_buf.len))
|
||||||
return -ENAMETOOLONG;
|
return -ENAMETOOLONG;
|
||||||
|
@ -291,8 +291,9 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
|
|||||||
/* fname.c */
|
/* fname.c */
|
||||||
int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
|
int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
|
||||||
u8 *out, unsigned int olen);
|
u8 *out, unsigned int olen);
|
||||||
bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
|
bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
|
||||||
u32 max_len, u32 *encrypted_len_ret);
|
u32 orig_len, u32 max_len,
|
||||||
|
u32 *encrypted_len_ret);
|
||||||
extern const struct dentry_operations fscrypt_d_ops;
|
extern const struct dentry_operations fscrypt_d_ops;
|
||||||
|
|
||||||
/* hkdf.c */
|
/* hkdf.c */
|
||||||
@ -592,5 +593,6 @@ bool fscrypt_supported_policy(const union fscrypt_policy *policy_u,
|
|||||||
int fscrypt_policy_from_context(union fscrypt_policy *policy_u,
|
int fscrypt_policy_from_context(union fscrypt_policy *policy_u,
|
||||||
const union fscrypt_context *ctx_u,
|
const union fscrypt_context *ctx_u,
|
||||||
int ctx_size);
|
int ctx_size);
|
||||||
|
const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir);
|
||||||
|
|
||||||
#endif /* _FSCRYPT_PRIVATE_H */
|
#endif /* _FSCRYPT_PRIVATE_H */
|
||||||
|
@ -193,30 +193,24 @@ int fscrypt_prepare_symlink(struct inode *dir, const char *target,
|
|||||||
unsigned int len, unsigned int max_len,
|
unsigned int len, unsigned int max_len,
|
||||||
struct fscrypt_str *disk_link)
|
struct fscrypt_str *disk_link)
|
||||||
{
|
{
|
||||||
int err;
|
const union fscrypt_policy *policy;
|
||||||
|
|
||||||
if (!IS_ENCRYPTED(dir) && !fscrypt_get_dummy_context(dir->i_sb)) {
|
/*
|
||||||
|
* To calculate the size of the encrypted symlink target we need to know
|
||||||
|
* the amount of NUL padding, which is determined by the flags set in
|
||||||
|
* the encryption policy which will be inherited from the directory.
|
||||||
|
*/
|
||||||
|
policy = fscrypt_policy_to_inherit(dir);
|
||||||
|
if (policy == NULL) {
|
||||||
|
/* Not encrypted */
|
||||||
disk_link->name = (unsigned char *)target;
|
disk_link->name = (unsigned char *)target;
|
||||||
disk_link->len = len + 1;
|
disk_link->len = len + 1;
|
||||||
if (disk_link->len > max_len)
|
if (disk_link->len > max_len)
|
||||||
return -ENAMETOOLONG;
|
return -ENAMETOOLONG;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (IS_ERR(policy))
|
||||||
/*
|
return PTR_ERR(policy);
|
||||||
* To calculate the size of the encrypted symlink target we need to know
|
|
||||||
* the amount of NUL padding, which is determined by the flags set in
|
|
||||||
* the encryption policy which will be inherited from the directory.
|
|
||||||
* The easiest way to get access to this is to just load the directory's
|
|
||||||
* fscrypt_info, since we'll need it to create the dir_entry anyway.
|
|
||||||
*
|
|
||||||
* Note: in test_dummy_encryption mode, @dir may be unencrypted.
|
|
||||||
*/
|
|
||||||
err = fscrypt_get_encryption_info(dir);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
if (!fscrypt_has_encryption_key(dir))
|
|
||||||
return -ENOKEY;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate the size of the encrypted symlink and verify it won't
|
* Calculate the size of the encrypted symlink and verify it won't
|
||||||
@ -229,7 +223,7 @@ int fscrypt_prepare_symlink(struct inode *dir, const char *target,
|
|||||||
* counting it (even though it is meaningless for ciphertext) is simpler
|
* counting it (even though it is meaningless for ciphertext) is simpler
|
||||||
* for now since filesystems will assume it is there and subtract it.
|
* for now since filesystems will assume it is there and subtract it.
|
||||||
*/
|
*/
|
||||||
if (!fscrypt_fname_encrypted_size(dir, len,
|
if (!fscrypt_fname_encrypted_size(policy, len,
|
||||||
max_len - sizeof(struct fscrypt_symlink_data),
|
max_len - sizeof(struct fscrypt_symlink_data),
|
||||||
&disk_link->len))
|
&disk_link->len))
|
||||||
return -ENAMETOOLONG;
|
return -ENAMETOOLONG;
|
||||||
|
@ -547,7 +547,7 @@ out:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* fscrypt_get_encryption_info() - set up an inode's encryption key
|
* fscrypt_get_encryption_info() - set up an inode's encryption key
|
||||||
* @inode: the inode to set up the key for
|
* @inode: the inode to set up the key for. Must be encrypted.
|
||||||
*
|
*
|
||||||
* Set up ->i_crypt_info, if it hasn't already been done.
|
* Set up ->i_crypt_info, if it hasn't already been done.
|
||||||
*
|
*
|
||||||
@ -569,18 +569,8 @@ int fscrypt_get_encryption_info(struct inode *inode)
|
|||||||
|
|
||||||
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
|
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
const union fscrypt_context *dummy_ctx =
|
fscrypt_warn(inode, "Error %d getting encryption context", res);
|
||||||
fscrypt_get_dummy_context(inode->i_sb);
|
return res;
|
||||||
|
|
||||||
if (IS_ENCRYPTED(inode) || !dummy_ctx) {
|
|
||||||
fscrypt_warn(inode,
|
|
||||||
"Error %d getting encryption context",
|
|
||||||
res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
/* Fake up a context for an unencrypted directory */
|
|
||||||
res = fscrypt_context_size(dummy_ctx);
|
|
||||||
memcpy(&ctx, dummy_ctx, res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fscrypt_policy_from_context(&policy, &ctx, res);
|
res = fscrypt_policy_from_context(&policy, &ctx, res);
|
||||||
@ -627,17 +617,14 @@ EXPORT_SYMBOL(fscrypt_get_encryption_info);
|
|||||||
int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
|
int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
|
||||||
bool *encrypt_ret)
|
bool *encrypt_ret)
|
||||||
{
|
{
|
||||||
int err;
|
const union fscrypt_policy *policy;
|
||||||
u8 nonce[FSCRYPT_FILE_NONCE_SIZE];
|
u8 nonce[FSCRYPT_FILE_NONCE_SIZE];
|
||||||
|
|
||||||
if (!IS_ENCRYPTED(dir) && fscrypt_get_dummy_context(dir->i_sb) == NULL)
|
policy = fscrypt_policy_to_inherit(dir);
|
||||||
|
if (policy == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (IS_ERR(policy))
|
||||||
err = fscrypt_get_encryption_info(dir);
|
return PTR_ERR(policy);
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
if (!fscrypt_has_encryption_key(dir))
|
|
||||||
return -ENOKEY;
|
|
||||||
|
|
||||||
if (WARN_ON_ONCE(inode->i_mode == 0))
|
if (WARN_ON_ONCE(inode->i_mode == 0))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -654,9 +641,7 @@ int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
|
|||||||
*encrypt_ret = true;
|
*encrypt_ret = true;
|
||||||
|
|
||||||
get_random_bytes(nonce, FSCRYPT_FILE_NONCE_SIZE);
|
get_random_bytes(nonce, FSCRYPT_FILE_NONCE_SIZE);
|
||||||
return fscrypt_setup_encryption_info(inode,
|
return fscrypt_setup_encryption_info(inode, policy, nonce,
|
||||||
&dir->i_crypt_info->ci_policy,
|
|
||||||
nonce,
|
|
||||||
IS_CASEFOLDED(dir) &&
|
IS_CASEFOLDED(dir) &&
|
||||||
S_ISDIR(inode->i_mode));
|
S_ISDIR(inode->i_mode));
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,14 @@ bool fscrypt_policies_equal(const union fscrypt_policy *policy1,
|
|||||||
return !memcmp(policy1, policy2, fscrypt_policy_size(policy1));
|
return !memcmp(policy1, policy2, fscrypt_policy_size(policy1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const union fscrypt_policy *
|
||||||
|
fscrypt_get_dummy_policy(struct super_block *sb)
|
||||||
|
{
|
||||||
|
if (!sb->s_cop->get_dummy_policy)
|
||||||
|
return NULL;
|
||||||
|
return sb->s_cop->get_dummy_policy(sb);
|
||||||
|
}
|
||||||
|
|
||||||
static bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode)
|
static bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode)
|
||||||
{
|
{
|
||||||
if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
|
if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
|
||||||
@ -628,6 +636,25 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fscrypt_has_permitted_context);
|
EXPORT_SYMBOL(fscrypt_has_permitted_context);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the encryption policy that new files in the directory will inherit, or
|
||||||
|
* NULL if none, or an ERR_PTR() on error. If the directory is encrypted, also
|
||||||
|
* ensure that its key is set up, so that the new filename can be encrypted.
|
||||||
|
*/
|
||||||
|
const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (IS_ENCRYPTED(dir)) {
|
||||||
|
err = fscrypt_require_key(dir);
|
||||||
|
if (err)
|
||||||
|
return ERR_PTR(err);
|
||||||
|
return &dir->i_crypt_info->ci_policy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fscrypt_get_dummy_policy(dir->i_sb);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fscrypt_set_context() - Set the fscrypt context of a new inode
|
* fscrypt_set_context() - Set the fscrypt context of a new inode
|
||||||
* @inode: a new inode
|
* @inode: a new inode
|
||||||
@ -672,31 +699,28 @@ EXPORT_SYMBOL_GPL(fscrypt_set_context);
|
|||||||
* @sb: the filesystem on which test_dummy_encryption is being specified
|
* @sb: the filesystem on which test_dummy_encryption is being specified
|
||||||
* @arg: the argument to the test_dummy_encryption option.
|
* @arg: the argument to the test_dummy_encryption option.
|
||||||
* If no argument was specified, then @arg->from == NULL.
|
* If no argument was specified, then @arg->from == NULL.
|
||||||
* @dummy_ctx: the filesystem's current dummy context (input/output, see below)
|
* @dummy_policy: the filesystem's current dummy policy (input/output, see
|
||||||
|
* below)
|
||||||
*
|
*
|
||||||
* Handle the test_dummy_encryption mount option by creating a dummy encryption
|
* Handle the test_dummy_encryption mount option by creating a dummy encryption
|
||||||
* context, saving it in @dummy_ctx, and adding the corresponding dummy
|
* policy, saving it in @dummy_policy, and adding the corresponding dummy
|
||||||
* encryption key to the filesystem. If the @dummy_ctx is already set, then
|
* encryption key to the filesystem. If the @dummy_policy is already set, then
|
||||||
* instead validate that it matches @arg. Don't support changing it via
|
* instead validate that it matches @arg. Don't support changing it via
|
||||||
* remount, as that is difficult to do safely.
|
* remount, as that is difficult to do safely.
|
||||||
*
|
*
|
||||||
* The reason we use an fscrypt_context rather than an fscrypt_policy is because
|
* Return: 0 on success (dummy policy set, or the same policy is already set);
|
||||||
* we mustn't generate a new nonce each time we access a dummy-encrypted
|
* -EEXIST if a different dummy policy is already set;
|
||||||
* directory, as that would change the way filenames are encrypted.
|
|
||||||
*
|
|
||||||
* Return: 0 on success (dummy context set, or the same context is already set);
|
|
||||||
* -EEXIST if a different dummy context is already set;
|
|
||||||
* or another -errno value.
|
* or another -errno value.
|
||||||
*/
|
*/
|
||||||
int fscrypt_set_test_dummy_encryption(struct super_block *sb,
|
int fscrypt_set_test_dummy_encryption(struct super_block *sb,
|
||||||
const substring_t *arg,
|
const substring_t *arg,
|
||||||
struct fscrypt_dummy_context *dummy_ctx)
|
struct fscrypt_dummy_policy *dummy_policy)
|
||||||
{
|
{
|
||||||
const char *argstr = "v2";
|
const char *argstr = "v2";
|
||||||
const char *argstr_to_free = NULL;
|
const char *argstr_to_free = NULL;
|
||||||
struct fscrypt_key_specifier key_spec = { 0 };
|
struct fscrypt_key_specifier key_spec = { 0 };
|
||||||
int version;
|
int version;
|
||||||
union fscrypt_context *ctx = NULL;
|
union fscrypt_policy *policy = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (arg->from) {
|
if (arg->from) {
|
||||||
@ -706,12 +730,12 @@ int fscrypt_set_test_dummy_encryption(struct super_block *sb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(argstr, "v1")) {
|
if (!strcmp(argstr, "v1")) {
|
||||||
version = FSCRYPT_CONTEXT_V1;
|
version = FSCRYPT_POLICY_V1;
|
||||||
key_spec.type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
|
key_spec.type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
|
||||||
memset(key_spec.u.descriptor, 0x42,
|
memset(key_spec.u.descriptor, 0x42,
|
||||||
FSCRYPT_KEY_DESCRIPTOR_SIZE);
|
FSCRYPT_KEY_DESCRIPTOR_SIZE);
|
||||||
} else if (!strcmp(argstr, "v2")) {
|
} else if (!strcmp(argstr, "v2")) {
|
||||||
version = FSCRYPT_CONTEXT_V2;
|
version = FSCRYPT_POLICY_V2;
|
||||||
key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
|
key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
|
||||||
/* key_spec.u.identifier gets filled in when adding the key */
|
/* key_spec.u.identifier gets filled in when adding the key */
|
||||||
} else {
|
} else {
|
||||||
@ -719,21 +743,8 @@ int fscrypt_set_test_dummy_encryption(struct super_block *sb,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dummy_ctx->ctx) {
|
policy = kzalloc(sizeof(*policy), GFP_KERNEL);
|
||||||
/*
|
if (!policy) {
|
||||||
* Note: if we ever make test_dummy_encryption support
|
|
||||||
* specifying other encryption settings, such as the encryption
|
|
||||||
* modes, we'll need to compare those settings here.
|
|
||||||
*/
|
|
||||||
if (dummy_ctx->ctx->version == version)
|
|
||||||
err = 0;
|
|
||||||
else
|
|
||||||
err = -EEXIST;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
|
||||||
if (!ctx) {
|
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -742,18 +753,18 @@ int fscrypt_set_test_dummy_encryption(struct super_block *sb,
|
|||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ctx->version = version;
|
policy->version = version;
|
||||||
switch (ctx->version) {
|
switch (policy->version) {
|
||||||
case FSCRYPT_CONTEXT_V1:
|
case FSCRYPT_POLICY_V1:
|
||||||
ctx->v1.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
|
policy->v1.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
|
||||||
ctx->v1.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
|
policy->v1.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
|
||||||
memcpy(ctx->v1.master_key_descriptor, key_spec.u.descriptor,
|
memcpy(policy->v1.master_key_descriptor, key_spec.u.descriptor,
|
||||||
FSCRYPT_KEY_DESCRIPTOR_SIZE);
|
FSCRYPT_KEY_DESCRIPTOR_SIZE);
|
||||||
break;
|
break;
|
||||||
case FSCRYPT_CONTEXT_V2:
|
case FSCRYPT_POLICY_V2:
|
||||||
ctx->v2.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
|
policy->v2.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
|
||||||
ctx->v2.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
|
policy->v2.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
|
||||||
memcpy(ctx->v2.master_key_identifier, key_spec.u.identifier,
|
memcpy(policy->v2.master_key_identifier, key_spec.u.identifier,
|
||||||
FSCRYPT_KEY_IDENTIFIER_SIZE);
|
FSCRYPT_KEY_IDENTIFIER_SIZE);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -761,11 +772,19 @@ int fscrypt_set_test_dummy_encryption(struct super_block *sb,
|
|||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
dummy_ctx->ctx = ctx;
|
|
||||||
ctx = NULL;
|
if (dummy_policy->policy) {
|
||||||
|
if (fscrypt_policies_equal(policy, dummy_policy->policy))
|
||||||
|
err = 0;
|
||||||
|
else
|
||||||
|
err = -EEXIST;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
dummy_policy->policy = policy;
|
||||||
|
policy = NULL;
|
||||||
err = 0;
|
err = 0;
|
||||||
out:
|
out:
|
||||||
kfree(ctx);
|
kfree(policy);
|
||||||
kfree(argstr_to_free);
|
kfree(argstr_to_free);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -783,10 +802,16 @@ EXPORT_SYMBOL_GPL(fscrypt_set_test_dummy_encryption);
|
|||||||
void fscrypt_show_test_dummy_encryption(struct seq_file *seq, char sep,
|
void fscrypt_show_test_dummy_encryption(struct seq_file *seq, char sep,
|
||||||
struct super_block *sb)
|
struct super_block *sb)
|
||||||
{
|
{
|
||||||
const union fscrypt_context *ctx = fscrypt_get_dummy_context(sb);
|
const union fscrypt_policy *policy = fscrypt_get_dummy_policy(sb);
|
||||||
|
int vers;
|
||||||
|
|
||||||
if (!ctx)
|
if (!policy)
|
||||||
return;
|
return;
|
||||||
seq_printf(seq, "%ctest_dummy_encryption=v%d", sep, ctx->version);
|
|
||||||
|
vers = policy->version;
|
||||||
|
if (vers == FSCRYPT_POLICY_V1) /* Handle numbering quirk */
|
||||||
|
vers = 1;
|
||||||
|
|
||||||
|
seq_printf(seq, "%ctest_dummy_encryption=v%d", sep, vers);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fscrypt_show_test_dummy_encryption);
|
EXPORT_SYMBOL_GPL(fscrypt_show_test_dummy_encryption);
|
||||||
|
@ -1401,7 +1401,7 @@ struct ext4_super_block {
|
|||||||
#define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
|
#define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
|
||||||
|
|
||||||
#ifdef CONFIG_FS_ENCRYPTION
|
#ifdef CONFIG_FS_ENCRYPTION
|
||||||
#define DUMMY_ENCRYPTION_ENABLED(sbi) ((sbi)->s_dummy_enc_ctx.ctx != NULL)
|
#define DUMMY_ENCRYPTION_ENABLED(sbi) ((sbi)->s_dummy_enc_policy.policy != NULL)
|
||||||
#else
|
#else
|
||||||
#define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
|
#define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
|
||||||
#endif
|
#endif
|
||||||
@ -1596,8 +1596,8 @@ struct ext4_sb_info {
|
|||||||
atomic_t s_warning_count;
|
atomic_t s_warning_count;
|
||||||
atomic_t s_msg_count;
|
atomic_t s_msg_count;
|
||||||
|
|
||||||
/* Encryption context for '-o test_dummy_encryption' */
|
/* Encryption policy for '-o test_dummy_encryption' */
|
||||||
struct fscrypt_dummy_context s_dummy_enc_ctx;
|
struct fscrypt_dummy_policy s_dummy_enc_policy;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Barrier between writepages ops and changing any inode's JOURNAL_DATA
|
* Barrier between writepages ops and changing any inode's JOURNAL_DATA
|
||||||
|
@ -1104,7 +1104,7 @@ static void ext4_put_super(struct super_block *sb)
|
|||||||
crypto_free_shash(sbi->s_chksum_driver);
|
crypto_free_shash(sbi->s_chksum_driver);
|
||||||
kfree(sbi->s_blockgroup_lock);
|
kfree(sbi->s_blockgroup_lock);
|
||||||
fs_put_dax(sbi->s_daxdev);
|
fs_put_dax(sbi->s_daxdev);
|
||||||
fscrypt_free_dummy_context(&sbi->s_dummy_enc_ctx);
|
fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
|
||||||
#ifdef CONFIG_UNICODE
|
#ifdef CONFIG_UNICODE
|
||||||
utf8_unload(sbi->s_encoding);
|
utf8_unload(sbi->s_encoding);
|
||||||
#endif
|
#endif
|
||||||
@ -1392,10 +1392,9 @@ retry:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const union fscrypt_context *
|
static const union fscrypt_policy *ext4_get_dummy_policy(struct super_block *sb)
|
||||||
ext4_get_dummy_context(struct super_block *sb)
|
|
||||||
{
|
{
|
||||||
return EXT4_SB(sb)->s_dummy_enc_ctx.ctx;
|
return EXT4_SB(sb)->s_dummy_enc_policy.policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ext4_has_stable_inodes(struct super_block *sb)
|
static bool ext4_has_stable_inodes(struct super_block *sb)
|
||||||
@ -1414,7 +1413,7 @@ static const struct fscrypt_operations ext4_cryptops = {
|
|||||||
.key_prefix = "ext4:",
|
.key_prefix = "ext4:",
|
||||||
.get_context = ext4_get_context,
|
.get_context = ext4_get_context,
|
||||||
.set_context = ext4_set_context,
|
.set_context = ext4_set_context,
|
||||||
.get_dummy_context = ext4_get_dummy_context,
|
.get_dummy_policy = ext4_get_dummy_policy,
|
||||||
.empty_dir = ext4_empty_dir,
|
.empty_dir = ext4_empty_dir,
|
||||||
.max_namelen = EXT4_NAME_LEN,
|
.max_namelen = EXT4_NAME_LEN,
|
||||||
.has_stable_inodes = ext4_has_stable_inodes,
|
.has_stable_inodes = ext4_has_stable_inodes,
|
||||||
@ -1888,12 +1887,13 @@ static int ext4_set_test_dummy_encryption(struct super_block *sb,
|
|||||||
* needed to allow it to be set or changed during remount. We do allow
|
* needed to allow it to be set or changed during remount. We do allow
|
||||||
* it to be specified during remount, but only if there is no change.
|
* it to be specified during remount, but only if there is no change.
|
||||||
*/
|
*/
|
||||||
if (is_remount && !sbi->s_dummy_enc_ctx.ctx) {
|
if (is_remount && !sbi->s_dummy_enc_policy.policy) {
|
||||||
ext4_msg(sb, KERN_WARNING,
|
ext4_msg(sb, KERN_WARNING,
|
||||||
"Can't set test_dummy_encryption on remount");
|
"Can't set test_dummy_encryption on remount");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
err = fscrypt_set_test_dummy_encryption(sb, arg, &sbi->s_dummy_enc_ctx);
|
err = fscrypt_set_test_dummy_encryption(sb, arg,
|
||||||
|
&sbi->s_dummy_enc_policy);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err == -EEXIST)
|
if (err == -EEXIST)
|
||||||
ext4_msg(sb, KERN_WARNING,
|
ext4_msg(sb, KERN_WARNING,
|
||||||
@ -4935,7 +4935,7 @@ failed_mount:
|
|||||||
for (i = 0; i < EXT4_MAXQUOTAS; i++)
|
for (i = 0; i < EXT4_MAXQUOTAS; i++)
|
||||||
kfree(get_qf_name(sb, sbi, i));
|
kfree(get_qf_name(sb, sbi, i));
|
||||||
#endif
|
#endif
|
||||||
fscrypt_free_dummy_context(&sbi->s_dummy_enc_ctx);
|
fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
|
||||||
ext4_blkdev_remove(sbi);
|
ext4_blkdev_remove(sbi);
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
out_fail:
|
out_fail:
|
||||||
|
@ -138,7 +138,7 @@ struct f2fs_mount_info {
|
|||||||
int fsync_mode; /* fsync policy */
|
int fsync_mode; /* fsync policy */
|
||||||
int fs_mode; /* fs mode: LFS or ADAPTIVE */
|
int fs_mode; /* fs mode: LFS or ADAPTIVE */
|
||||||
int bggc_mode; /* bggc mode: off, on or sync */
|
int bggc_mode; /* bggc mode: off, on or sync */
|
||||||
struct fscrypt_dummy_context dummy_enc_ctx; /* test dummy encryption */
|
struct fscrypt_dummy_policy dummy_enc_policy; /* test dummy encryption */
|
||||||
block_t unusable_cap_perc; /* percentage for cap */
|
block_t unusable_cap_perc; /* percentage for cap */
|
||||||
block_t unusable_cap; /* Amount of space allowed to be
|
block_t unusable_cap; /* Amount of space allowed to be
|
||||||
* unusable when disabling checkpoint
|
* unusable when disabling checkpoint
|
||||||
|
@ -433,12 +433,12 @@ static int f2fs_set_test_dummy_encryption(struct super_block *sb,
|
|||||||
* needed to allow it to be set or changed during remount. We do allow
|
* needed to allow it to be set or changed during remount. We do allow
|
||||||
* it to be specified during remount, but only if there is no change.
|
* it to be specified during remount, but only if there is no change.
|
||||||
*/
|
*/
|
||||||
if (is_remount && !F2FS_OPTION(sbi).dummy_enc_ctx.ctx) {
|
if (is_remount && !F2FS_OPTION(sbi).dummy_enc_policy.policy) {
|
||||||
f2fs_warn(sbi, "Can't set test_dummy_encryption on remount");
|
f2fs_warn(sbi, "Can't set test_dummy_encryption on remount");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = fscrypt_set_test_dummy_encryption(
|
err = fscrypt_set_test_dummy_encryption(
|
||||||
sb, arg, &F2FS_OPTION(sbi).dummy_enc_ctx);
|
sb, arg, &F2FS_OPTION(sbi).dummy_enc_policy);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err == -EEXIST)
|
if (err == -EEXIST)
|
||||||
f2fs_warn(sbi,
|
f2fs_warn(sbi,
|
||||||
@ -1275,7 +1275,7 @@ static void f2fs_put_super(struct super_block *sb)
|
|||||||
for (i = 0; i < MAXQUOTAS; i++)
|
for (i = 0; i < MAXQUOTAS; i++)
|
||||||
kfree(F2FS_OPTION(sbi).s_qf_names[i]);
|
kfree(F2FS_OPTION(sbi).s_qf_names[i]);
|
||||||
#endif
|
#endif
|
||||||
fscrypt_free_dummy_context(&F2FS_OPTION(sbi).dummy_enc_ctx);
|
fscrypt_free_dummy_policy(&F2FS_OPTION(sbi).dummy_enc_policy);
|
||||||
destroy_percpu_info(sbi);
|
destroy_percpu_info(sbi);
|
||||||
for (i = 0; i < NR_PAGE_TYPE; i++)
|
for (i = 0; i < NR_PAGE_TYPE; i++)
|
||||||
kvfree(sbi->write_io[i]);
|
kvfree(sbi->write_io[i]);
|
||||||
@ -2482,10 +2482,9 @@ static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len,
|
|||||||
ctx, len, fs_data, XATTR_CREATE);
|
ctx, len, fs_data, XATTR_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const union fscrypt_context *
|
static const union fscrypt_policy *f2fs_get_dummy_policy(struct super_block *sb)
|
||||||
f2fs_get_dummy_context(struct super_block *sb)
|
|
||||||
{
|
{
|
||||||
return F2FS_OPTION(F2FS_SB(sb)).dummy_enc_ctx.ctx;
|
return F2FS_OPTION(F2FS_SB(sb)).dummy_enc_policy.policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool f2fs_has_stable_inodes(struct super_block *sb)
|
static bool f2fs_has_stable_inodes(struct super_block *sb)
|
||||||
@ -2523,7 +2522,7 @@ static const struct fscrypt_operations f2fs_cryptops = {
|
|||||||
.key_prefix = "f2fs:",
|
.key_prefix = "f2fs:",
|
||||||
.get_context = f2fs_get_context,
|
.get_context = f2fs_get_context,
|
||||||
.set_context = f2fs_set_context,
|
.set_context = f2fs_set_context,
|
||||||
.get_dummy_context = f2fs_get_dummy_context,
|
.get_dummy_policy = f2fs_get_dummy_policy,
|
||||||
.empty_dir = f2fs_empty_dir,
|
.empty_dir = f2fs_empty_dir,
|
||||||
.max_namelen = F2FS_NAME_LEN,
|
.max_namelen = F2FS_NAME_LEN,
|
||||||
.has_stable_inodes = f2fs_has_stable_inodes,
|
.has_stable_inodes = f2fs_has_stable_inodes,
|
||||||
@ -3864,7 +3863,7 @@ free_options:
|
|||||||
for (i = 0; i < MAXQUOTAS; i++)
|
for (i = 0; i < MAXQUOTAS; i++)
|
||||||
kfree(F2FS_OPTION(sbi).s_qf_names[i]);
|
kfree(F2FS_OPTION(sbi).s_qf_names[i]);
|
||||||
#endif
|
#endif
|
||||||
fscrypt_free_dummy_context(&F2FS_OPTION(sbi).dummy_enc_ctx);
|
fscrypt_free_dummy_policy(&F2FS_OPTION(sbi).dummy_enc_policy);
|
||||||
kvfree(options);
|
kvfree(options);
|
||||||
free_sb_buf:
|
free_sb_buf:
|
||||||
kfree(raw_super);
|
kfree(raw_super);
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#define FS_CRYPTO_BLOCK_SIZE 16
|
#define FS_CRYPTO_BLOCK_SIZE 16
|
||||||
|
|
||||||
union fscrypt_context;
|
union fscrypt_policy;
|
||||||
struct fscrypt_info;
|
struct fscrypt_info;
|
||||||
struct seq_file;
|
struct seq_file;
|
||||||
|
|
||||||
@ -62,8 +62,7 @@ struct fscrypt_operations {
|
|||||||
int (*get_context)(struct inode *inode, void *ctx, size_t len);
|
int (*get_context)(struct inode *inode, void *ctx, size_t len);
|
||||||
int (*set_context)(struct inode *inode, const void *ctx, size_t len,
|
int (*set_context)(struct inode *inode, const void *ctx, size_t len,
|
||||||
void *fs_data);
|
void *fs_data);
|
||||||
const union fscrypt_context *(*get_dummy_context)(
|
const union fscrypt_policy *(*get_dummy_policy)(struct super_block *sb);
|
||||||
struct super_block *sb);
|
|
||||||
bool (*empty_dir)(struct inode *inode);
|
bool (*empty_dir)(struct inode *inode);
|
||||||
unsigned int max_namelen;
|
unsigned int max_namelen;
|
||||||
bool (*has_stable_inodes)(struct super_block *sb);
|
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);
|
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
|
* 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
|
* 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_has_permitted_context(struct inode *parent, struct inode *child);
|
||||||
int fscrypt_set_context(struct inode *inode, void *fs_data);
|
int fscrypt_set_context(struct inode *inode, void *fs_data);
|
||||||
|
|
||||||
struct fscrypt_dummy_context {
|
struct fscrypt_dummy_policy {
|
||||||
const union fscrypt_context *ctx;
|
const union fscrypt_policy *policy;
|
||||||
};
|
};
|
||||||
|
|
||||||
int fscrypt_set_test_dummy_encryption(struct super_block *sb,
|
int fscrypt_set_test_dummy_encryption(
|
||||||
const substring_t *arg,
|
struct super_block *sb,
|
||||||
struct fscrypt_dummy_context *dummy_ctx);
|
const substring_t *arg,
|
||||||
|
struct fscrypt_dummy_policy *dummy_policy);
|
||||||
void fscrypt_show_test_dummy_encryption(struct seq_file *seq, char sep,
|
void fscrypt_show_test_dummy_encryption(struct seq_file *seq, char sep,
|
||||||
struct super_block *sb);
|
struct super_block *sb);
|
||||||
static inline void
|
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);
|
kfree(dummy_policy->policy);
|
||||||
dummy_ctx->ctx = NULL;
|
dummy_policy->policy = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* keyring.c */
|
/* keyring.c */
|
||||||
@ -250,12 +242,6 @@ static inline bool fscrypt_needs_contents_encryption(const struct inode *inode)
|
|||||||
return false;
|
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)
|
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;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fscrypt_dummy_context {
|
struct fscrypt_dummy_policy {
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void fscrypt_show_test_dummy_encryption(struct seq_file *seq,
|
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
|
static inline void
|
||||||
fscrypt_free_dummy_context(struct fscrypt_dummy_context *dummy_ctx)
|
fscrypt_free_dummy_policy(struct fscrypt_dummy_policy *dummy_policy)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user