forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
f2fs crypto: add encryption policy and password salt support
This patch adds encryption policy and password salt support through ioctl implementation. It adds three ioctls: F2FS_IOC_SET_ENCRYPTION_POLICY, F2FS_IOC_GET_ENCRYPTION_POLICY, F2FS_IOC_GET_ENCRYPTION_PWSALT, which use xattr operations. Note that, these definition and codes are taken from ext4 crypto support. For f2fs, xattr operations and on-disk flags for superblock and inode were changed. Signed-off-by: Michael Halcrow <mhalcrow@google.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Ildar Muslukhov <muslukhovi@gmail.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
- Loading branch information
Jaegeuk Kim
committed
May 28, 2015
1 parent
b93531d
commit f424f66
Showing
5 changed files
with
319 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
/* | ||
* copied from linux/fs/ext4/crypto_policy.c | ||
* | ||
* Copyright (C) 2015, Google, Inc. | ||
* Copyright (C) 2015, Motorola Mobility. | ||
* | ||
* This contains encryption policy functions for f2fs with some modifications | ||
* to support f2fs-specific xattr APIs. | ||
* | ||
* Written by Michael Halcrow, 2015. | ||
* Modified by Jaegeuk Kim, 2015. | ||
*/ | ||
#include <linux/random.h> | ||
#include <linux/string.h> | ||
#include <linux/types.h> | ||
#include <linux/f2fs_fs.h> | ||
|
||
#include "f2fs.h" | ||
#include "xattr.h" | ||
|
||
static int f2fs_inode_has_encryption_context(struct inode *inode) | ||
{ | ||
int res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, | ||
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, NULL, 0, NULL); | ||
return (res > 0); | ||
} | ||
|
||
/* | ||
* check whether the policy is consistent with the encryption context | ||
* for the inode | ||
*/ | ||
static int f2fs_is_encryption_context_consistent_with_policy( | ||
struct inode *inode, const struct f2fs_encryption_policy *policy) | ||
{ | ||
struct f2fs_encryption_context ctx; | ||
int res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, | ||
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx, | ||
sizeof(ctx), NULL); | ||
|
||
if (res != sizeof(ctx)) | ||
return 0; | ||
|
||
return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor, | ||
F2FS_KEY_DESCRIPTOR_SIZE) == 0 && | ||
(ctx.flags == policy->flags) && | ||
(ctx.contents_encryption_mode == | ||
policy->contents_encryption_mode) && | ||
(ctx.filenames_encryption_mode == | ||
policy->filenames_encryption_mode)); | ||
} | ||
|
||
static int f2fs_create_encryption_context_from_policy( | ||
struct inode *inode, const struct f2fs_encryption_policy *policy) | ||
{ | ||
struct f2fs_encryption_context ctx; | ||
|
||
ctx.format = F2FS_ENCRYPTION_CONTEXT_FORMAT_V1; | ||
memcpy(ctx.master_key_descriptor, policy->master_key_descriptor, | ||
F2FS_KEY_DESCRIPTOR_SIZE); | ||
|
||
if (!f2fs_valid_contents_enc_mode(policy->contents_encryption_mode)) { | ||
printk(KERN_WARNING | ||
"%s: Invalid contents encryption mode %d\n", __func__, | ||
policy->contents_encryption_mode); | ||
return -EINVAL; | ||
} | ||
|
||
if (!f2fs_valid_filenames_enc_mode(policy->filenames_encryption_mode)) { | ||
printk(KERN_WARNING | ||
"%s: Invalid filenames encryption mode %d\n", __func__, | ||
policy->filenames_encryption_mode); | ||
return -EINVAL; | ||
} | ||
|
||
if (policy->flags & ~F2FS_POLICY_FLAGS_VALID) | ||
return -EINVAL; | ||
|
||
ctx.contents_encryption_mode = policy->contents_encryption_mode; | ||
ctx.filenames_encryption_mode = policy->filenames_encryption_mode; | ||
ctx.flags = policy->flags; | ||
BUILD_BUG_ON(sizeof(ctx.nonce) != F2FS_KEY_DERIVATION_NONCE_SIZE); | ||
get_random_bytes(ctx.nonce, F2FS_KEY_DERIVATION_NONCE_SIZE); | ||
|
||
return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, | ||
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx, | ||
sizeof(ctx), NULL, 0); | ||
} | ||
|
||
int f2fs_process_policy(const struct f2fs_encryption_policy *policy, | ||
struct inode *inode) | ||
{ | ||
if (policy->version != 0) | ||
return -EINVAL; | ||
|
||
if (!f2fs_inode_has_encryption_context(inode)) { | ||
if (!f2fs_empty_dir(inode)) | ||
return -ENOTEMPTY; | ||
return f2fs_create_encryption_context_from_policy(inode, | ||
policy); | ||
} | ||
|
||
if (f2fs_is_encryption_context_consistent_with_policy(inode, policy)) | ||
return 0; | ||
|
||
printk(KERN_WARNING "%s: Policy inconsistent with encryption context\n", | ||
__func__); | ||
return -EINVAL; | ||
} | ||
|
||
int f2fs_get_policy(struct inode *inode, struct f2fs_encryption_policy *policy) | ||
{ | ||
struct f2fs_encryption_context ctx; | ||
int res; | ||
|
||
if (!f2fs_encrypted_inode(inode)) | ||
return -ENODATA; | ||
|
||
res = f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, | ||
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, | ||
&ctx, sizeof(ctx), NULL); | ||
if (res != sizeof(ctx)) | ||
return -ENODATA; | ||
if (ctx.format != F2FS_ENCRYPTION_CONTEXT_FORMAT_V1) | ||
return -EINVAL; | ||
|
||
policy->version = 0; | ||
policy->contents_encryption_mode = ctx.contents_encryption_mode; | ||
policy->filenames_encryption_mode = ctx.filenames_encryption_mode; | ||
policy->flags = ctx.flags; | ||
memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor, | ||
F2FS_KEY_DESCRIPTOR_SIZE); | ||
return 0; | ||
} | ||
|
||
int f2fs_is_child_context_consistent_with_parent(struct inode *parent, | ||
struct inode *child) | ||
{ | ||
struct f2fs_crypt_info *parent_ci, *child_ci; | ||
int res; | ||
|
||
if ((parent == NULL) || (child == NULL)) { | ||
pr_err("parent %p child %p\n", parent, child); | ||
BUG_ON(1); | ||
} | ||
|
||
/* no restrictions if the parent directory is not encrypted */ | ||
if (!f2fs_encrypted_inode(parent)) | ||
return 1; | ||
/* if the child directory is not encrypted, this is always a problem */ | ||
if (!f2fs_encrypted_inode(child)) | ||
return 0; | ||
res = f2fs_get_encryption_info(parent); | ||
if (res) | ||
return 0; | ||
res = f2fs_get_encryption_info(child); | ||
if (res) | ||
return 0; | ||
parent_ci = F2FS_I(parent)->i_crypt_info; | ||
child_ci = F2FS_I(child)->i_crypt_info; | ||
if (!parent_ci && !child_ci) | ||
return 1; | ||
if (!parent_ci || !child_ci) | ||
return 0; | ||
|
||
return (memcmp(parent_ci->ci_master_key, | ||
child_ci->ci_master_key, | ||
F2FS_KEY_DESCRIPTOR_SIZE) == 0 && | ||
(parent_ci->ci_data_mode == child_ci->ci_data_mode) && | ||
(parent_ci->ci_filename_mode == child_ci->ci_filename_mode) && | ||
(parent_ci->ci_flags == child_ci->ci_flags)); | ||
} | ||
|
||
/** | ||
* f2fs_inherit_context() - Sets a child context from its parent | ||
* @parent: Parent inode from which the context is inherited. | ||
* @child: Child inode that inherits the context from @parent. | ||
* | ||
* Return: Zero on success, non-zero otherwise | ||
*/ | ||
int f2fs_inherit_context(struct inode *parent, struct inode *child, | ||
struct page *ipage) | ||
{ | ||
struct f2fs_encryption_context ctx; | ||
struct f2fs_crypt_info *ci; | ||
int res; | ||
|
||
res = f2fs_get_encryption_info(parent); | ||
if (res < 0) | ||
return res; | ||
|
||
ci = F2FS_I(parent)->i_crypt_info; | ||
BUG_ON(ci == NULL); | ||
|
||
ctx.format = F2FS_ENCRYPTION_CONTEXT_FORMAT_V1; | ||
|
||
ctx.contents_encryption_mode = ci->ci_data_mode; | ||
ctx.filenames_encryption_mode = ci->ci_filename_mode; | ||
ctx.flags = ci->ci_flags; | ||
memcpy(ctx.master_key_descriptor, ci->ci_master_key, | ||
F2FS_KEY_DESCRIPTOR_SIZE); | ||
|
||
get_random_bytes(ctx.nonce, F2FS_KEY_DERIVATION_NONCE_SIZE); | ||
return f2fs_setxattr(child, F2FS_XATTR_INDEX_ENCRYPTION, | ||
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx, | ||
sizeof(ctx), ipage, 0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters