xref: /openbmc/linux/fs/crypto/policy.c (revision 0b81d077)
10b81d077SJaegeuk Kim /*
20b81d077SJaegeuk Kim  * Encryption policy functions for per-file encryption support.
30b81d077SJaegeuk Kim  *
40b81d077SJaegeuk Kim  * Copyright (C) 2015, Google, Inc.
50b81d077SJaegeuk Kim  * Copyright (C) 2015, Motorola Mobility.
60b81d077SJaegeuk Kim  *
70b81d077SJaegeuk Kim  * Written by Michael Halcrow, 2015.
80b81d077SJaegeuk Kim  * Modified by Jaegeuk Kim, 2015.
90b81d077SJaegeuk Kim  */
100b81d077SJaegeuk Kim 
110b81d077SJaegeuk Kim #include <linux/random.h>
120b81d077SJaegeuk Kim #include <linux/string.h>
130b81d077SJaegeuk Kim #include <linux/fscrypto.h>
140b81d077SJaegeuk Kim 
150b81d077SJaegeuk Kim static int inode_has_encryption_context(struct inode *inode)
160b81d077SJaegeuk Kim {
170b81d077SJaegeuk Kim 	if (!inode->i_sb->s_cop->get_context)
180b81d077SJaegeuk Kim 		return 0;
190b81d077SJaegeuk Kim 	return (inode->i_sb->s_cop->get_context(inode, NULL, 0L) > 0);
200b81d077SJaegeuk Kim }
210b81d077SJaegeuk Kim 
220b81d077SJaegeuk Kim /*
230b81d077SJaegeuk Kim  * check whether the policy is consistent with the encryption context
240b81d077SJaegeuk Kim  * for the inode
250b81d077SJaegeuk Kim  */
260b81d077SJaegeuk Kim static int is_encryption_context_consistent_with_policy(struct inode *inode,
270b81d077SJaegeuk Kim 				const struct fscrypt_policy *policy)
280b81d077SJaegeuk Kim {
290b81d077SJaegeuk Kim 	struct fscrypt_context ctx;
300b81d077SJaegeuk Kim 	int res;
310b81d077SJaegeuk Kim 
320b81d077SJaegeuk Kim 	if (!inode->i_sb->s_cop->get_context)
330b81d077SJaegeuk Kim 		return 0;
340b81d077SJaegeuk Kim 
350b81d077SJaegeuk Kim 	res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
360b81d077SJaegeuk Kim 	if (res != sizeof(ctx))
370b81d077SJaegeuk Kim 		return 0;
380b81d077SJaegeuk Kim 
390b81d077SJaegeuk Kim 	return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor,
400b81d077SJaegeuk Kim 			FS_KEY_DESCRIPTOR_SIZE) == 0 &&
410b81d077SJaegeuk Kim 			(ctx.flags == policy->flags) &&
420b81d077SJaegeuk Kim 			(ctx.contents_encryption_mode ==
430b81d077SJaegeuk Kim 			 policy->contents_encryption_mode) &&
440b81d077SJaegeuk Kim 			(ctx.filenames_encryption_mode ==
450b81d077SJaegeuk Kim 			 policy->filenames_encryption_mode));
460b81d077SJaegeuk Kim }
470b81d077SJaegeuk Kim 
480b81d077SJaegeuk Kim static int create_encryption_context_from_policy(struct inode *inode,
490b81d077SJaegeuk Kim 				const struct fscrypt_policy *policy)
500b81d077SJaegeuk Kim {
510b81d077SJaegeuk Kim 	struct fscrypt_context ctx;
520b81d077SJaegeuk Kim 	int res;
530b81d077SJaegeuk Kim 
540b81d077SJaegeuk Kim 	if (!inode->i_sb->s_cop->set_context)
550b81d077SJaegeuk Kim 		return -EOPNOTSUPP;
560b81d077SJaegeuk Kim 
570b81d077SJaegeuk Kim 	if (inode->i_sb->s_cop->prepare_context) {
580b81d077SJaegeuk Kim 		res = inode->i_sb->s_cop->prepare_context(inode);
590b81d077SJaegeuk Kim 		if (res)
600b81d077SJaegeuk Kim 			return res;
610b81d077SJaegeuk Kim 	}
620b81d077SJaegeuk Kim 
630b81d077SJaegeuk Kim 	ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
640b81d077SJaegeuk Kim 	memcpy(ctx.master_key_descriptor, policy->master_key_descriptor,
650b81d077SJaegeuk Kim 					FS_KEY_DESCRIPTOR_SIZE);
660b81d077SJaegeuk Kim 
670b81d077SJaegeuk Kim 	if (!fscrypt_valid_contents_enc_mode(
680b81d077SJaegeuk Kim 				policy->contents_encryption_mode)) {
690b81d077SJaegeuk Kim 		printk(KERN_WARNING
700b81d077SJaegeuk Kim 		       "%s: Invalid contents encryption mode %d\n", __func__,
710b81d077SJaegeuk Kim 			policy->contents_encryption_mode);
720b81d077SJaegeuk Kim 		return -EINVAL;
730b81d077SJaegeuk Kim 	}
740b81d077SJaegeuk Kim 
750b81d077SJaegeuk Kim 	if (!fscrypt_valid_filenames_enc_mode(
760b81d077SJaegeuk Kim 				policy->filenames_encryption_mode)) {
770b81d077SJaegeuk Kim 		printk(KERN_WARNING
780b81d077SJaegeuk Kim 			"%s: Invalid filenames encryption mode %d\n", __func__,
790b81d077SJaegeuk Kim 			policy->filenames_encryption_mode);
800b81d077SJaegeuk Kim 		return -EINVAL;
810b81d077SJaegeuk Kim 	}
820b81d077SJaegeuk Kim 
830b81d077SJaegeuk Kim 	if (policy->flags & ~FS_POLICY_FLAGS_VALID)
840b81d077SJaegeuk Kim 		return -EINVAL;
850b81d077SJaegeuk Kim 
860b81d077SJaegeuk Kim 	ctx.contents_encryption_mode = policy->contents_encryption_mode;
870b81d077SJaegeuk Kim 	ctx.filenames_encryption_mode = policy->filenames_encryption_mode;
880b81d077SJaegeuk Kim 	ctx.flags = policy->flags;
890b81d077SJaegeuk Kim 	BUILD_BUG_ON(sizeof(ctx.nonce) != FS_KEY_DERIVATION_NONCE_SIZE);
900b81d077SJaegeuk Kim 	get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);
910b81d077SJaegeuk Kim 
920b81d077SJaegeuk Kim 	return inode->i_sb->s_cop->set_context(inode, &ctx, sizeof(ctx), NULL);
930b81d077SJaegeuk Kim }
940b81d077SJaegeuk Kim 
950b81d077SJaegeuk Kim int fscrypt_process_policy(struct inode *inode,
960b81d077SJaegeuk Kim 				const struct fscrypt_policy *policy)
970b81d077SJaegeuk Kim {
980b81d077SJaegeuk Kim 	if (policy->version != 0)
990b81d077SJaegeuk Kim 		return -EINVAL;
1000b81d077SJaegeuk Kim 
1010b81d077SJaegeuk Kim 	if (!inode_has_encryption_context(inode)) {
1020b81d077SJaegeuk Kim 		if (!inode->i_sb->s_cop->empty_dir)
1030b81d077SJaegeuk Kim 			return -EOPNOTSUPP;
1040b81d077SJaegeuk Kim 		if (!inode->i_sb->s_cop->empty_dir(inode))
1050b81d077SJaegeuk Kim 			return -ENOTEMPTY;
1060b81d077SJaegeuk Kim 		return create_encryption_context_from_policy(inode, policy);
1070b81d077SJaegeuk Kim 	}
1080b81d077SJaegeuk Kim 
1090b81d077SJaegeuk Kim 	if (is_encryption_context_consistent_with_policy(inode, policy))
1100b81d077SJaegeuk Kim 		return 0;
1110b81d077SJaegeuk Kim 
1120b81d077SJaegeuk Kim 	printk(KERN_WARNING "%s: Policy inconsistent with encryption context\n",
1130b81d077SJaegeuk Kim 	       __func__);
1140b81d077SJaegeuk Kim 	return -EINVAL;
1150b81d077SJaegeuk Kim }
1160b81d077SJaegeuk Kim EXPORT_SYMBOL(fscrypt_process_policy);
1170b81d077SJaegeuk Kim 
1180b81d077SJaegeuk Kim int fscrypt_get_policy(struct inode *inode, struct fscrypt_policy *policy)
1190b81d077SJaegeuk Kim {
1200b81d077SJaegeuk Kim 	struct fscrypt_context ctx;
1210b81d077SJaegeuk Kim 	int res;
1220b81d077SJaegeuk Kim 
1230b81d077SJaegeuk Kim 	if (!inode->i_sb->s_cop->get_context ||
1240b81d077SJaegeuk Kim 			!inode->i_sb->s_cop->is_encrypted(inode))
1250b81d077SJaegeuk Kim 		return -ENODATA;
1260b81d077SJaegeuk Kim 
1270b81d077SJaegeuk Kim 	res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
1280b81d077SJaegeuk Kim 	if (res != sizeof(ctx))
1290b81d077SJaegeuk Kim 		return -ENODATA;
1300b81d077SJaegeuk Kim 	if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1)
1310b81d077SJaegeuk Kim 		return -EINVAL;
1320b81d077SJaegeuk Kim 
1330b81d077SJaegeuk Kim 	policy->version = 0;
1340b81d077SJaegeuk Kim 	policy->contents_encryption_mode = ctx.contents_encryption_mode;
1350b81d077SJaegeuk Kim 	policy->filenames_encryption_mode = ctx.filenames_encryption_mode;
1360b81d077SJaegeuk Kim 	policy->flags = ctx.flags;
1370b81d077SJaegeuk Kim 	memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor,
1380b81d077SJaegeuk Kim 				FS_KEY_DESCRIPTOR_SIZE);
1390b81d077SJaegeuk Kim 	return 0;
1400b81d077SJaegeuk Kim }
1410b81d077SJaegeuk Kim EXPORT_SYMBOL(fscrypt_get_policy);
1420b81d077SJaegeuk Kim 
1430b81d077SJaegeuk Kim int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
1440b81d077SJaegeuk Kim {
1450b81d077SJaegeuk Kim 	struct fscrypt_info *parent_ci, *child_ci;
1460b81d077SJaegeuk Kim 	int res;
1470b81d077SJaegeuk Kim 
1480b81d077SJaegeuk Kim 	if ((parent == NULL) || (child == NULL)) {
1490b81d077SJaegeuk Kim 		printk(KERN_ERR	"parent %p child %p\n", parent, child);
1500b81d077SJaegeuk Kim 		BUG_ON(1);
1510b81d077SJaegeuk Kim 	}
1520b81d077SJaegeuk Kim 
1530b81d077SJaegeuk Kim 	/* no restrictions if the parent directory is not encrypted */
1540b81d077SJaegeuk Kim 	if (!parent->i_sb->s_cop->is_encrypted(parent))
1550b81d077SJaegeuk Kim 		return 1;
1560b81d077SJaegeuk Kim 	/* if the child directory is not encrypted, this is always a problem */
1570b81d077SJaegeuk Kim 	if (!parent->i_sb->s_cop->is_encrypted(child))
1580b81d077SJaegeuk Kim 		return 0;
1590b81d077SJaegeuk Kim 	res = fscrypt_get_encryption_info(parent);
1600b81d077SJaegeuk Kim 	if (res)
1610b81d077SJaegeuk Kim 		return 0;
1620b81d077SJaegeuk Kim 	res = fscrypt_get_encryption_info(child);
1630b81d077SJaegeuk Kim 	if (res)
1640b81d077SJaegeuk Kim 		return 0;
1650b81d077SJaegeuk Kim 	parent_ci = parent->i_crypt_info;
1660b81d077SJaegeuk Kim 	child_ci = child->i_crypt_info;
1670b81d077SJaegeuk Kim 	if (!parent_ci && !child_ci)
1680b81d077SJaegeuk Kim 		return 1;
1690b81d077SJaegeuk Kim 	if (!parent_ci || !child_ci)
1700b81d077SJaegeuk Kim 		return 0;
1710b81d077SJaegeuk Kim 
1720b81d077SJaegeuk Kim 	return (memcmp(parent_ci->ci_master_key,
1730b81d077SJaegeuk Kim 			child_ci->ci_master_key,
1740b81d077SJaegeuk Kim 			FS_KEY_DESCRIPTOR_SIZE) == 0 &&
1750b81d077SJaegeuk Kim 		(parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
1760b81d077SJaegeuk Kim 		(parent_ci->ci_filename_mode == child_ci->ci_filename_mode) &&
1770b81d077SJaegeuk Kim 		(parent_ci->ci_flags == child_ci->ci_flags));
1780b81d077SJaegeuk Kim }
1790b81d077SJaegeuk Kim EXPORT_SYMBOL(fscrypt_has_permitted_context);
1800b81d077SJaegeuk Kim 
1810b81d077SJaegeuk Kim /**
1820b81d077SJaegeuk Kim  * fscrypt_inherit_context() - Sets a child context from its parent
1830b81d077SJaegeuk Kim  * @parent: Parent inode from which the context is inherited.
1840b81d077SJaegeuk Kim  * @child:  Child inode that inherits the context from @parent.
1850b81d077SJaegeuk Kim  * @fs_data:  private data given by FS.
1860b81d077SJaegeuk Kim  * @preload:  preload child i_crypt_info
1870b81d077SJaegeuk Kim  *
1880b81d077SJaegeuk Kim  * Return: Zero on success, non-zero otherwise
1890b81d077SJaegeuk Kim  */
1900b81d077SJaegeuk Kim int fscrypt_inherit_context(struct inode *parent, struct inode *child,
1910b81d077SJaegeuk Kim 						void *fs_data, bool preload)
1920b81d077SJaegeuk Kim {
1930b81d077SJaegeuk Kim 	struct fscrypt_context ctx;
1940b81d077SJaegeuk Kim 	struct fscrypt_info *ci;
1950b81d077SJaegeuk Kim 	int res;
1960b81d077SJaegeuk Kim 
1970b81d077SJaegeuk Kim 	if (!parent->i_sb->s_cop->set_context)
1980b81d077SJaegeuk Kim 		return -EOPNOTSUPP;
1990b81d077SJaegeuk Kim 
2000b81d077SJaegeuk Kim 	res = fscrypt_get_encryption_info(parent);
2010b81d077SJaegeuk Kim 	if (res < 0)
2020b81d077SJaegeuk Kim 		return res;
2030b81d077SJaegeuk Kim 
2040b81d077SJaegeuk Kim 	ci = parent->i_crypt_info;
2050b81d077SJaegeuk Kim 	if (ci == NULL)
2060b81d077SJaegeuk Kim 		return -ENOKEY;
2070b81d077SJaegeuk Kim 
2080b81d077SJaegeuk Kim 	ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
2090b81d077SJaegeuk Kim 	if (fscrypt_dummy_context_enabled(parent)) {
2100b81d077SJaegeuk Kim 		ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
2110b81d077SJaegeuk Kim 		ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
2120b81d077SJaegeuk Kim 		ctx.flags = 0;
2130b81d077SJaegeuk Kim 		memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE);
2140b81d077SJaegeuk Kim 		res = 0;
2150b81d077SJaegeuk Kim 	} else {
2160b81d077SJaegeuk Kim 		ctx.contents_encryption_mode = ci->ci_data_mode;
2170b81d077SJaegeuk Kim 		ctx.filenames_encryption_mode = ci->ci_filename_mode;
2180b81d077SJaegeuk Kim 		ctx.flags = ci->ci_flags;
2190b81d077SJaegeuk Kim 		memcpy(ctx.master_key_descriptor, ci->ci_master_key,
2200b81d077SJaegeuk Kim 				FS_KEY_DESCRIPTOR_SIZE);
2210b81d077SJaegeuk Kim 	}
2220b81d077SJaegeuk Kim 	get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);
2230b81d077SJaegeuk Kim 	res = parent->i_sb->s_cop->set_context(child, &ctx,
2240b81d077SJaegeuk Kim 						sizeof(ctx), fs_data);
2250b81d077SJaegeuk Kim 	if (res)
2260b81d077SJaegeuk Kim 		return res;
2270b81d077SJaegeuk Kim 	return preload ? fscrypt_get_encryption_info(child): 0;
2280b81d077SJaegeuk Kim }
2290b81d077SJaegeuk Kim EXPORT_SYMBOL(fscrypt_inherit_context);
230