On Thu, Jan 18, 2018 at 01:13:59PM +0000, André Draszik wrote: > -static int validate_user_key(struct fscrypt_info *crypt_info, > +static inline struct key *fscrypt_get_encrypted_key(const char *description) > +{ > + if (IS_ENABLED(CONFIG_ENCRYPTED_KEYS)) > + return request_key(&key_type_encrypted, description, NULL); > + return ERR_PTR(-ENOKEY); > +} > + > +static int validate_keyring_key(struct fscrypt_info *crypt_info, > struct fscrypt_context *ctx, u8 *raw_key, > const char *prefix, int min_keysize) > { > char *description; > struct key *keyring_key; > - struct fscrypt_key *master_key; > - const struct user_key_payload *ukp; > + const u8 *master_key; > + u32 master_key_len; > int res; > > description = kasprintf(GFP_NOFS, "%s%*phN", prefix, > @@ -83,39 +93,55 @@ static int validate_user_key(struct fscrypt_info *crypt_info, > return -ENOMEM; > > keyring_key = request_key(&key_type_logon, description, NULL); > + if (keyring_key == ERR_PTR(-ENOKEY)) > + keyring_key = fscrypt_get_encrypted_key(description); > kfree(description); > if (IS_ERR(keyring_key)) > return PTR_ERR(keyring_key); > down_read(&keyring_key->sem); > > - if (keyring_key->type != &key_type_logon) { > + if (keyring_key->type == &key_type_logon) { > + const struct user_key_payload *ukp; > + const struct fscrypt_key *fk; > + > + ukp = user_key_payload_locked(keyring_key); > + if (!ukp) { > + /* key was revoked before we acquired its semaphore */ > + res = -EKEYREVOKED; > + goto out; > + } > + if (ukp->datalen != sizeof(struct fscrypt_key)) { > + res = -EINVAL; > + goto out; > + } > + fk = (struct fscrypt_key *)ukp->data; > + master_key = fk->raw; > + master_key_len = fk->size; > + } else if (keyring_key->type == &key_type_encrypted) { > + const struct encrypted_key_payload *ekp; > + > + ekp = keyring_key->payload.data[0]; > + master_key = ekp->decrypted_data; > + master_key_len = ekp->decrypted_datalen; > + } else { > printk_once(KERN_WARNING > - "%s: key type must be logon\n", __func__); > + "%s: key type must be logon or encrypted\n", > + __func__); > res = -ENOKEY; > goto out; > } > - ukp = user_key_payload_locked(keyring_key); > - if (!ukp) { > - /* key was revoked before we acquired its semaphore */ > - res = -EKEYREVOKED; > - goto out; > - } > - if (ukp->datalen != sizeof(struct fscrypt_key)) { > - res = -EINVAL; > - goto out; > - } > - master_key = (struct fscrypt_key *)ukp->data; > BUILD_BUG_ON(FS_AES_128_ECB_KEY_SIZE != FS_KEY_DERIVATION_NONCE_SIZE); > > - if (master_key->size < min_keysize || master_key->size > FS_MAX_KEY_SIZE > - || master_key->size % AES_BLOCK_SIZE != 0) { > + if (master_key_len < min_keysize || master_key_len > FS_MAX_KEY_SIZE > + || master_key_len % AES_BLOCK_SIZE != 0) { > printk_once(KERN_WARNING > - "%s: key size incorrect: %d\n", > - __func__, master_key->size); > + "%s: key size incorrect: %u\n", > + __func__, master_key_len); > res = -ENOKEY; > goto out; > } > - res = derive_key_aes(ctx->nonce, master_key, raw_key); > + res = derive_key_aes(ctx->nonce, master_key, master_key_len, raw_key); > + > out: > up_read(&keyring_key->sem); > key_put(keyring_key); > @@ -302,12 +328,12 @@ int fscrypt_get_encryption_info(struct inode *inode) > if (!raw_key) > goto out; > > - res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX, > - keysize); > + res = validate_keyring_key(crypt_info, &ctx, raw_key, > + FS_KEY_DESC_PREFIX, keysize); > if (res && inode->i_sb->s_cop->key_prefix) { > - int res2 = validate_user_key(crypt_info, &ctx, raw_key, > - inode->i_sb->s_cop->key_prefix, > - keysize); > + int res2 = validate_keyring_key(crypt_info, &ctx, raw_key, > + inode->i_sb->s_cop->key_prefix, > + keysize); > if (res2) { > if (res2 == -ENOKEY) > res = -ENOKEY; > -- > 2.15.1 > > -- > To unsubscribe from this list: send the line "unsubscribe keyrings" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html The code changes here look fine, but unfortunately there is a lock ordering problem exposed by using a key type that implements the key_type ->read() method. The problem is that encrypted_read() can take a page fault during copy_to_user() while holding the key semaphore, which then (with ext4) can trigger the start of a jbd2 transaction. Meanwhile fscrypt_get_encryption_info() can be called from within a jbd2 transaction via fscrypt_inherit_context(), which results in a different locking order. We probably will need to fix this by removing the call to fscrypt_get_encryption_info() from fscrypt_inherit_context(). I've pasted the lockdep report I got below: [ 432.705339] [ 432.705681] ====================================================== [ 432.707015] WARNING: possible circular locking dependency detected [ 432.708155] 4.15.0-rc8-next-20180119-00019-gab7ec46b6936 #31 Not tainted [ 432.709365] ------------------------------------------------------ [ 432.710482] keyctl/877 is trying to acquire lock: [ 432.711286] (&mm->mmap_sem){++++}, at: [<00000000e8bba1c7>] __might_fault+0xce/0x1a0 [ 432.712688] [ 432.712688] but task is already holding lock: [ 432.713684] (&type->lock_class#2){++++}, at: [<000000008ccfa156>] keyctl_read_key+0x174/0x240 [ 432.715176] [ 432.715176] which lock already depends on the new lock. [ 432.715176] [ 432.716601] [ 432.716601] the existing dependency chain (in reverse order) is: [ 432.717901] [ 432.717901] -> #3 (&type->lock_class#2){++++}: [ 432.718924] lock_acquire+0xaa/0x170 [ 432.719632] down_read+0x37/0xa0 [ 432.720298] validate_keyring_key.isra.1+0x97/0x410 [ 432.721218] fscrypt_get_encryption_info+0x724/0x1200 [ 432.722233] fscrypt_inherit_context+0x2c1/0x330 [ 432.723067] __ext4_new_inode+0x34f5/0x44d0 [ 432.723830] ext4_create+0x195/0x4a0 [ 432.724499] lookup_open+0xbe2/0x1400 [ 432.725185] path_openat+0xb31/0x1e50 [ 432.725876] do_filp_open+0x175/0x250 [ 432.726572] do_sys_open+0x219/0x3f0 [ 432.727312] entry_SYSCALL_64_fastpath+0x1e/0x8b [ 432.728153] [ 432.728153] -> #2 (jbd2_handle){.+.+}: [ 432.729008] lock_acquire+0xaa/0x170 [ 432.729680] start_this_handle+0x47b/0x1020 [ 432.730463] jbd2__journal_start+0x32e/0x5c0 [ 432.731276] __ext4_journal_start_sb+0xa8/0x190 [ 432.732183] ext4_truncate+0x4dd/0xd00 [ 432.732868] ext4_setattr+0xa62/0x1ac0 [ 432.733528] notify_change+0x672/0xdb0 [ 432.734198] do_truncate+0x111/0x1c0 [ 432.734831] path_openat+0xee6/0x1e50 [ 432.735476] do_filp_open+0x175/0x250 [ 432.736149] do_sys_open+0x219/0x3f0 [ 432.736785] entry_SYSCALL_64_fastpath+0x1e/0x8b [ 432.737576] [ 432.737576] -> #1 (&ei->i_mmap_sem){++++}: [ 432.738508] lock_acquire+0xaa/0x170 [ 432.739148] down_read+0x37/0xa0 [ 432.739735] ext4_filemap_fault+0x7b/0xb0 [ 432.740446] __do_fault+0x7a/0x200 [ 432.741060] __handle_mm_fault+0x6e0/0x2040 [ 432.741801] handle_mm_fault+0x194/0x320 [ 432.742494] __do_page_fault+0x4e1/0xa70 [ 432.743184] page_fault+0x2c/0x60 [ 432.743784] __clear_user+0x3d/0x60 [ 432.744409] clear_user+0x76/0xa0 [ 432.745009] load_elf_binary+0x2bf6/0x2f10 [ 432.745753] search_binary_handler+0x136/0x450 [ 432.746522] do_execveat_common.isra.12+0x1241/0x19c0 [ 432.747339] do_execve+0x2c/0x40 [ 432.747881] try_to_run_init_process+0x12/0x40 [ 432.748611] kernel_init+0xf2/0x180 [ 432.749190] ret_from_fork+0x3a/0x50 [ 432.749785] [ 432.749785] -> #0 (&mm->mmap_sem){++++}: [ 432.750576] __lock_acquire+0x8d1/0x12d0 [ 432.751232] lock_acquire+0xaa/0x170 [ 432.751848] __might_fault+0x12b/0x1a0 [ 432.752478] _copy_to_user+0x27/0xc0 [ 432.753080] encrypted_read+0x54d/0x7b0 [ 432.753734] keyctl_read_key+0x1f2/0x240 [ 432.754396] SyS_keyctl+0x184/0x2a0 [ 432.754995] entry_SYSCALL_64_fastpath+0x1e/0x8b [ 432.755778] [ 432.755778] other info that might help us debug this: [ 432.755778] [ 432.756972] Chain exists of: [ 432.756972] &mm->mmap_sem --> jbd2_handle --> &type->lock_class#2 [ 432.756972] [ 432.758498] Possible unsafe locking scenario: [ 432.758498] [ 432.759302] CPU0 CPU1 [ 432.759919] ---- ---- [ 432.760536] lock(&type->lock_class#2); [ 432.761100] lock(jbd2_handle); [ 432.761926] lock(&type->lock_class#2); [ 432.762836] lock(&mm->mmap_sem); [ 432.763348] [ 432.763348] *** DEADLOCK *** [ 432.763348] [ 432.764209] 1 lock held by keyctl/877: [ 432.764765] #0: (&type->lock_class#2){++++}, at: [<000000008ccfa156>] keyctl_read_key+0x174/0x240 [ 432.766045] [ 432.766045] stack backtrace: [ 432.766671] CPU: 1 PID: 877 Comm: keyctl Not tainted 4.15.0-rc8-next-20180119-00019-gab7ec46b6936 #31 [ 432.768021] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014 [ 432.769211] Call Trace: [ 432.769559] dump_stack+0x8d/0xd5 [ 432.770041] print_circular_bug.isra.20+0x321/0x5e0 [ 432.770712] ? save_trace+0xd6/0x250 [ 432.771185] check_prev_add.constprop.27+0xa2a/0x1670 [ 432.771867] ? depot_save_stack+0x2d5/0x490 [ 432.772504] ? check_usage+0x13c0/0x13c0 [ 432.773047] ? trace_hardirqs_on_caller+0x3dc/0x550 [ 432.773712] ? _raw_spin_unlock_irqrestore+0x39/0x60 [ 432.774401] ? depot_save_stack+0x2d5/0x490 [ 432.774979] ? kasan_kmalloc+0x13a/0x170 [ 432.775522] ? validate_chain.isra.24+0x13ee/0x2410 [ 432.776187] validate_chain.isra.24+0x13ee/0x2410 [ 432.776831] ? check_prev_add.constprop.27+0x1670/0x1670 [ 432.777546] __lock_acquire+0x8d1/0x12d0 [ 432.778088] lock_acquire+0xaa/0x170 [ 432.778576] ? __might_fault+0xce/0x1a0 [ 432.779096] __might_fault+0x12b/0x1a0 [ 432.779608] ? __might_fault+0xce/0x1a0 [ 432.780029] _copy_to_user+0x27/0xc0 [ 432.780438] encrypted_read+0x54d/0x7b0 [ 432.780858] ? key_task_permission+0x16e/0x3b0 [ 432.781340] ? encrypted_instantiate+0x8b0/0x8b0 [ 432.781851] ? creds_are_invalid+0x9/0x50 [ 432.782287] ? lookup_user_key+0x19a/0xf50 [ 432.782736] ? __lock_acquire+0x8d1/0x12d0 [ 432.783182] ? key_validate+0xb0/0xb0 [ 432.783602] ? keyctl_read_key+0x174/0x240 [ 432.784058] keyctl_read_key+0x1f2/0x240 [ 432.784486] SyS_keyctl+0x184/0x2a0 [ 432.784875] entry_SYSCALL_64_fastpath+0x1e/0x8b [ 432.785374] RIP: 0033:0x7f812b6c8259