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