policy.c 6.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * Encryption policy functions for per-file encryption support.
 *
 * Copyright (C) 2015, Google, Inc.
 * Copyright (C) 2015, Motorola Mobility.
 *
 * Written by Michael Halcrow, 2015.
 * Modified by Jaegeuk Kim, 2015.
 */

#include <linux/random.h>
#include <linux/string.h>
13
#include <linux/mount.h>
14
#include "fscrypt_private.h"
15 16

/*
17
 * check whether an encryption policy is consistent with an encryption context
18
 */
19 20
static bool is_encryption_context_consistent_with_policy(
				const struct fscrypt_context *ctx,
21 22
				const struct fscrypt_policy *policy)
{
23 24 25 26 27 28 29
	return memcmp(ctx->master_key_descriptor, policy->master_key_descriptor,
		      FS_KEY_DESCRIPTOR_SIZE) == 0 &&
		(ctx->flags == policy->flags) &&
		(ctx->contents_encryption_mode ==
		 policy->contents_encryption_mode) &&
		(ctx->filenames_encryption_mode ==
		 policy->filenames_encryption_mode);
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
}

static int create_encryption_context_from_policy(struct inode *inode,
				const struct fscrypt_policy *policy)
{
	struct fscrypt_context ctx;
	int res;

	if (!inode->i_sb->s_cop->set_context)
		return -EOPNOTSUPP;

	if (inode->i_sb->s_cop->prepare_context) {
		res = inode->i_sb->s_cop->prepare_context(inode);
		if (res)
			return res;
	}

	ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
	memcpy(ctx.master_key_descriptor, policy->master_key_descriptor,
					FS_KEY_DESCRIPTOR_SIZE);

	if (!fscrypt_valid_contents_enc_mode(
52
				policy->contents_encryption_mode))
53 54 55
		return -EINVAL;

	if (!fscrypt_valid_filenames_enc_mode(
56
				policy->filenames_encryption_mode))
57 58 59 60 61 62 63 64 65 66 67 68 69 70
		return -EINVAL;

	if (policy->flags & ~FS_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) != FS_KEY_DERIVATION_NONCE_SIZE);
	get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);

	return inode->i_sb->s_cop->set_context(inode, &ctx, sizeof(ctx), NULL);
}

71
int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
72
{
73
	struct fscrypt_policy policy;
74 75
	struct inode *inode = file_inode(filp);
	int ret;
76
	struct fscrypt_context ctx;
77

78 79 80
	if (copy_from_user(&policy, arg, sizeof(policy)))
		return -EFAULT;

81 82 83
	if (!inode_owner_or_capable(inode))
		return -EACCES;

84
	if (policy.version != 0)
85 86
		return -EINVAL;

87 88 89 90
	ret = mnt_want_write_file(filp);
	if (ret)
		return ret;

91 92
	inode_lock(inode);

93 94
	ret = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
	if (ret == -ENODATA) {
95
		if (!S_ISDIR(inode->i_mode))
96
			ret = -ENOTDIR;
97 98 99 100 101 102
		else if (!inode->i_sb->s_cop->empty_dir)
			ret = -EOPNOTSUPP;
		else if (!inode->i_sb->s_cop->empty_dir(inode))
			ret = -ENOTEMPTY;
		else
			ret = create_encryption_context_from_policy(inode,
103
								    &policy);
104 105 106 107 108 109 110
	} else if (ret == sizeof(ctx) &&
		   is_encryption_context_consistent_with_policy(&ctx,
								&policy)) {
		/* The file already uses the same encryption policy. */
		ret = 0;
	} else if (ret >= 0 || ret == -ERANGE) {
		/* The file already uses a different encryption policy. */
111
		ret = -EEXIST;
112 113
	}

114 115
	inode_unlock(inode);

116 117
	mnt_drop_write_file(filp);
	return ret;
118
}
119
EXPORT_SYMBOL(fscrypt_ioctl_set_policy);
120

121
int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg)
122
{
123
	struct inode *inode = file_inode(filp);
124
	struct fscrypt_context ctx;
125
	struct fscrypt_policy policy;
126 127 128 129 130 131 132
	int res;

	if (!inode->i_sb->s_cop->get_context ||
			!inode->i_sb->s_cop->is_encrypted(inode))
		return -ENODATA;

	res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
133 134
	if (res < 0 && res != -ERANGE)
		return res;
135
	if (res != sizeof(ctx))
136
		return -EINVAL;
137 138 139
	if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1)
		return -EINVAL;

140 141 142 143 144
	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,
145
				FS_KEY_DESCRIPTOR_SIZE);
146 147 148

	if (copy_to_user(arg, &policy, sizeof(policy)))
		return -EFAULT;
149 150
	return 0;
}
151
EXPORT_SYMBOL(fscrypt_ioctl_get_policy);
152 153 154 155 156 157 158 159 160 161 162

int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
{
	struct fscrypt_info *parent_ci, *child_ci;
	int res;

	if ((parent == NULL) || (child == NULL)) {
		printk(KERN_ERR	"parent %p child %p\n", parent, child);
		BUG_ON(1);
	}

163 164 165 166 167
	/* No restrictions on file types which are never encrypted */
	if (!S_ISREG(child->i_mode) && !S_ISDIR(child->i_mode) &&
	    !S_ISLNK(child->i_mode))
		return 1;

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
	/* no restrictions if the parent directory is not encrypted */
	if (!parent->i_sb->s_cop->is_encrypted(parent))
		return 1;
	/* if the child directory is not encrypted, this is always a problem */
	if (!parent->i_sb->s_cop->is_encrypted(child))
		return 0;
	res = fscrypt_get_encryption_info(parent);
	if (res)
		return 0;
	res = fscrypt_get_encryption_info(child);
	if (res)
		return 0;
	parent_ci = parent->i_crypt_info;
	child_ci = 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,
			FS_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));
}
EXPORT_SYMBOL(fscrypt_has_permitted_context);

/**
 * fscrypt_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.
 * @fs_data:  private data given by FS.
201
 * @preload:  preload child i_crypt_info if true
202
 *
203
 * Return: 0 on success, -errno on failure
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
 */
int fscrypt_inherit_context(struct inode *parent, struct inode *child,
						void *fs_data, bool preload)
{
	struct fscrypt_context ctx;
	struct fscrypt_info *ci;
	int res;

	if (!parent->i_sb->s_cop->set_context)
		return -EOPNOTSUPP;

	res = fscrypt_get_encryption_info(parent);
	if (res < 0)
		return res;

	ci = parent->i_crypt_info;
	if (ci == NULL)
		return -ENOKEY;

	ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
224 225 226 227 228
	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,
	       FS_KEY_DESCRIPTOR_SIZE);
229 230 231 232 233 234 235 236
	get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);
	res = parent->i_sb->s_cop->set_context(child, &ctx,
						sizeof(ctx), fs_data);
	if (res)
		return res;
	return preload ? fscrypt_get_encryption_info(child): 0;
}
EXPORT_SYMBOL(fscrypt_inherit_context);