add patch create-function-to-read-journal-inode
[ext4-patch-queue.git] / fscrypto-improved-validation-when-loading-inode-encryption-metadata
blob991914d0f8327c80e948fe3f0bc36881d0f8d34a
1 From: Eric Biggers <ebiggers@google.com>
3 fscrypto: improved validation when loading inode encryption metadata
5 - Validate fscrypt_context.format and fscrypt_context.flags.  If
6   unrecognized values are set, then the kernel may not know how to
7   interpret the encrypted file, so it should fail the operation.
9 - Validate that AES_256_XTS is used for contents and that AES_256_CTS is
10   used for filenames.  It was previously possible for the kernel to
11   accept these reversed, though it would have taken manual editing of
12   the block device.  This was not intended.
14 - Fail cleanly rather than BUG()-ing if a file has an unexpected type.
16 Signed-off-by: Eric Biggers <ebiggers@google.com>
17 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
18 ---
19  fs/crypto/keyinfo.c      | 68 ++++++++++++++++++++++++++++++++----------------
20  include/linux/fscrypto.h | 24 -----------------
21  2 files changed, 45 insertions(+), 47 deletions(-)
23 diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
24 index 1ac263e..b5374ef 100644
25 --- a/fs/crypto/keyinfo.c
26 +++ b/fs/crypto/keyinfo.c
27 @@ -139,6 +139,38 @@ out:
28         return res;
29  }
31 +static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode,
32 +                                const char **cipher_str_ret, int *keysize_ret)
34 +       if (S_ISREG(inode->i_mode)) {
35 +               if (ci->ci_data_mode == FS_ENCRYPTION_MODE_AES_256_XTS) {
36 +                       *cipher_str_ret = "xts(aes)";
37 +                       *keysize_ret = FS_AES_256_XTS_KEY_SIZE;
38 +                       return 0;
39 +               }
40 +               pr_warn_once("fscrypto: unsupported contents encryption mode "
41 +                            "%d for inode %lu\n",
42 +                            ci->ci_data_mode, inode->i_ino);
43 +               return -ENOKEY;
44 +       }
46 +       if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) {
47 +               if (ci->ci_filename_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
48 +                       *cipher_str_ret = "cts(cbc(aes))";
49 +                       *keysize_ret = FS_AES_256_CTS_KEY_SIZE;
50 +                       return 0;
51 +               }
52 +               pr_warn_once("fscrypto: unsupported filenames encryption mode "
53 +                            "%d for inode %lu\n",
54 +                            ci->ci_filename_mode, inode->i_ino);
55 +               return -ENOKEY;
56 +       }
58 +       pr_warn_once("fscrypto: unsupported file type %d for inode %lu\n",
59 +                    (inode->i_mode & S_IFMT), inode->i_ino);
60 +       return -ENOKEY;
63  static void put_crypt_info(struct fscrypt_info *ci)
64  {
65         if (!ci)
66 @@ -155,8 +187,8 @@ int get_crypt_info(struct inode *inode)
67         struct fscrypt_context ctx;
68         struct crypto_skcipher *ctfm;
69         const char *cipher_str;
70 +       int keysize;
71         u8 raw_key[FS_MAX_KEY_SIZE];
72 -       u8 mode;
73         int res;
75         res = fscrypt_initialize();
76 @@ -179,13 +211,19 @@ retry:
77         if (res < 0) {
78                 if (!fscrypt_dummy_context_enabled(inode))
79                         return res;
80 +               ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
81                 ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
82                 ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
83                 ctx.flags = 0;
84         } else if (res != sizeof(ctx)) {
85                 return -EINVAL;
86         }
87 -       res = 0;
89 +       if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1)
90 +               return -EINVAL;
92 +       if (ctx.flags & ~FS_POLICY_FLAGS_VALID)
93 +               return -EINVAL;
95         crypt_info = kmem_cache_alloc(fscrypt_info_cachep, GFP_NOFS);
96         if (!crypt_info)
97 @@ -198,27 +236,11 @@ retry:
98         crypt_info->ci_keyring_key = NULL;
99         memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
100                                 sizeof(crypt_info->ci_master_key));
101 -       if (S_ISREG(inode->i_mode))
102 -               mode = crypt_info->ci_data_mode;
103 -       else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
104 -               mode = crypt_info->ci_filename_mode;
105 -       else
106 -               BUG();
108 -       switch (mode) {
109 -       case FS_ENCRYPTION_MODE_AES_256_XTS:
110 -               cipher_str = "xts(aes)";
111 -               break;
112 -       case FS_ENCRYPTION_MODE_AES_256_CTS:
113 -               cipher_str = "cts(cbc(aes))";
114 -               break;
115 -       default:
116 -               printk_once(KERN_WARNING
117 -                           "%s: unsupported key mode %d (ino %u)\n",
118 -                           __func__, mode, (unsigned) inode->i_ino);
119 -               res = -ENOKEY;
121 +       res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize);
122 +       if (res)
123                 goto out;
124 -       }
126         if (fscrypt_dummy_context_enabled(inode)) {
127                 memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
128                 goto got_key;
129 @@ -253,7 +275,7 @@ got_key:
130         crypt_info->ci_ctfm = ctfm;
131         crypto_skcipher_clear_flags(ctfm, ~0);
132         crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY);
133 -       res = crypto_skcipher_setkey(ctfm, raw_key, fscrypt_key_size(mode));
134 +       res = crypto_skcipher_setkey(ctfm, raw_key, keysize);
135         if (res)
136                 goto out;
138 diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
139 index cfa6cde..00813c2 100644
140 --- a/include/linux/fscrypto.h
141 +++ b/include/linux/fscrypto.h
142 @@ -111,23 +111,6 @@ struct fscrypt_completion_result {
143         struct fscrypt_completion_result ecr = { \
144                 COMPLETION_INITIALIZER((ecr).completion), 0 }
146 -static inline int fscrypt_key_size(int mode)
148 -       switch (mode) {
149 -       case FS_ENCRYPTION_MODE_AES_256_XTS:
150 -               return FS_AES_256_XTS_KEY_SIZE;
151 -       case FS_ENCRYPTION_MODE_AES_256_GCM:
152 -               return FS_AES_256_GCM_KEY_SIZE;
153 -       case FS_ENCRYPTION_MODE_AES_256_CBC:
154 -               return FS_AES_256_CBC_KEY_SIZE;
155 -       case FS_ENCRYPTION_MODE_AES_256_CTS:
156 -               return FS_AES_256_CTS_KEY_SIZE;
157 -       default:
158 -               BUG();
159 -       }
160 -       return 0;
163  #define FS_FNAME_NUM_SCATTER_ENTRIES   4
164  #define FS_CRYPTO_BLOCK_SIZE           16
165  #define FS_FNAME_CRYPTO_DIGEST_SIZE    32
166 @@ -202,13 +185,6 @@ static inline bool fscrypt_valid_filenames_enc_mode(u32 mode)
167         return (mode == FS_ENCRYPTION_MODE_AES_256_CTS);
170 -static inline u32 fscrypt_validate_encryption_key_size(u32 mode, u32 size)
172 -       if (size == fscrypt_key_size(mode))
173 -               return size;
174 -       return 0;
177  static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
179         if (str->len == 1 && str->name[0] == '.')