aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/crypto_key.c
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2015-05-31 13:34:22 -0400
committerTheodore Ts'o <tytso@mit.edu>2015-05-31 13:34:22 -0400
commitc936e1ec2879e43599d801dfa6fe58e7ccfee433 (patch)
treea09688def0b1c75f7e23a9b1c98848f41e043d2e /fs/ext4/crypto_key.c
parent71dea01ea2edb73f3c5d9a0cd7ba028bb9313287 (diff)
ext4 crypto: use per-inode tfm structure
As suggested by Herbert Xu, we shouldn't allocate a new tfm each time we read or write a page. Instead we can use a single tfm hanging off the inode's crypt_info structure for all of our encryption needs for that inode, since the tfm can be used by multiple crypto requests in parallel. Also use cmpxchg() to avoid races that could result in crypt_info structure getting doubly allocated or doubly freed. Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/crypto_key.c')
-rw-r--r--fs/ext4/crypto_key.c108
1 files changed, 78 insertions, 30 deletions
diff --git a/fs/ext4/crypto_key.c b/fs/ext4/crypto_key.c
index 858d7d67a4e1..442d24e8efc0 100644
--- a/fs/ext4/crypto_key.c
+++ b/fs/ext4/crypto_key.c
@@ -84,20 +84,32 @@ out:
84 return res; 84 return res;
85} 85}
86 86
87void ext4_free_encryption_info(struct inode *inode) 87void ext4_free_crypt_info(struct ext4_crypt_info *ci)
88{ 88{
89 struct ext4_inode_info *ei = EXT4_I(inode);
90 struct ext4_crypt_info *ci = ei->i_crypt_info;
91
92 if (!ci) 89 if (!ci)
93 return; 90 return;
94 91
95 if (ci->ci_keyring_key) 92 if (ci->ci_keyring_key)
96 key_put(ci->ci_keyring_key); 93 key_put(ci->ci_keyring_key);
97 crypto_free_ablkcipher(ci->ci_ctfm); 94 crypto_free_ablkcipher(ci->ci_ctfm);
98 memzero_explicit(&ci->ci_raw, sizeof(ci->ci_raw));
99 kmem_cache_free(ext4_crypt_info_cachep, ci); 95 kmem_cache_free(ext4_crypt_info_cachep, ci);
100 ei->i_crypt_info = NULL; 96}
97
98void ext4_free_encryption_info(struct inode *inode,
99 struct ext4_crypt_info *ci)
100{
101 struct ext4_inode_info *ei = EXT4_I(inode);
102 struct ext4_crypt_info *prev;
103
104 if (ci == NULL)
105 ci = ACCESS_ONCE(ei->i_crypt_info);
106 if (ci == NULL)
107 return;
108 prev = cmpxchg(&ei->i_crypt_info, ci, NULL);
109 if (prev != ci)
110 return;
111
112 ext4_free_crypt_info(ci);
101} 113}
102 114
103int _ext4_get_encryption_info(struct inode *inode) 115int _ext4_get_encryption_info(struct inode *inode)
@@ -111,6 +123,10 @@ int _ext4_get_encryption_info(struct inode *inode)
111 struct ext4_encryption_context ctx; 123 struct ext4_encryption_context ctx;
112 struct user_key_payload *ukp; 124 struct user_key_payload *ukp;
113 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); 125 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
126 struct crypto_ablkcipher *ctfm;
127 const char *cipher_str;
128 char raw_key[EXT4_MAX_KEY_SIZE];
129 char mode;
114 int res; 130 int res;
115 131
116 if (!ext4_read_workqueue) { 132 if (!ext4_read_workqueue) {
@@ -119,11 +135,14 @@ int _ext4_get_encryption_info(struct inode *inode)
119 return res; 135 return res;
120 } 136 }
121 137
122 if (ei->i_crypt_info) { 138retry:
123 if (!ei->i_crypt_info->ci_keyring_key || 139 crypt_info = ACCESS_ONCE(ei->i_crypt_info);
124 key_validate(ei->i_crypt_info->ci_keyring_key) == 0) 140 if (crypt_info) {
141 if (!crypt_info->ci_keyring_key ||
142 key_validate(crypt_info->ci_keyring_key) == 0)
125 return 0; 143 return 0;
126 ext4_free_encryption_info(inode); 144 ext4_free_encryption_info(inode, crypt_info);
145 goto retry;
127 } 146 }
128 147
129 res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION, 148 res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
@@ -144,26 +163,37 @@ int _ext4_get_encryption_info(struct inode *inode)
144 if (!crypt_info) 163 if (!crypt_info)
145 return -ENOMEM; 164 return -ENOMEM;
146 165
147 ei->i_crypt_policy_flags = ctx.flags;
148 crypt_info->ci_flags = ctx.flags; 166 crypt_info->ci_flags = ctx.flags;
149 crypt_info->ci_data_mode = ctx.contents_encryption_mode; 167 crypt_info->ci_data_mode = ctx.contents_encryption_mode;
150 crypt_info->ci_filename_mode = ctx.filenames_encryption_mode; 168 crypt_info->ci_filename_mode = ctx.filenames_encryption_mode;
151 crypt_info->ci_ctfm = NULL; 169 crypt_info->ci_ctfm = NULL;
170 crypt_info->ci_keyring_key = NULL;
152 memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor, 171 memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
153 sizeof(crypt_info->ci_master_key)); 172 sizeof(crypt_info->ci_master_key));
154 if (S_ISREG(inode->i_mode)) 173 if (S_ISREG(inode->i_mode))
155 crypt_info->ci_size = 174 mode = crypt_info->ci_data_mode;
156 ext4_encryption_key_size(crypt_info->ci_data_mode);
157 else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) 175 else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
158 crypt_info->ci_size = 176 mode = crypt_info->ci_filename_mode;
159 ext4_encryption_key_size(crypt_info->ci_filename_mode);
160 else 177 else
161 BUG(); 178 BUG();
162 BUG_ON(!crypt_info->ci_size); 179 switch (mode) {
163 if (DUMMY_ENCRYPTION_ENABLED(sbi)) { 180 case EXT4_ENCRYPTION_MODE_AES_256_XTS:
164 memset(crypt_info->ci_raw, 0x42, EXT4_AES_256_XTS_KEY_SIZE); 181 cipher_str = "xts(aes)";
182 break;
183 case EXT4_ENCRYPTION_MODE_AES_256_CTS:
184 cipher_str = "cts(cbc(aes))";
185 break;
186 default:
187 printk_once(KERN_WARNING
188 "ext4: unsupported key mode %d (ino %u)\n",
189 mode, (unsigned) inode->i_ino);
190 res = -ENOKEY;
165 goto out; 191 goto out;
166 } 192 }
193 if (DUMMY_ENCRYPTION_ENABLED(sbi)) {
194 memset(raw_key, 0x42, EXT4_AES_256_XTS_KEY_SIZE);
195 goto got_key;
196 }
167 memcpy(full_key_descriptor, EXT4_KEY_DESC_PREFIX, 197 memcpy(full_key_descriptor, EXT4_KEY_DESC_PREFIX,
168 EXT4_KEY_DESC_PREFIX_SIZE); 198 EXT4_KEY_DESC_PREFIX_SIZE);
169 sprintf(full_key_descriptor + EXT4_KEY_DESC_PREFIX_SIZE, 199 sprintf(full_key_descriptor + EXT4_KEY_DESC_PREFIX_SIZE,
@@ -177,6 +207,7 @@ int _ext4_get_encryption_info(struct inode *inode)
177 keyring_key = NULL; 207 keyring_key = NULL;
178 goto out; 208 goto out;
179 } 209 }
210 crypt_info->ci_keyring_key = keyring_key;
180 BUG_ON(keyring_key->type != &key_type_logon); 211 BUG_ON(keyring_key->type != &key_type_logon);
181 ukp = ((struct user_key_payload *)keyring_key->payload.data); 212 ukp = ((struct user_key_payload *)keyring_key->payload.data);
182 if (ukp->datalen != sizeof(struct ext4_encryption_key)) { 213 if (ukp->datalen != sizeof(struct ext4_encryption_key)) {
@@ -188,19 +219,36 @@ int _ext4_get_encryption_info(struct inode *inode)
188 EXT4_KEY_DERIVATION_NONCE_SIZE); 219 EXT4_KEY_DERIVATION_NONCE_SIZE);
189 BUG_ON(master_key->size != EXT4_AES_256_XTS_KEY_SIZE); 220 BUG_ON(master_key->size != EXT4_AES_256_XTS_KEY_SIZE);
190 res = ext4_derive_key_aes(ctx.nonce, master_key->raw, 221 res = ext4_derive_key_aes(ctx.nonce, master_key->raw,
191 crypt_info->ci_raw); 222 raw_key);
192out: 223got_key:
193 if (res < 0) { 224 ctfm = crypto_alloc_ablkcipher(cipher_str, 0, 0);
194 if (res == -ENOKEY) 225 if (!ctfm || IS_ERR(ctfm)) {
195 res = 0; 226 res = ctfm ? PTR_ERR(ctfm) : -ENOMEM;
196 kmem_cache_free(ext4_crypt_info_cachep, crypt_info); 227 printk(KERN_DEBUG
197 } else { 228 "%s: error %d (inode %u) allocating crypto tfm\n",
198 ei->i_crypt_info = crypt_info; 229 __func__, res, (unsigned) inode->i_ino);
199 crypt_info->ci_keyring_key = keyring_key; 230 goto out;
200 keyring_key = NULL; 231 }
232 crypt_info->ci_ctfm = ctfm;
233 crypto_ablkcipher_clear_flags(ctfm, ~0);
234 crypto_tfm_set_flags(crypto_ablkcipher_tfm(ctfm),
235 CRYPTO_TFM_REQ_WEAK_KEY);
236 res = crypto_ablkcipher_setkey(ctfm, raw_key,
237 ext4_encryption_key_size(mode));
238 if (res)
239 goto out;
240 memzero_explicit(raw_key, sizeof(raw_key));
241 if (cmpxchg(&ei->i_crypt_info, NULL, crypt_info) != NULL) {
242 ext4_free_crypt_info(crypt_info);
243 goto retry;
201 } 244 }
202 if (keyring_key) 245 return 0;
203 key_put(keyring_key); 246
247out:
248 if (res == -ENOKEY)
249 res = 0;
250 ext4_free_crypt_info(crypt_info);
251 memzero_explicit(raw_key, sizeof(raw_key));
204 return res; 252 return res;
205} 253}
206 254