Skip to content

Commit d051311

Browse files
Jaegeuk KimTheScarastic
authored andcommitted
fscrypto/f2fs: allow fs-specific key prefix for fs encryption
This patch allows fscrypto to handle a second key prefix given by filesystem. The main reason is to provide backward compatibility, since previously f2fs used "f2fs:" as a crypto prefix instead of "fscrypt:". Later, ext4 should also provide key_prefix() to give "ext4:". One concern decribed by Ted would be kinda double check overhead of prefixes. In x86, for example, validate_user_key consumes 8 ms after boot-up, which turns out derive_key_aes() consumed most of the time to load specific crypto module. After such the cold miss, it shows almost zero latencies, which treats as a negligible overhead. Note that request_key() detects wrong prefix in prior to derive_key_aes() even. Cc: Ted Tso <tytso@mit.edu> Cc: stable@vger.kernel.org # v4.6 Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> Conflicts: fs/crypto/keyinfo.c
1 parent bdd2ae6 commit d051311

4 files changed

Lines changed: 98 additions & 44 deletions

File tree

fs/crypto/keyinfo.c

Lines changed: 76 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,67 @@ static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE],
8282
return res;
8383
}
8484

85+
static int validate_user_key(struct fscrypt_info *crypt_info,
86+
struct fscrypt_context *ctx, u8 *raw_key,
87+
u8 *prefix, int prefix_size)
88+
{
89+
u8 *full_key_descriptor;
90+
struct key *keyring_key;
91+
struct fscrypt_key *master_key;
92+
const struct user_key_payload *ukp;
93+
int full_key_len = prefix_size + (FS_KEY_DESCRIPTOR_SIZE * 2) + 1;
94+
int res;
95+
96+
full_key_descriptor = kmalloc(full_key_len, GFP_NOFS);
97+
if (!full_key_descriptor)
98+
return -ENOMEM;
99+
100+
memcpy(full_key_descriptor, prefix, prefix_size);
101+
sprintf(full_key_descriptor + prefix_size,
102+
"%*phN", FS_KEY_DESCRIPTOR_SIZE,
103+
ctx->master_key_descriptor);
104+
full_key_descriptor[full_key_len - 1] = '\0';
105+
keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL);
106+
kfree(full_key_descriptor);
107+
if (IS_ERR(keyring_key))
108+
return PTR_ERR(keyring_key);
109+
110+
if (keyring_key->type != &key_type_logon) {
111+
printk_once(KERN_WARNING
112+
"%s: key type must be logon\n", __func__);
113+
res = -ENOKEY;
114+
goto out;
115+
}
116+
down_read(&keyring_key->sem);
117+
ukp = ((struct user_key_payload *)keyring_key->payload.data);
118+
if (ukp->datalen != sizeof(struct fscrypt_key)) {
119+
res = -EINVAL;
120+
up_read(&keyring_key->sem);
121+
goto out;
122+
}
123+
master_key = (struct fscrypt_key *)ukp->data;
124+
BUILD_BUG_ON(FS_AES_128_ECB_KEY_SIZE != FS_KEY_DERIVATION_NONCE_SIZE);
125+
126+
if (master_key->size != FS_AES_256_XTS_KEY_SIZE) {
127+
printk_once(KERN_WARNING
128+
"%s: key size incorrect: %d\n",
129+
__func__, master_key->size);
130+
res = -ENOKEY;
131+
up_read(&keyring_key->sem);
132+
goto out;
133+
}
134+
res = derive_key_aes(ctx->nonce, master_key->raw, raw_key);
135+
up_read(&keyring_key->sem);
136+
if (res)
137+
goto out;
138+
139+
crypt_info->ci_keyring_key = keyring_key;
140+
return 0;
141+
out:
142+
key_put(keyring_key);
143+
return res;
144+
}
145+
85146
static void put_crypt_info(struct fscrypt_info *ci)
86147
{
87148
if (!ci)
@@ -96,12 +157,7 @@ static void put_crypt_info(struct fscrypt_info *ci)
96157
int get_crypt_info(struct inode *inode)
97158
{
98159
struct fscrypt_info *crypt_info;
99-
u8 full_key_descriptor[FS_KEY_DESC_PREFIX_SIZE +
100-
(FS_KEY_DESCRIPTOR_SIZE * 2) + 1];
101-
struct key *keyring_key = NULL;
102-
struct fscrypt_key *master_key;
103160
struct fscrypt_context ctx;
104-
struct user_key_payload *ukp;
105161
struct crypto_ablkcipher *ctfm;
106162
const char *cipher_str;
107163
u8 raw_key[FS_MAX_KEY_SIZE];
@@ -172,48 +228,24 @@ int get_crypt_info(struct inode *inode)
172228
memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
173229
goto got_key;
174230
}
175-
memcpy(full_key_descriptor, FS_KEY_DESC_PREFIX,
176-
FS_KEY_DESC_PREFIX_SIZE);
177-
sprintf(full_key_descriptor + FS_KEY_DESC_PREFIX_SIZE,
178-
"%*phN", FS_KEY_DESCRIPTOR_SIZE,
179-
ctx.master_key_descriptor);
180-
full_key_descriptor[FS_KEY_DESC_PREFIX_SIZE +
181-
(2 * FS_KEY_DESCRIPTOR_SIZE)] = '\0';
182-
keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL);
183-
if (IS_ERR(keyring_key)) {
184-
res = PTR_ERR(keyring_key);
185-
keyring_key = NULL;
186-
goto out;
187-
}
188-
crypt_info->ci_keyring_key = keyring_key;
189-
if (keyring_key->type != &key_type_logon) {
190-
printk_once(KERN_WARNING
191-
"%s: key type must be logon\n", __func__);
192-
res = -ENOKEY;
193-
goto out;
194-
}
195-
down_read(&keyring_key->sem);
196-
ukp = ((struct user_key_payload *)keyring_key->payload.data);
197-
if (ukp->datalen != sizeof(struct fscrypt_key)) {
198-
res = -EINVAL;
199-
up_read(&keyring_key->sem);
200-
goto out;
201-
}
202-
master_key = (struct fscrypt_key *)ukp->data;
203-
BUILD_BUG_ON(FS_AES_128_ECB_KEY_SIZE != FS_KEY_DERIVATION_NONCE_SIZE);
204231

205-
if (master_key->size != FS_AES_256_XTS_KEY_SIZE) {
206-
printk_once(KERN_WARNING
207-
"%s: key size incorrect: %d\n",
208-
__func__, master_key->size);
209-
res = -ENOKEY;
210-
up_read(&keyring_key->sem);
232+
res = validate_user_key(crypt_info, &ctx, raw_key,
233+
FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE);
234+
if (res && inode->i_sb->s_cop->key_prefix) {
235+
u8 *prefix = NULL;
236+
int prefix_size, res2;
237+
238+
prefix_size = inode->i_sb->s_cop->key_prefix(inode, &prefix);
239+
res2 = validate_user_key(crypt_info, &ctx, raw_key,
240+
prefix, prefix_size);
241+
if (res2) {
242+
if (res2 == -ENOKEY)
243+
res = -ENOKEY;
244+
goto out;
245+
}
246+
} else if (res) {
211247
goto out;
212248
}
213-
res = derive_key_aes(ctx.nonce, master_key->raw, raw_key);
214-
up_read(&keyring_key->sem);
215-
if (res)
216-
goto out;
217249
got_key:
218250
ctfm = crypto_alloc_ablkcipher(cipher_str, 0, 0);
219251
if (!ctfm || IS_ERR(ctfm)) {

fs/f2fs/f2fs.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,13 +742,21 @@ enum {
742742
MAX_TIME,
743743
};
744744

745+
#ifdef CONFIG_F2FS_FS_ENCRYPTION
746+
#define F2FS_KEY_DESC_PREFIX "f2fs:"
747+
#define F2FS_KEY_DESC_PREFIX_SIZE 5
748+
#endif
745749
struct f2fs_sb_info {
746750
struct super_block *sb; /* pointer to VFS super block */
747751
struct proc_dir_entry *s_proc; /* proc entry */
748752
struct f2fs_super_block *raw_super; /* raw super block pointer */
749753
int valid_super_block; /* valid super block no */
750754
int s_flag; /* flags for sbi */
751755

756+
#ifdef CONFIG_F2FS_FS_ENCRYPTION
757+
u8 key_prefix[F2FS_KEY_DESC_PREFIX_SIZE];
758+
u8 key_prefix_size;
759+
#endif
752760
/* for node-related operations */
753761
struct f2fs_nm_info *nm_info; /* node manager */
754762
struct inode *node_inode; /* cache node blocks */

fs/f2fs/super.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,12 @@ static int f2fs_get_context(struct inode *inode, void *ctx, size_t len)
964964
ctx, len, NULL);
965965
}
966966

967+
static int f2fs_key_prefix(struct inode *inode, u8 **key)
968+
{
969+
*key = F2FS_I_SB(inode)->key_prefix;
970+
return F2FS_I_SB(inode)->key_prefix_size;
971+
}
972+
967973
static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len,
968974
void *fs_data)
969975
{
@@ -980,6 +986,7 @@ static unsigned f2fs_max_namelen(struct inode *inode)
980986

981987
static struct fscrypt_operations f2fs_cryptops = {
982988
.get_context = f2fs_get_context,
989+
.key_prefix = f2fs_key_prefix,
983990
.set_context = f2fs_set_context,
984991
.is_encrypted = f2fs_encrypted_inode,
985992
.empty_dir = f2fs_empty_dir,
@@ -1330,6 +1337,12 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
13301337

13311338
INIT_LIST_HEAD(&sbi->s_list);
13321339
mutex_init(&sbi->umount_mutex);
1340+
1341+
#ifdef CONFIG_F2FS_FS_ENCRYPTION
1342+
memcpy(sbi->key_prefix, F2FS_KEY_DESC_PREFIX,
1343+
F2FS_KEY_DESC_PREFIX_SIZE);
1344+
sbi->key_prefix_size = F2FS_KEY_DESC_PREFIX_SIZE;
1345+
#endif
13331346
}
13341347

13351348
/*

include/linux/fscrypto.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ struct fscrypt_name {
174174
*/
175175
struct fscrypt_operations {
176176
int (*get_context)(struct inode *, void *, size_t);
177+
int (*key_prefix)(struct inode *, u8 **);
177178
int (*prepare_context)(struct inode *);
178179
int (*set_context)(struct inode *, const void *, size_t, void *);
179180
int (*dummy_context)(struct inode *);

0 commit comments

Comments
 (0)