linux/fs/ext4/crypto_policy.c
<<
>>
Prefs
   1/*
   2 * linux/fs/ext4/crypto_policy.c
   3 *
   4 * Copyright (C) 2015, Google, Inc.
   5 *
   6 * This contains encryption policy functions for ext4
   7 *
   8 * Written by Michael Halcrow, 2015.
   9 */
  10
  11#include <linux/random.h>
  12#include <linux/string.h>
  13#include <linux/types.h>
  14
  15#include "ext4_jbd2.h"
  16#include "ext4.h"
  17#include "xattr.h"
  18
  19static int ext4_inode_has_encryption_context(struct inode *inode)
  20{
  21        int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
  22                                 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, NULL, 0);
  23        return (res > 0);
  24}
  25
  26/*
  27 * check whether the policy is consistent with the encryption context
  28 * for the inode
  29 */
  30static int ext4_is_encryption_context_consistent_with_policy(
  31        struct inode *inode, const struct ext4_encryption_policy *policy)
  32{
  33        struct ext4_encryption_context ctx;
  34        int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
  35                                 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
  36                                 sizeof(ctx));
  37        if (res != sizeof(ctx))
  38                return 0;
  39        return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor,
  40                        EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
  41                (ctx.flags ==
  42                 policy->flags) &&
  43                (ctx.contents_encryption_mode ==
  44                 policy->contents_encryption_mode) &&
  45                (ctx.filenames_encryption_mode ==
  46                 policy->filenames_encryption_mode));
  47}
  48
  49static int ext4_create_encryption_context_from_policy(
  50        struct inode *inode, const struct ext4_encryption_policy *policy)
  51{
  52        struct ext4_encryption_context ctx;
  53        handle_t *handle;
  54        int res, res2;
  55
  56        res = ext4_convert_inline_data(inode);
  57        if (res)
  58                return res;
  59
  60        ctx.format = EXT4_ENCRYPTION_CONTEXT_FORMAT_V1;
  61        memcpy(ctx.master_key_descriptor, policy->master_key_descriptor,
  62               EXT4_KEY_DESCRIPTOR_SIZE);
  63        if (!ext4_valid_contents_enc_mode(policy->contents_encryption_mode)) {
  64                printk(KERN_WARNING
  65                       "%s: Invalid contents encryption mode %d\n", __func__,
  66                        policy->contents_encryption_mode);
  67                return -EINVAL;
  68        }
  69        if (!ext4_valid_filenames_enc_mode(policy->filenames_encryption_mode)) {
  70                printk(KERN_WARNING
  71                       "%s: Invalid filenames encryption mode %d\n", __func__,
  72                        policy->filenames_encryption_mode);
  73                return -EINVAL;
  74        }
  75        if (policy->flags & ~EXT4_POLICY_FLAGS_VALID)
  76                return -EINVAL;
  77        ctx.contents_encryption_mode = policy->contents_encryption_mode;
  78        ctx.filenames_encryption_mode = policy->filenames_encryption_mode;
  79        ctx.flags = policy->flags;
  80        BUILD_BUG_ON(sizeof(ctx.nonce) != EXT4_KEY_DERIVATION_NONCE_SIZE);
  81        get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);
  82
  83        handle = ext4_journal_start(inode, EXT4_HT_MISC,
  84                                    ext4_jbd2_credits_xattr(inode));
  85        if (IS_ERR(handle))
  86                return PTR_ERR(handle);
  87        res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
  88                             EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
  89                             sizeof(ctx), 0);
  90        if (!res) {
  91                ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
  92                res = ext4_mark_inode_dirty(handle, inode);
  93                if (res)
  94                        EXT4_ERROR_INODE(inode, "Failed to mark inode dirty");
  95        }
  96        res2 = ext4_journal_stop(handle);
  97        if (!res)
  98                res = res2;
  99        return res;
 100}
 101
 102int ext4_process_policy(const struct ext4_encryption_policy *policy,
 103                        struct inode *inode)
 104{
 105        if (policy->version != 0)
 106                return -EINVAL;
 107
 108        if (!ext4_inode_has_encryption_context(inode)) {
 109                if (!S_ISDIR(inode->i_mode))
 110                        return -EINVAL;
 111                if (!ext4_empty_dir(inode))
 112                        return -ENOTEMPTY;
 113                return ext4_create_encryption_context_from_policy(inode,
 114                                                                  policy);
 115        }
 116
 117        if (ext4_is_encryption_context_consistent_with_policy(inode, policy))
 118                return 0;
 119
 120        printk(KERN_WARNING "%s: Policy inconsistent with encryption context\n",
 121               __func__);
 122        return -EINVAL;
 123}
 124
 125int ext4_get_policy(struct inode *inode, struct ext4_encryption_policy *policy)
 126{
 127        struct ext4_encryption_context ctx;
 128
 129        int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
 130                                 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
 131                                 &ctx, sizeof(ctx));
 132        if (res != sizeof(ctx))
 133                return -ENOENT;
 134        if (ctx.format != EXT4_ENCRYPTION_CONTEXT_FORMAT_V1)
 135                return -EINVAL;
 136        policy->version = 0;
 137        policy->contents_encryption_mode = ctx.contents_encryption_mode;
 138        policy->filenames_encryption_mode = ctx.filenames_encryption_mode;
 139        policy->flags = ctx.flags;
 140        memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor,
 141               EXT4_KEY_DESCRIPTOR_SIZE);
 142        return 0;
 143}
 144
 145int ext4_is_child_context_consistent_with_parent(struct inode *parent,
 146                                                 struct inode *child)
 147{
 148        struct ext4_crypt_info *parent_ci, *child_ci;
 149        int res;
 150
 151        if ((parent == NULL) || (child == NULL)) {
 152                pr_err("parent %p child %p\n", parent, child);
 153                BUG_ON(1);
 154        }
 155        /* no restrictions if the parent directory is not encrypted */
 156        if (!ext4_encrypted_inode(parent))
 157                return 1;
 158        /* if the child directory is not encrypted, this is always a problem */
 159        if (!ext4_encrypted_inode(child))
 160                return 0;
 161        res = ext4_get_encryption_info(parent);
 162        if (res)
 163                return 0;
 164        res = ext4_get_encryption_info(child);
 165        if (res)
 166                return 0;
 167        parent_ci = EXT4_I(parent)->i_crypt_info;
 168        child_ci = EXT4_I(child)->i_crypt_info;
 169        if (!parent_ci && !child_ci)
 170                return 1;
 171        if (!parent_ci || !child_ci)
 172                return 0;
 173
 174        return (memcmp(parent_ci->ci_master_key,
 175                       child_ci->ci_master_key,
 176                       EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
 177                (parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
 178                (parent_ci->ci_filename_mode == child_ci->ci_filename_mode) &&
 179                (parent_ci->ci_flags == child_ci->ci_flags));
 180}
 181
 182/**
 183 * ext4_inherit_context() - Sets a child context from its parent
 184 * @parent: Parent inode from which the context is inherited.
 185 * @child:  Child inode that inherits the context from @parent.
 186 *
 187 * Return: Zero on success, non-zero otherwise
 188 */
 189int ext4_inherit_context(struct inode *parent, struct inode *child)
 190{
 191        struct ext4_encryption_context ctx;
 192        struct ext4_crypt_info *ci;
 193        int res;
 194
 195        res = ext4_get_encryption_info(parent);
 196        if (res < 0)
 197                return res;
 198        ci = EXT4_I(parent)->i_crypt_info;
 199        if (ci == NULL)
 200                return -ENOKEY;
 201
 202        ctx.format = EXT4_ENCRYPTION_CONTEXT_FORMAT_V1;
 203        if (DUMMY_ENCRYPTION_ENABLED(EXT4_SB(parent->i_sb))) {
 204                ctx.contents_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
 205                ctx.filenames_encryption_mode =
 206                        EXT4_ENCRYPTION_MODE_AES_256_CTS;
 207                ctx.flags = 0;
 208                memset(ctx.master_key_descriptor, 0x42,
 209                       EXT4_KEY_DESCRIPTOR_SIZE);
 210                res = 0;
 211        } else {
 212                ctx.contents_encryption_mode = ci->ci_data_mode;
 213                ctx.filenames_encryption_mode = ci->ci_filename_mode;
 214                ctx.flags = ci->ci_flags;
 215                memcpy(ctx.master_key_descriptor, ci->ci_master_key,
 216                       EXT4_KEY_DESCRIPTOR_SIZE);
 217        }
 218        get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);
 219        res = ext4_xattr_set(child, EXT4_XATTR_INDEX_ENCRYPTION,
 220                             EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
 221                             sizeof(ctx), 0);
 222        if (!res) {
 223                ext4_set_inode_flag(child, EXT4_INODE_ENCRYPT);
 224                ext4_clear_inode_state(child, EXT4_STATE_MAY_INLINE_DATA);
 225                res = ext4_get_encryption_info(child);
 226        }
 227        return res;
 228}
 229