From 386d7447be133dc758152aeb19e96c791555d230 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 30 Mar 2017 10:58:35 +0200 Subject: [PATCH] 4.9-stable patches added patches: fscrypt-remove-broken-support-for-detecting-keyring-key-revocation.patch sched-rt-add-a-missing-rescheduling-point.patch usb-musb-fix-possible-spinlock-deadlock.patch --- ...for-detecting-keyring-key-revocation.patch | 245 ++++++++++++++++++ ...anup-the-page-tracking-srcu-instance.patch | 62 ----- ...-rt-add-a-missing-rescheduling-point.patch | 76 ++++++ queue-4.9/series | 4 +- ...-musb-fix-possible-spinlock-deadlock.patch | 88 +++++++ 5 files changed, 412 insertions(+), 63 deletions(-) create mode 100644 queue-4.9/fscrypt-remove-broken-support-for-detecting-keyring-key-revocation.patch delete mode 100644 queue-4.9/kvm-x86-cleanup-the-page-tracking-srcu-instance.patch create mode 100644 queue-4.9/sched-rt-add-a-missing-rescheduling-point.patch create mode 100644 queue-4.9/usb-musb-fix-possible-spinlock-deadlock.patch diff --git a/queue-4.9/fscrypt-remove-broken-support-for-detecting-keyring-key-revocation.patch b/queue-4.9/fscrypt-remove-broken-support-for-detecting-keyring-key-revocation.patch new file mode 100644 index 00000000000..bf6cceecd1e --- /dev/null +++ b/queue-4.9/fscrypt-remove-broken-support-for-detecting-keyring-key-revocation.patch @@ -0,0 +1,245 @@ +From 1b53cf9815bb4744958d41f3795d5d5a1d365e2d Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Tue, 21 Feb 2017 15:07:11 -0800 +Subject: fscrypt: remove broken support for detecting keyring key revocation + +From: Eric Biggers + +commit 1b53cf9815bb4744958d41f3795d5d5a1d365e2d upstream. + +Filesystem encryption ostensibly supported revoking a keyring key that +had been used to "unlock" encrypted files, causing those files to become +"locked" again. This was, however, buggy for several reasons, the most +severe of which was that when key revocation happened to be detected for +an inode, its fscrypt_info was immediately freed, even while other +threads could be using it for encryption or decryption concurrently. +This could be exploited to crash the kernel or worse. + +This patch fixes the use-after-free by removing the code which detects +the keyring key having been revoked, invalidated, or expired. Instead, +an encrypted inode that is "unlocked" now simply remains unlocked until +it is evicted from memory. Note that this is no worse than the case for +block device-level encryption, e.g. dm-crypt, and it still remains +possible for a privileged user to evict unused pages, inodes, and +dentries by running 'sync; echo 3 > /proc/sys/vm/drop_caches', or by +simply unmounting the filesystem. In fact, one of those actions was +already needed anyway for key revocation to work even somewhat sanely. +This change is not expected to break any applications. + +In the future I'd like to implement a real API for fscrypt key +revocation that interacts sanely with ongoing filesystem operations --- +waiting for existing operations to complete and blocking new operations, +and invalidating and sanitizing key material and plaintext from the VFS +caches. But this is a hard problem, and for now this bug must be fixed. + +This bug affected almost all versions of ext4, f2fs, and ubifs +encryption, and it was potentially reachable in any kernel configured +with encryption support (CONFIG_EXT4_ENCRYPTION=y, +CONFIG_EXT4_FS_ENCRYPTION=y, CONFIG_F2FS_FS_ENCRYPTION=y, or +CONFIG_UBIFS_FS_ENCRYPTION=y). Note that older kernels did not use the +shared fs/crypto/ code, but due to the potential security implications +of this bug, it may still be worthwhile to backport this fix to them. + +Fixes: b7236e21d55f ("ext4 crypto: reorganize how we store keys in the inode") +Signed-off-by: Eric Biggers +Signed-off-by: Theodore Ts'o +Acked-by: Michael Halcrow +Signed-off-by: Greg Kroah-Hartman + +--- + fs/crypto/crypto.c | 10 --------- + fs/crypto/fname.c | 2 - + fs/crypto/keyinfo.c | 52 ++++++++--------------------------------------- + include/linux/fscrypto.h | 2 - + 4 files changed, 11 insertions(+), 55 deletions(-) + +--- a/fs/crypto/crypto.c ++++ b/fs/crypto/crypto.c +@@ -352,7 +352,6 @@ EXPORT_SYMBOL(fscrypt_zeroout_range); + static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) + { + struct dentry *dir; +- struct fscrypt_info *ci; + int dir_has_key, cached_with_key; + + if (flags & LOOKUP_RCU) +@@ -364,18 +363,11 @@ static int fscrypt_d_revalidate(struct d + return 0; + } + +- ci = d_inode(dir)->i_crypt_info; +- if (ci && ci->ci_keyring_key && +- (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) | +- (1 << KEY_FLAG_REVOKED) | +- (1 << KEY_FLAG_DEAD)))) +- ci = NULL; +- + /* this should eventually be an flag in d_flags */ + spin_lock(&dentry->d_lock); + cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY; + spin_unlock(&dentry->d_lock); +- dir_has_key = (ci != NULL); ++ dir_has_key = (d_inode(dir)->i_crypt_info != NULL); + dput(dir); + + /* +--- a/fs/crypto/fname.c ++++ b/fs/crypto/fname.c +@@ -350,7 +350,7 @@ int fscrypt_setup_filename(struct inode + fname->disk_name.len = iname->len; + return 0; + } +- ret = get_crypt_info(dir); ++ ret = fscrypt_get_encryption_info(dir); + if (ret && ret != -EOPNOTSUPP) + return ret; + +--- a/fs/crypto/keyinfo.c ++++ b/fs/crypto/keyinfo.c +@@ -99,6 +99,7 @@ static int validate_user_key(struct fscr + kfree(full_key_descriptor); + if (IS_ERR(keyring_key)) + return PTR_ERR(keyring_key); ++ down_read(&keyring_key->sem); + + if (keyring_key->type != &key_type_logon) { + printk_once(KERN_WARNING +@@ -106,11 +107,9 @@ static int validate_user_key(struct fscr + res = -ENOKEY; + goto out; + } +- down_read(&keyring_key->sem); + ukp = user_key_payload(keyring_key); + if (ukp->datalen != sizeof(struct fscrypt_key)) { + res = -EINVAL; +- up_read(&keyring_key->sem); + goto out; + } + master_key = (struct fscrypt_key *)ukp->data; +@@ -121,17 +120,11 @@ static int validate_user_key(struct fscr + "%s: key size incorrect: %d\n", + __func__, master_key->size); + res = -ENOKEY; +- up_read(&keyring_key->sem); + goto out; + } + res = derive_key_aes(ctx->nonce, master_key->raw, raw_key); +- up_read(&keyring_key->sem); +- if (res) +- goto out; +- +- crypt_info->ci_keyring_key = keyring_key; +- return 0; + out: ++ up_read(&keyring_key->sem); + key_put(keyring_key); + return res; + } +@@ -173,12 +166,11 @@ static void put_crypt_info(struct fscryp + if (!ci) + return; + +- key_put(ci->ci_keyring_key); + crypto_free_skcipher(ci->ci_ctfm); + kmem_cache_free(fscrypt_info_cachep, ci); + } + +-int get_crypt_info(struct inode *inode) ++int fscrypt_get_encryption_info(struct inode *inode) + { + struct fscrypt_info *crypt_info; + struct fscrypt_context ctx; +@@ -188,21 +180,15 @@ int get_crypt_info(struct inode *inode) + u8 *raw_key = NULL; + int res; + ++ if (inode->i_crypt_info) ++ return 0; ++ + res = fscrypt_initialize(); + if (res) + return res; + + if (!inode->i_sb->s_cop->get_context) + return -EOPNOTSUPP; +-retry: +- crypt_info = ACCESS_ONCE(inode->i_crypt_info); +- if (crypt_info) { +- if (!crypt_info->ci_keyring_key || +- key_validate(crypt_info->ci_keyring_key) == 0) +- return 0; +- fscrypt_put_encryption_info(inode, crypt_info); +- goto retry; +- } + + res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); + if (res < 0) { +@@ -230,7 +216,6 @@ retry: + crypt_info->ci_data_mode = ctx.contents_encryption_mode; + crypt_info->ci_filename_mode = ctx.filenames_encryption_mode; + crypt_info->ci_ctfm = NULL; +- crypt_info->ci_keyring_key = NULL; + memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor, + sizeof(crypt_info->ci_master_key)); + +@@ -285,14 +270,8 @@ got_key: + if (res) + goto out; + +- kzfree(raw_key); +- raw_key = NULL; +- if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) { +- put_crypt_info(crypt_info); +- goto retry; +- } +- return 0; +- ++ if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL) ++ crypt_info = NULL; + out: + if (res == -ENOKEY) + res = 0; +@@ -300,6 +279,7 @@ out: + kzfree(raw_key); + return res; + } ++EXPORT_SYMBOL(fscrypt_get_encryption_info); + + void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci) + { +@@ -317,17 +297,3 @@ void fscrypt_put_encryption_info(struct + put_crypt_info(ci); + } + EXPORT_SYMBOL(fscrypt_put_encryption_info); +- +-int fscrypt_get_encryption_info(struct inode *inode) +-{ +- struct fscrypt_info *ci = inode->i_crypt_info; +- +- if (!ci || +- (ci->ci_keyring_key && +- (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) | +- (1 << KEY_FLAG_REVOKED) | +- (1 << KEY_FLAG_DEAD))))) +- return get_crypt_info(inode); +- return 0; +-} +-EXPORT_SYMBOL(fscrypt_get_encryption_info); +--- a/include/linux/fscrypto.h ++++ b/include/linux/fscrypto.h +@@ -79,7 +79,6 @@ struct fscrypt_info { + u8 ci_filename_mode; + u8 ci_flags; + struct crypto_skcipher *ci_ctfm; +- struct key *ci_keyring_key; + u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE]; + }; + +@@ -256,7 +255,6 @@ extern int fscrypt_has_permitted_context + extern int fscrypt_inherit_context(struct inode *, struct inode *, + void *, bool); + /* keyinfo.c */ +-extern int get_crypt_info(struct inode *); + extern int fscrypt_get_encryption_info(struct inode *); + extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *); + diff --git a/queue-4.9/kvm-x86-cleanup-the-page-tracking-srcu-instance.patch b/queue-4.9/kvm-x86-cleanup-the-page-tracking-srcu-instance.patch deleted file mode 100644 index eb506ffcf17..00000000000 --- a/queue-4.9/kvm-x86-cleanup-the-page-tracking-srcu-instance.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 2beb6dad2e8f95d710159d5befb390e4f62ab5cf Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 27 Mar 2017 17:53:50 +0200 -Subject: KVM: x86: cleanup the page tracking SRCU instance - -From: Paolo Bonzini - -commit 2beb6dad2e8f95d710159d5befb390e4f62ab5cf upstream. - -SRCU uses a delayed work item. Skip cleaning it up, and -the result is use-after-free in the work item callbacks. - -Reported-by: Dmitry Vyukov -Suggested-by: Dmitry Vyukov -Fixes: 0eb05bf290cfe8610d9680b49abef37febd1c38a -Reviewed-by: Xiao Guangrong -Signed-off-by: Paolo Bonzini -Signed-off-by: Greg Kroah-Hartman - ---- - arch/x86/include/asm/kvm_page_track.h | 1 + - arch/x86/kvm/page_track.c | 8 ++++++++ - arch/x86/kvm/x86.c | 1 + - 3 files changed, 10 insertions(+) - ---- a/arch/x86/include/asm/kvm_page_track.h -+++ b/arch/x86/include/asm/kvm_page_track.h -@@ -35,6 +35,7 @@ struct kvm_page_track_notifier_node { - }; - - void kvm_page_track_init(struct kvm *kvm); -+void kvm_page_track_cleanup(struct kvm *kvm); - - void kvm_page_track_free_memslot(struct kvm_memory_slot *free, - struct kvm_memory_slot *dont); ---- a/arch/x86/kvm/page_track.c -+++ b/arch/x86/kvm/page_track.c -@@ -156,6 +156,14 @@ bool kvm_page_track_is_active(struct kvm - return !!ACCESS_ONCE(slot->arch.gfn_track[mode][index]); - } - -+void kvm_page_track_cleanup(struct kvm *kvm) -+{ -+ struct kvm_page_track_notifier_head *head; -+ -+ head = &kvm->arch.track_notifier_head; -+ cleanup_srcu_struct(&head->track_srcu); -+} -+ - void kvm_page_track_init(struct kvm *kvm) - { - struct kvm_page_track_notifier_head *head; ---- a/arch/x86/kvm/x86.c -+++ b/arch/x86/kvm/x86.c -@@ -7976,6 +7976,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm - kvm_free_vcpus(kvm); - kvfree(rcu_dereference_check(kvm->arch.apic_map, 1)); - kvm_mmu_uninit_vm(kvm); -+ kvm_page_track_cleanup(kvm); - } - - void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free, diff --git a/queue-4.9/sched-rt-add-a-missing-rescheduling-point.patch b/queue-4.9/sched-rt-add-a-missing-rescheduling-point.patch new file mode 100644 index 00000000000..bd0aaf0fa64 --- /dev/null +++ b/queue-4.9/sched-rt-add-a-missing-rescheduling-point.patch @@ -0,0 +1,76 @@ +From 619bd4a71874a8fd78eb6ccf9f272c5e98bcc7b7 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Tue, 24 Jan 2017 15:40:06 +0100 +Subject: sched/rt: Add a missing rescheduling point + +From: Sebastian Andrzej Siewior + +commit 619bd4a71874a8fd78eb6ccf9f272c5e98bcc7b7 upstream. + +Since the change in commit: + + fd7a4bed1835 ("sched, rt: Convert switched_{from, to}_rt() / prio_changed_rt() to balance callbacks") + +... we don't reschedule a task under certain circumstances: + +Lets say task-A, SCHED_OTHER, is running on CPU0 (and it may run only on +CPU0) and holds a PI lock. This task is removed from the CPU because it +used up its time slice and another SCHED_OTHER task is running. Task-B on +CPU1 runs at RT priority and asks for the lock owned by task-A. This +results in a priority boost for task-A. Task-B goes to sleep until the +lock has been made available. Task-A is already runnable (but not active), +so it receives no wake up. + +The reality now is that task-A gets on the CPU once the scheduler decides +to remove the current task despite the fact that a high priority task is +enqueued and waiting. This may take a long time. + +The desired behaviour is that CPU0 immediately reschedules after the +priority boost which made task-A the task with the lowest priority. + +Suggested-by: Peter Zijlstra +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Peter Zijlstra (Intel) +Cc: Linus Torvalds +Cc: Mike Galbraith +Cc: Thomas Gleixner +Fixes: fd7a4bed1835 ("sched, rt: Convert switched_{from, to}_rt() prio_changed_rt() to balance callbacks") +Link: http://lkml.kernel.org/r/20170124144006.29821-1-bigeasy@linutronix.de +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/sched/deadline.c | 3 +-- + kernel/sched/rt.c | 3 +-- + 2 files changed, 2 insertions(+), 4 deletions(-) + +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -1729,12 +1729,11 @@ static void switched_to_dl(struct rq *rq + #ifdef CONFIG_SMP + if (tsk_nr_cpus_allowed(p) > 1 && rq->dl.overloaded) + queue_push_tasks(rq); +-#else ++#endif + if (dl_task(rq->curr)) + check_preempt_curr_dl(rq, p, 0); + else + resched_curr(rq); +-#endif + } + } + +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -2198,10 +2198,9 @@ static void switched_to_rt(struct rq *rq + #ifdef CONFIG_SMP + if (tsk_nr_cpus_allowed(p) > 1 && rq->rt.overloaded) + queue_push_tasks(rq); +-#else ++#endif /* CONFIG_SMP */ + if (p->prio < rq->curr->prio) + resched_curr(rq); +-#endif /* CONFIG_SMP */ + } + } + diff --git a/queue-4.9/series b/queue-4.9/series index 21514e8a2e4..c62286021f4 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -3,7 +3,6 @@ xfrm_user-validate-xfrm_msg_newae-xfrma_replay_esn_val-replay_window.patch xfrm_user-validate-xfrm_msg_newae-incoming-esn-size-harder.patch kvm-nvmx-invvpid-handling-improvements.patch kvm-nvmx-fix-nested-vpid-vmx-exec-control.patch -kvm-x86-cleanup-the-page-tracking-srcu-instance.patch virtio_balloon-init-1st-buffer-in-stats-vq.patch pinctrl-qcom-don-t-clear-status-bit-on-irq_unmask.patch c6x-ptrace-remove-useless-ptrace_setregset-implementation.patch @@ -13,3 +12,6 @@ sparc-ptrace-preserve-previous-registers-for-short-regset-write.patch metag-ptrace-preserve-previous-registers-for-short-regset-write.patch metag-ptrace-provide-default-txstatus-for-short-nt_prstatus.patch metag-ptrace-reject-partial-nt_metag_rpipe-writes.patch +fscrypt-remove-broken-support-for-detecting-keyring-key-revocation.patch +sched-rt-add-a-missing-rescheduling-point.patch +usb-musb-fix-possible-spinlock-deadlock.patch diff --git a/queue-4.9/usb-musb-fix-possible-spinlock-deadlock.patch b/queue-4.9/usb-musb-fix-possible-spinlock-deadlock.patch new file mode 100644 index 00000000000..5b094ed65cf --- /dev/null +++ b/queue-4.9/usb-musb-fix-possible-spinlock-deadlock.patch @@ -0,0 +1,88 @@ +From bc1e2154542071e3cfe1734b143af9b8bdacf8bd Mon Sep 17 00:00:00 2001 +From: Bin Liu +Date: Fri, 10 Mar 2017 14:43:37 -0600 +Subject: usb: musb: fix possible spinlock deadlock + +From: Bin Liu + +commit bc1e2154542071e3cfe1734b143af9b8bdacf8bd upstream. + +The DSPS glue calls del_timer_sync() in its musb_platform_disable() +implementation, which requires the caller to not hold a lock. But +musb_remove() calls musb_platform_disable() will musb->lock held. This +could causes spinlock deadlock. + +So change musb_remove() to call musb_platform_disable() without holds +musb->lock. This doesn't impact the musb_platform_disable implementation +in other glue drivers. + +root@am335x-evm:~# modprobe -r musb-dsps +[ 126.134879] musb-hdrc musb-hdrc.1: remove, state 1 +[ 126.140465] usb usb2: USB disconnect, device number 1 +[ 126.146178] usb 2-1: USB disconnect, device number 2 +[ 126.416985] musb-hdrc musb-hdrc.1: USB bus 2 deregistered +[ 126.423943] +[ 126.425525] ====================================================== +[ 126.431997] [ INFO: possible circular locking dependency detected ] +[ 126.438564] 4.11.0-rc1-00003-g1557f13bca04-dirty #77 Not tainted +[ 126.444852] ------------------------------------------------------- +[ 126.451414] modprobe/778 is trying to acquire lock: +[ 126.456523] (((&glue->timer))){+.-...}, at: [] del_timer_sync+0x0/0xd0 +[ 126.464403] +[ 126.464403] but task is already holding lock: +[ 126.470511] (&(&musb->lock)->rlock){-.-...}, at: [] musb_remove+0x50/0x1 +30 [musb_hdrc] +[ 126.479965] +[ 126.479965] which lock already depends on the new lock. +[ 126.479965] +[ 126.488531] +[ 126.488531] the existing dependency chain (in reverse order) is: +[ 126.496368] +[ 126.496368] -> #1 (&(&musb->lock)->rlock){-.-...}: +[ 126.502968] otg_timer+0x80/0xec [musb_dsps] +[ 126.507990] call_timer_fn+0xb4/0x390 +[ 126.512372] expire_timers+0xf0/0x1fc +[ 126.516754] run_timer_softirq+0x80/0x178 +[ 126.521511] __do_softirq+0xc4/0x554 +[ 126.525802] irq_exit+0xe8/0x158 +[ 126.529735] __handle_domain_irq+0x58/0xb8 +[ 126.534583] __irq_usr+0x54/0x80 +[ 126.538507] +[ 126.538507] -> #0 (((&glue->timer))){+.-...}: +[ 126.544636] del_timer_sync+0x40/0xd0 +[ 126.549066] musb_remove+0x6c/0x130 [musb_hdrc] +[ 126.554370] platform_drv_remove+0x24/0x3c +[ 126.559206] device_release_driver_internal+0x14c/0x1e0 +[ 126.565225] bus_remove_device+0xd8/0x108 +[ 126.569970] device_del+0x1e4/0x308 +[ 126.574170] platform_device_del+0x24/0x8c +[ 126.579006] platform_device_unregister+0xc/0x20 +[ 126.584394] dsps_remove+0x14/0x30 [musb_dsps] +[ 126.589595] platform_drv_remove+0x24/0x3c +[ 126.594432] device_release_driver_internal+0x14c/0x1e0 +[ 126.600450] driver_detach+0x38/0x6c +[ 126.604740] bus_remove_driver+0x4c/0xa0 +[ 126.609407] SyS_delete_module+0x11c/0x1e4 +[ 126.614252] __sys_trace_return+0x0/0x10 + +Fixes: ea2f35c01d5ea ("usb: musb: Fix sleeping function called from invalid context for hdrc glue") +Acked-by: Tony Lindgren +Signed-off-by: Bin Liu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/musb/musb_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/musb/musb_core.c ++++ b/drivers/usb/musb/musb_core.c +@@ -2467,8 +2467,8 @@ static int musb_remove(struct platform_d + pm_runtime_get_sync(musb->controller); + musb_host_cleanup(musb); + musb_gadget_cleanup(musb); +- spin_lock_irqsave(&musb->lock, flags); + musb_platform_disable(musb); ++ spin_lock_irqsave(&musb->lock, flags); + musb_generic_disable(musb); + spin_unlock_irqrestore(&musb->lock, flags); + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); -- 2.47.3