aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorMichael Halcrow <mhalcrow@google.com>2015-04-11 07:48:01 -0400
committerTheodore Ts'o <tytso@mit.edu>2015-04-11 07:48:01 -0400
commit9bd8212f981ea6375911fe055382ad7529be5b28 (patch)
tree1ff145c6d5986d4687230ca4918ae8d5dece40bc /fs/ext4
parent887e2c452255fbfdc8bdb891ff2066fb26908466 (diff)
ext4 crypto: add encryption policy and password salt support
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>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/Makefile1
-rw-r--r--fs/ext4/crypto_policy.c167
-rw-r--r--fs/ext4/ext4.h15
-rw-r--r--fs/ext4/ext4_crypto.h49
-rw-r--r--fs/ext4/ioctl.c85
5 files changed, 317 insertions, 0 deletions
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index cd6f50fce278..3886ee45f556 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -12,3 +12,4 @@ ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \
12 12
13ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o 13ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
14ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o 14ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o
15ext4-$(CONFIG_EXT4_FS_ENCRYPTION) += crypto_policy.o
diff --git a/fs/ext4/crypto_policy.c b/fs/ext4/crypto_policy.c
new file mode 100644
index 000000000000..532b69c0afab
--- /dev/null
+++ b/fs/ext4/crypto_policy.c
@@ -0,0 +1,167 @@
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.h"
16#include "xattr.h"
17
18static int ext4_inode_has_encryption_context(struct inode *inode)
19{
20 int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
21 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, NULL, 0);
22 return (res > 0);
23}
24
25/*
26 * check whether the policy is consistent with the encryption context
27 * for the inode
28 */
29static int ext4_is_encryption_context_consistent_with_policy(
30 struct inode *inode, const struct ext4_encryption_policy *policy)
31{
32 struct ext4_encryption_context ctx;
33 int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
34 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
35 sizeof(ctx));
36 if (res != sizeof(ctx))
37 return 0;
38 return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor,
39 EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
40 (ctx.contents_encryption_mode ==
41 policy->contents_encryption_mode) &&
42 (ctx.filenames_encryption_mode ==
43 policy->filenames_encryption_mode));
44}
45
46static int ext4_create_encryption_context_from_policy(
47 struct inode *inode, const struct ext4_encryption_policy *policy)
48{
49 struct ext4_encryption_context ctx;
50 int res = 0;
51
52 ctx.format = EXT4_ENCRYPTION_CONTEXT_FORMAT_V1;
53 memcpy(ctx.master_key_descriptor, policy->master_key_descriptor,
54 EXT4_KEY_DESCRIPTOR_SIZE);
55 ctx.contents_encryption_mode = policy->contents_encryption_mode;
56 ctx.filenames_encryption_mode = policy->filenames_encryption_mode;
57 BUILD_BUG_ON(sizeof(ctx.nonce) != EXT4_KEY_DERIVATION_NONCE_SIZE);
58 get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);
59
60 res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
61 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
62 sizeof(ctx), 0);
63 if (!res)
64 ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
65 return res;
66}
67
68int ext4_process_policy(const struct ext4_encryption_policy *policy,
69 struct inode *inode)
70{
71 if (policy->version != 0)
72 return -EINVAL;
73
74 if (!ext4_inode_has_encryption_context(inode)) {
75 if (!ext4_empty_dir(inode))
76 return -ENOTEMPTY;
77 return ext4_create_encryption_context_from_policy(inode,
78 policy);
79 }
80
81 if (ext4_is_encryption_context_consistent_with_policy(inode, policy))
82 return 0;
83
84 printk(KERN_WARNING "%s: Policy inconsistent with encryption context\n",
85 __func__);
86 return -EINVAL;
87}
88
89int ext4_get_policy(struct inode *inode, struct ext4_encryption_policy *policy)
90{
91 struct ext4_encryption_context ctx;
92
93 int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
94 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
95 &ctx, sizeof(ctx));
96 if (res != sizeof(ctx))
97 return -ENOENT;
98 if (ctx.format != EXT4_ENCRYPTION_CONTEXT_FORMAT_V1)
99 return -EINVAL;
100 policy->version = 0;
101 policy->contents_encryption_mode = ctx.contents_encryption_mode;
102 policy->filenames_encryption_mode = ctx.filenames_encryption_mode;
103 memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor,
104 EXT4_KEY_DESCRIPTOR_SIZE);
105 return 0;
106}
107
108int ext4_is_child_context_consistent_with_parent(struct inode *parent,
109 struct inode *child)
110{
111 struct ext4_encryption_context parent_ctx, child_ctx;
112 int res;
113
114 if ((parent == NULL) || (child == NULL)) {
115 pr_err("parent %p child %p\n", parent, child);
116 BUG_ON(1);
117 }
118 /* no restrictions if the parent directory is not encrypted */
119 if (!ext4_encrypted_inode(parent))
120 return 1;
121 res = ext4_xattr_get(parent, EXT4_XATTR_INDEX_ENCRYPTION,
122 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
123 &parent_ctx, sizeof(parent_ctx));
124 if (res != sizeof(parent_ctx))
125 return 0;
126 /* if the child directory is not encrypted, this is always a problem */
127 if (!ext4_encrypted_inode(child))
128 return 0;
129 res = ext4_xattr_get(child, EXT4_XATTR_INDEX_ENCRYPTION,
130 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
131 &child_ctx, sizeof(child_ctx));
132 if (res != sizeof(child_ctx))
133 return 0;
134 return (memcmp(parent_ctx.master_key_descriptor,
135 child_ctx.master_key_descriptor,
136 EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
137 (parent_ctx.contents_encryption_mode ==
138 child_ctx.contents_encryption_mode) &&
139 (parent_ctx.filenames_encryption_mode ==
140 child_ctx.filenames_encryption_mode));
141}
142
143/**
144 * ext4_inherit_context() - Sets a child context from its parent
145 * @parent: Parent inode from which the context is inherited.
146 * @child: Child inode that inherits the context from @parent.
147 *
148 * Return: Zero on success, non-zero otherwise
149 */
150int ext4_inherit_context(struct inode *parent, struct inode *child)
151{
152 struct ext4_encryption_context ctx;
153 int res = ext4_xattr_get(parent, EXT4_XATTR_INDEX_ENCRYPTION,
154 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
155 &ctx, sizeof(ctx));
156
157 if (res != sizeof(ctx))
158 return -ENOENT;
159
160 get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);
161 res = ext4_xattr_set(child, EXT4_XATTR_INDEX_ENCRYPTION,
162 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
163 sizeof(ctx), 0);
164 if (!res)
165 ext4_set_inode_flag(child, EXT4_INODE_ENCRYPT);
166 return res;
167}
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 180111de2302..ab873aa9955e 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -589,6 +589,8 @@ enum {
589#define EXT4_ENCRYPTION_MODE_AES_256_CBC 3 589#define EXT4_ENCRYPTION_MODE_AES_256_CBC 3
590#define EXT4_ENCRYPTION_MODE_AES_256_CTS 4 590#define EXT4_ENCRYPTION_MODE_AES_256_CTS 4
591 591
592#include "ext4_crypto.h"
593
592/* 594/*
593 * ioctl commands 595 * ioctl commands
594 */ 596 */
@@ -610,6 +612,9 @@ enum {
610#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64) 612#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
611#define EXT4_IOC_SWAP_BOOT _IO('f', 17) 613#define EXT4_IOC_SWAP_BOOT _IO('f', 17)
612#define EXT4_IOC_PRECACHE_EXTENTS _IO('f', 18) 614#define EXT4_IOC_PRECACHE_EXTENTS _IO('f', 18)
615#define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy)
616#define EXT4_IOC_GET_ENCRYPTION_PWSALT _IOW('f', 20, __u8[16])
617#define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy)
613 618
614#if defined(__KERNEL__) && defined(CONFIG_COMPAT) 619#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
615/* 620/*
@@ -2011,6 +2016,16 @@ extern unsigned ext4_free_clusters_after_init(struct super_block *sb,
2011 struct ext4_group_desc *gdp); 2016 struct ext4_group_desc *gdp);
2012ext4_fsblk_t ext4_inode_to_goal_block(struct inode *); 2017ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
2013 2018
2019/* crypto_policy.c */
2020int ext4_is_child_context_consistent_with_parent(struct inode *parent,
2021 struct inode *child);
2022int ext4_inherit_context(struct inode *parent, struct inode *child);
2023void ext4_to_hex(char *dst, char *src, size_t src_size);
2024int ext4_process_policy(const struct ext4_encryption_policy *policy,
2025 struct inode *inode);
2026int ext4_get_policy(struct inode *inode,
2027 struct ext4_encryption_policy *policy);
2028
2014/* dir.c */ 2029/* dir.c */
2015extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *, 2030extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
2016 struct file *, 2031 struct file *,
diff --git a/fs/ext4/ext4_crypto.h b/fs/ext4/ext4_crypto.h
new file mode 100644
index 000000000000..a69d2ba54bee
--- /dev/null
+++ b/fs/ext4/ext4_crypto.h
@@ -0,0 +1,49 @@
1/*
2 * linux/fs/ext4/ext4_crypto.h
3 *
4 * Copyright (C) 2015, Google, Inc.
5 *
6 * This contains encryption header content for ext4
7 *
8 * Written by Michael Halcrow, 2015.
9 */
10
11#ifndef _EXT4_CRYPTO_H
12#define _EXT4_CRYPTO_H
13
14#include <linux/fs.h>
15
16#define EXT4_KEY_DESCRIPTOR_SIZE 8
17
18/* Policy provided via an ioctl on the topmost directory */
19struct ext4_encryption_policy {
20 char version;
21 char contents_encryption_mode;
22 char filenames_encryption_mode;
23 char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
24} __attribute__((__packed__));
25
26#define EXT4_ENCRYPTION_CONTEXT_FORMAT_V1 1
27#define EXT4_KEY_DERIVATION_NONCE_SIZE 16
28
29/**
30 * Encryption context for inode
31 *
32 * Protector format:
33 * 1 byte: Protector format (1 = this version)
34 * 1 byte: File contents encryption mode
35 * 1 byte: File names encryption mode
36 * 1 byte: Reserved
37 * 8 bytes: Master Key descriptor
38 * 16 bytes: Encryption Key derivation nonce
39 */
40struct ext4_encryption_context {
41 char format;
42 char contents_encryption_mode;
43 char filenames_encryption_mode;
44 char reserved;
45 char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
46 char nonce[EXT4_KEY_DERIVATION_NONCE_SIZE];
47} __attribute__((__packed__));
48
49#endif /* _EXT4_CRYPTO_H */
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index f1aa32c2277c..2cb9e178d1c5 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -13,6 +13,7 @@
13#include <linux/compat.h> 13#include <linux/compat.h>
14#include <linux/mount.h> 14#include <linux/mount.h>
15#include <linux/file.h> 15#include <linux/file.h>
16#include <linux/random.h>
16#include <asm/uaccess.h> 17#include <asm/uaccess.h>
17#include "ext4_jbd2.h" 18#include "ext4_jbd2.h"
18#include "ext4.h" 19#include "ext4.h"
@@ -195,6 +196,16 @@ journal_err_out:
195 return err; 196 return err;
196} 197}
197 198
199static int uuid_is_zero(__u8 u[16])
200{
201 int i;
202
203 for (i = 0; i < 16; i++)
204 if (u[i])
205 return 0;
206 return 1;
207}
208
198long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 209long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
199{ 210{
200 struct inode *inode = file_inode(filp); 211 struct inode *inode = file_inode(filp);
@@ -614,7 +625,78 @@ resizefs_out:
614 } 625 }
615 case EXT4_IOC_PRECACHE_EXTENTS: 626 case EXT4_IOC_PRECACHE_EXTENTS:
616 return ext4_ext_precache(inode); 627 return ext4_ext_precache(inode);
628 case EXT4_IOC_SET_ENCRYPTION_POLICY: {
629#ifdef CONFIG_EXT4_FS_ENCRYPTION
630 struct ext4_encryption_policy policy;
631 int err = 0;
632
633 if (copy_from_user(&policy,
634 (struct ext4_encryption_policy __user *)arg,
635 sizeof(policy))) {
636 err = -EFAULT;
637 goto encryption_policy_out;
638 }
617 639
640 err = ext4_process_policy(&policy, inode);
641encryption_policy_out:
642 return err;
643#else
644 return -EOPNOTSUPP;
645#endif
646 }
647 case EXT4_IOC_GET_ENCRYPTION_PWSALT: {
648 int err, err2;
649 struct ext4_sb_info *sbi = EXT4_SB(sb);
650 handle_t *handle;
651
652 if (!ext4_sb_has_crypto(sb))
653 return -EOPNOTSUPP;
654 if (uuid_is_zero(sbi->s_es->s_encrypt_pw_salt)) {
655 err = mnt_want_write_file(filp);
656 if (err)
657 return err;
658 handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1);
659 if (IS_ERR(handle)) {
660 err = PTR_ERR(handle);
661 goto pwsalt_err_exit;
662 }
663 err = ext4_journal_get_write_access(handle, sbi->s_sbh);
664 if (err)
665 goto pwsalt_err_journal;
666 generate_random_uuid(sbi->s_es->s_encrypt_pw_salt);
667 err = ext4_handle_dirty_metadata(handle, NULL,
668 sbi->s_sbh);
669 pwsalt_err_journal:
670 err2 = ext4_journal_stop(handle);
671 if (err2 && !err)
672 err = err2;
673 pwsalt_err_exit:
674 mnt_drop_write_file(filp);
675 if (err)
676 return err;
677 }
678 if (copy_to_user((void *) arg, sbi->s_es->s_encrypt_pw_salt,
679 16))
680 return -EFAULT;
681 return 0;
682 }
683 case EXT4_IOC_GET_ENCRYPTION_POLICY: {
684#ifdef CONFIG_EXT4_FS_ENCRYPTION
685 struct ext4_encryption_policy policy;
686 int err = 0;
687
688 if (!ext4_encrypted_inode(inode))
689 return -ENOENT;
690 err = ext4_get_policy(inode, &policy);
691 if (err)
692 return err;
693 if (copy_to_user((void *)arg, &policy, sizeof(policy)))
694 return -EFAULT;
695 return 0;
696#else
697 return -EOPNOTSUPP;
698#endif
699 }
618 default: 700 default:
619 return -ENOTTY; 701 return -ENOTTY;
620 } 702 }
@@ -679,6 +761,9 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
679 case FITRIM: 761 case FITRIM:
680 case EXT4_IOC_RESIZE_FS: 762 case EXT4_IOC_RESIZE_FS:
681 case EXT4_IOC_PRECACHE_EXTENTS: 763 case EXT4_IOC_PRECACHE_EXTENTS:
764 case EXT4_IOC_SET_ENCRYPTION_POLICY:
765 case EXT4_IOC_GET_ENCRYPTION_PWSALT:
766 case EXT4_IOC_GET_ENCRYPTION_POLICY:
682 break; 767 break;
683 default: 768 default:
684 return -ENOIOCTLCMD; 769 return -ENOIOCTLCMD;