From: Greg Kroah-Hartman Date: Mon, 1 Jul 2013 18:09:57 +0000 (-0700) Subject: 3.9-stable patches X-Git-Tag: v3.9.9~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ce36c9e7760dd822657669c8cbda5293e4b2e355;p=thirdparty%2Fkernel%2Fstable-queue.git 3.9-stable patches added patches: crypto-algboss-hold-ref-count-on-larval.patch perf-disable-monitoring-on-setuid-processes-for-regular-users.patch powerpc-eeh-fix-fetching-bus-for-single-dev-pe.patch ubifs-fix-a-horrid-bug.patch ubifs-prepare-to-fix-a-horrid-bug.patch --- diff --git a/queue-3.9/crypto-algboss-hold-ref-count-on-larval.patch b/queue-3.9/crypto-algboss-hold-ref-count-on-larval.patch new file mode 100644 index 00000000000..c6a6f9d8c82 --- /dev/null +++ b/queue-3.9/crypto-algboss-hold-ref-count-on-larval.patch @@ -0,0 +1,174 @@ +From 939e17799619e31331d2433041196529515a86a6 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Tue, 25 Jun 2013 19:15:17 +0800 +Subject: crypto: algboss - Hold ref count on larval + +From: Herbert Xu + +commit 939e17799619e31331d2433041196529515a86a6 upstream. + +On Thu, Jun 20, 2013 at 10:00:21AM +0200, Daniel Borkmann wrote: +> After having fixed a NULL pointer dereference in SCTP 1abd165e ("net: +> sctp: fix NULL pointer dereference in socket destruction"), I ran into +> the following NULL pointer dereference in the crypto subsystem with +> the same reproducer, easily hit each time: +> +> BUG: unable to handle kernel NULL pointer dereference at (null) +> IP: [] __wake_up_common+0x31/0x90 +> PGD 0 +> Oops: 0000 [#1] SMP +> Modules linked in: padlock_sha(F-) sha256_generic(F) sctp(F) libcrc32c(F) [..] +> CPU: 6 PID: 3326 Comm: cryptomgr_probe Tainted: GF 3.10.0-rc5+ #1 +> Hardware name: Dell Inc. PowerEdge T410/0H19HD, BIOS 1.6.3 02/01/2011 +> task: ffff88007b6cf4e0 ti: ffff88007b7cc000 task.ti: ffff88007b7cc000 +> RIP: 0010:[] [] __wake_up_common+0x31/0x90 +> RSP: 0018:ffff88007b7cde08 EFLAGS: 00010082 +> RAX: ffffffffffffffe8 RBX: ffff88003756c130 RCX: 0000000000000000 +> RDX: 0000000000000000 RSI: 0000000000000003 RDI: ffff88003756c130 +> RBP: ffff88007b7cde48 R08: 0000000000000000 R09: ffff88012b173200 +> R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000282 +> R13: ffff88003756c138 R14: 0000000000000000 R15: 0000000000000000 +> FS: 0000000000000000(0000) GS:ffff88012fc60000(0000) knlGS:0000000000000000 +> CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b +> CR2: 0000000000000000 CR3: 0000000001a0b000 CR4: 00000000000007e0 +> DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +> DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 +> Stack: +> ffff88007b7cde28 0000000300000000 ffff88007b7cde28 ffff88003756c130 +> 0000000000000282 ffff88003756c128 ffffffff81227670 0000000000000000 +> ffff88007b7cde78 ffffffff810722b7 ffff88007cdcf000 ffffffff81a90540 +> Call Trace: +> [] ? crypto_alloc_pcomp+0x20/0x20 +> [] complete_all+0x47/0x60 +> [] cryptomgr_probe+0x98/0xc0 +> [] ? crypto_alloc_pcomp+0x20/0x20 +> [] kthread+0xce/0xe0 +> [] ? kthread_freezable_should_stop+0x70/0x70 +> [] ret_from_fork+0x7c/0xb0 +> [] ? kthread_freezable_should_stop+0x70/0x70 +> Code: 41 56 41 55 41 54 53 48 83 ec 18 66 66 66 66 90 89 75 cc 89 55 c8 +> 4c 8d 6f 08 48 8b 57 08 41 89 cf 4d 89 c6 48 8d 42 e +> RIP [] __wake_up_common+0x31/0x90 +> RSP +> CR2: 0000000000000000 +> ---[ end trace b495b19270a4d37e ]--- +> +> My assumption is that the following is happening: the minimal SCTP +> tool runs under ``echo 1 > /proc/sys/net/sctp/auth_enable'', hence +> it's making use of crypto_alloc_hash() via sctp_auth_init_hmacs(). +> It forks itself, heavily allocates, binds, listens and waits in +> accept on sctp sockets, and then randomly kills some of them (no +> need for an actual client in this case to hit this). Then, again, +> allocating, binding, etc, and then killing child processes. +> +> The problem that might be happening here is that cryptomgr requests +> the module to probe/load through cryptomgr_schedule_probe(), but +> before the thread handler cryptomgr_probe() returns, we return from +> the wait_for_completion_interruptible() function and probably already +> have cleared up larval, thus we run into a NULL pointer dereference +> when in cryptomgr_probe() complete_all() is being called. +> +> If we wait with wait_for_completion() instead, this panic will not +> occur anymore. This is valid, because in case a signal is pending, +> cryptomgr_probe() returns from probing anyway with properly calling +> complete_all(). + +The use of wait_for_completion_interruptible is intentional so that +we don't lock up the thread if a bug causes us to never wake up. + +This bug is caused by the helper thread using the larval without +holding a reference count on it. If the helper thread completes +after the original thread requesting for help has gone away and +destroyed the larval, then we get the crash above. + +So the fix is to hold a reference count on the larval. + +Reported-by: Daniel Borkmann +Tested-by: Daniel Borkmann +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/algboss.c | 15 ++++++++------- + crypto/api.c | 6 ------ + crypto/internal.h | 6 ++++++ + 3 files changed, 14 insertions(+), 13 deletions(-) + +--- a/crypto/algboss.c ++++ b/crypto/algboss.c +@@ -45,10 +45,9 @@ struct cryptomgr_param { + } nu32; + } attrs[CRYPTO_MAX_ATTRS]; + +- char larval[CRYPTO_MAX_ALG_NAME]; + char template[CRYPTO_MAX_ALG_NAME]; + +- struct completion *completion; ++ struct crypto_larval *larval; + + u32 otype; + u32 omask; +@@ -87,7 +86,8 @@ static int cryptomgr_probe(void *data) + crypto_tmpl_put(tmpl); + + out: +- complete_all(param->completion); ++ complete_all(¶m->larval->completion); ++ crypto_alg_put(¶m->larval->alg); + kfree(param); + module_put_and_exit(0); + } +@@ -187,18 +187,19 @@ static int cryptomgr_schedule_probe(stru + param->otype = larval->alg.cra_flags; + param->omask = larval->mask; + +- memcpy(param->larval, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME); +- +- param->completion = &larval->completion; ++ crypto_alg_get(&larval->alg); ++ param->larval = larval; + + thread = kthread_run(cryptomgr_probe, param, "cryptomgr_probe"); + if (IS_ERR(thread)) +- goto err_free_param; ++ goto err_put_larval; + + wait_for_completion_interruptible(&larval->completion); + + return NOTIFY_STOP; + ++err_put_larval: ++ crypto_alg_put(&larval->alg); + err_free_param: + kfree(param); + err_put_module: +--- a/crypto/api.c ++++ b/crypto/api.c +@@ -34,12 +34,6 @@ EXPORT_SYMBOL_GPL(crypto_alg_sem); + BLOCKING_NOTIFIER_HEAD(crypto_chain); + EXPORT_SYMBOL_GPL(crypto_chain); + +-static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) +-{ +- atomic_inc(&alg->cra_refcnt); +- return alg; +-} +- + struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) + { + return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL; +--- a/crypto/internal.h ++++ b/crypto/internal.h +@@ -103,6 +103,12 @@ int crypto_register_notifier(struct noti + int crypto_unregister_notifier(struct notifier_block *nb); + int crypto_probing_notify(unsigned long val, void *v); + ++static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) ++{ ++ atomic_inc(&alg->cra_refcnt); ++ return alg; ++} ++ + static inline void crypto_alg_put(struct crypto_alg *alg) + { + if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy) diff --git a/queue-3.9/perf-disable-monitoring-on-setuid-processes-for-regular-users.patch b/queue-3.9/perf-disable-monitoring-on-setuid-processes-for-regular-users.patch new file mode 100644 index 00000000000..b236aec9b09 --- /dev/null +++ b/queue-3.9/perf-disable-monitoring-on-setuid-processes-for-regular-users.patch @@ -0,0 +1,61 @@ +From 2976b10f05bd7f6dab9f9e7524451ddfed656a89 Mon Sep 17 00:00:00 2001 +From: Stephane Eranian +Date: Thu, 20 Jun 2013 11:36:28 +0200 +Subject: perf: Disable monitoring on setuid processes for regular users + +From: Stephane Eranian + +commit 2976b10f05bd7f6dab9f9e7524451ddfed656a89 upstream. + +There was a a bug in setup_new_exec(), whereby +the test to disabled perf monitoring was not +correct because the new credentials for the +process were not yet committed and therefore +the get_dumpable() test was never firing. + +The patch fixes the problem by moving the +perf_event test until after the credentials +are committed. + +Signed-off-by: Stephane Eranian +Tested-by: Jiri Olsa +Acked-by: Peter Zijlstra +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + fs/exec.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1136,13 +1136,6 @@ void setup_new_exec(struct linux_binprm + set_dumpable(current->mm, suid_dumpable); + } + +- /* +- * Flush performance counters when crossing a +- * security domain: +- */ +- if (!get_dumpable(current->mm)) +- perf_event_exit_task(current); +- + /* An exec changes our domain. We are no longer part of the thread + group */ + +@@ -1206,6 +1199,15 @@ void install_exec_creds(struct linux_bin + + commit_creds(bprm->cred); + bprm->cred = NULL; ++ ++ /* ++ * Disable monitoring for regular users ++ * when executing setuid binaries. Must ++ * wait until new credentials are committed ++ * by commit_creds() above ++ */ ++ if (get_dumpable(current->mm) != SUID_DUMP_USER) ++ perf_event_exit_task(current); + /* + * cred_guard_mutex must be held at least to this point to prevent + * ptrace_attach() from altering our determination of the task's diff --git a/queue-3.9/powerpc-eeh-fix-fetching-bus-for-single-dev-pe.patch b/queue-3.9/powerpc-eeh-fix-fetching-bus-for-single-dev-pe.patch new file mode 100644 index 00000000000..902854c00c9 --- /dev/null +++ b/queue-3.9/powerpc-eeh-fix-fetching-bus-for-single-dev-pe.patch @@ -0,0 +1,35 @@ +From ea461abf61753b4b79e625a7c20650105b990f21 Mon Sep 17 00:00:00 2001 +From: Gavin Shan +Date: Wed, 5 Jun 2013 15:34:02 +0800 +Subject: powerpc/eeh: Fix fetching bus for single-dev-PE + +From: Gavin Shan + +commit ea461abf61753b4b79e625a7c20650105b990f21 upstream. + +While running Linux as guest on top of phyp, we possiblly have +PE that includes single PCI device. However, we didn't return +its PCI bus correctly and it leads to failure on recovery from +EEH errors for single-dev-PE. The patch fixes the issue. + +Signed-off-by: Gavin Shan +Cc: Steve Best +Signed-off-by: Benjamin Herrenschmidt +Signed-off-by: Greg Kroah-Hartman + +--- + arch/powerpc/platforms/pseries/eeh_pe.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/powerpc/platforms/pseries/eeh_pe.c ++++ b/arch/powerpc/platforms/pseries/eeh_pe.c +@@ -639,7 +639,8 @@ struct pci_bus *eeh_pe_bus_get(struct ee + + if (pe->type & EEH_PE_PHB) { + bus = pe->phb->bus; +- } else if (pe->type & EEH_PE_BUS) { ++ } else if (pe->type & EEH_PE_BUS || ++ pe->type & EEH_PE_DEVICE) { + edev = list_first_entry(&pe->edevs, struct eeh_dev, list); + pdev = eeh_dev_to_pci_dev(edev); + if (pdev) diff --git a/queue-3.9/series b/queue-3.9/series index 7d1af6ca48d..30152e007d7 100644 --- a/queue-3.9/series +++ b/queue-3.9/series @@ -15,3 +15,8 @@ dlci-validate-the-net-device-in-dlci_del.patch net-tg3-avoid-delay-during-mmio-access.patch rt2800-fix-rt5390-rt3290-tx-power-settings-regression.patch iommu-vt-d-add-quirk-for-broken-interrupt-remapping-on-55xx-chipsets.patch +perf-disable-monitoring-on-setuid-processes-for-regular-users.patch +crypto-algboss-hold-ref-count-on-larval.patch +powerpc-eeh-fix-fetching-bus-for-single-dev-pe.patch +ubifs-prepare-to-fix-a-horrid-bug.patch +ubifs-fix-a-horrid-bug.patch diff --git a/queue-3.9/ubifs-fix-a-horrid-bug.patch b/queue-3.9/ubifs-fix-a-horrid-bug.patch new file mode 100644 index 00000000000..ab152383df0 --- /dev/null +++ b/queue-3.9/ubifs-fix-a-horrid-bug.patch @@ -0,0 +1,96 @@ +From 605c912bb843c024b1ed173dc427cd5c08e5d54d Mon Sep 17 00:00:00 2001 +From: Artem Bityutskiy +Date: Fri, 28 Jun 2013 14:15:15 +0300 +Subject: UBIFS: fix a horrid bug + +From: Artem Bityutskiy + +commit 605c912bb843c024b1ed173dc427cd5c08e5d54d upstream. + +Al Viro pointed me to the fact that '->readdir()' and '->llseek()' have no +mutual exclusion, which means the 'ubifs_dir_llseek()' can be run while we are +in the middle of 'ubifs_readdir()'. + +This means that 'file->private_data' can be freed while 'ubifs_readdir()' uses +it, and this is a very bad bug: not only 'ubifs_readdir()' can return garbage, +but this may corrupt memory and lead to all kinds of problems like crashes an +security holes. + +This patch fixes the problem by using the 'file->f_version' field, which +'->llseek()' always unconditionally sets to zero. We set it to 1 in +'ubifs_readdir()' and whenever we detect that it became 0, we know there was a +seek and it is time to clear the state saved in 'file->private_data'. + +I tested this patch by writing a user-space program which runds readdir and +seek in parallell. I could easily crash the kernel without these patches, but +could not crash it with these patches. + +Reported-by: Al Viro +Tested-by: Artem Bityutskiy +Signed-off-by: Artem Bityutskiy +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ubifs/dir.c | 30 +++++++++++++++++++++++++++--- + 1 file changed, 27 insertions(+), 3 deletions(-) + +--- a/fs/ubifs/dir.c ++++ b/fs/ubifs/dir.c +@@ -365,6 +365,24 @@ static int ubifs_readdir(struct file *fi + */ + return 0; + ++ if (file->f_version == 0) { ++ /* ++ * The file was seek'ed, which means that @file->private_data ++ * is now invalid. This may also be just the first ++ * 'ubifs_readdir()' invocation, in which case ++ * @file->private_data is NULL, and the below code is ++ * basically a no-op. ++ */ ++ kfree(file->private_data); ++ file->private_data = NULL; ++ } ++ ++ /* ++ * 'generic_file_llseek()' unconditionally sets @file->f_version to ++ * zero, and we use this for detecting whether the file was seek'ed. ++ */ ++ file->f_version = 1; ++ + /* File positions 0 and 1 correspond to "." and ".." */ + if (pos == 0) { + ubifs_assert(!file->private_data); +@@ -438,6 +456,14 @@ static int ubifs_readdir(struct file *fi + file->f_pos = pos = key_hash_flash(c, &dent->key); + file->private_data = dent; + cond_resched(); ++ ++ if (file->f_version == 0) ++ /* ++ * The file was seek'ed meanwhile, lets return and start ++ * reading direntries from the new position on the next ++ * invocation. ++ */ ++ return 0; + } + + out: +@@ -448,15 +474,13 @@ out: + + kfree(file->private_data); + file->private_data = NULL; ++ /* 2 is a special value indicating that there are no more direntries */ + file->f_pos = 2; + return 0; + } + +-/* If a directory is seeked, we have to free saved readdir() state */ + static loff_t ubifs_dir_llseek(struct file *file, loff_t offset, int whence) + { +- kfree(file->private_data); +- file->private_data = NULL; + return generic_file_llseek(file, offset, whence); + } + diff --git a/queue-3.9/ubifs-prepare-to-fix-a-horrid-bug.patch b/queue-3.9/ubifs-prepare-to-fix-a-horrid-bug.patch new file mode 100644 index 00000000000..160969a6b06 --- /dev/null +++ b/queue-3.9/ubifs-prepare-to-fix-a-horrid-bug.patch @@ -0,0 +1,125 @@ +From 33f1a63ae84dfd9ad298cf275b8f1887043ced36 Mon Sep 17 00:00:00 2001 +From: Artem Bityutskiy +Date: Fri, 28 Jun 2013 14:15:14 +0300 +Subject: UBIFS: prepare to fix a horrid bug + +From: Artem Bityutskiy + +commit 33f1a63ae84dfd9ad298cf275b8f1887043ced36 upstream. + +Al Viro pointed me to the fact that '->readdir()' and '->llseek()' have no +mutual exclusion, which means the 'ubifs_dir_llseek()' can be run while we are +in the middle of 'ubifs_readdir()'. + +First of all, this means that 'file->private_data' can be freed while +'ubifs_readdir()' uses it. But this particular patch does not fix the problem. +This patch is only a preparation, and the fix will follow next. + +In this patch we make 'ubifs_readdir()' stop using 'file->f_pos' directly, +because 'file->f_pos' can be changed by '->llseek()' at any point. This may +lead 'ubifs_readdir()' to returning inconsistent data: directory entry names +may correspond to incorrect file positions. + +So here we introduce a local variable 'pos', read 'file->f_pose' once at very +the beginning, and then stick to 'pos'. The result of this is that when +'ubifs_dir_llseek()' changes 'file->f_pos' while we are in the middle of +'ubifs_readdir()', the latter "wins". + +Reported-by: Al Viro +Tested-by: Artem Bityutskiy +Signed-off-by: Artem Bityutskiy +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ubifs/dir.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +--- a/fs/ubifs/dir.c ++++ b/fs/ubifs/dir.c +@@ -349,15 +349,16 @@ static unsigned int vfs_dent_type(uint8_ + static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir) + { + int err, over = 0; ++ loff_t pos = file->f_pos; + struct qstr nm; + union ubifs_key key; + struct ubifs_dent_node *dent; + struct inode *dir = file_inode(file); + struct ubifs_info *c = dir->i_sb->s_fs_info; + +- dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos); ++ dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, pos); + +- if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2) ++ if (pos > UBIFS_S_KEY_HASH_MASK || pos == 2) + /* + * The directory was seek'ed to a senseless position or there + * are no more entries. +@@ -365,15 +366,15 @@ static int ubifs_readdir(struct file *fi + return 0; + + /* File positions 0 and 1 correspond to "." and ".." */ +- if (file->f_pos == 0) { ++ if (pos == 0) { + ubifs_assert(!file->private_data); + over = filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR); + if (over) + return 0; +- file->f_pos = 1; ++ file->f_pos = pos = 1; + } + +- if (file->f_pos == 1) { ++ if (pos == 1) { + ubifs_assert(!file->private_data); + over = filldir(dirent, "..", 2, 1, + parent_ino(file->f_path.dentry), DT_DIR); +@@ -389,7 +390,7 @@ static int ubifs_readdir(struct file *fi + goto out; + } + +- file->f_pos = key_hash_flash(c, &dent->key); ++ file->f_pos = pos = key_hash_flash(c, &dent->key); + file->private_data = dent; + } + +@@ -397,17 +398,16 @@ static int ubifs_readdir(struct file *fi + if (!dent) { + /* + * The directory was seek'ed to and is now readdir'ed. +- * Find the entry corresponding to @file->f_pos or the +- * closest one. ++ * Find the entry corresponding to @pos or the closest one. + */ +- dent_key_init_hash(c, &key, dir->i_ino, file->f_pos); ++ dent_key_init_hash(c, &key, dir->i_ino, pos); + nm.name = NULL; + dent = ubifs_tnc_next_ent(c, &key, &nm); + if (IS_ERR(dent)) { + err = PTR_ERR(dent); + goto out; + } +- file->f_pos = key_hash_flash(c, &dent->key); ++ file->f_pos = pos = key_hash_flash(c, &dent->key); + file->private_data = dent; + } + +@@ -419,7 +419,7 @@ static int ubifs_readdir(struct file *fi + ubifs_inode(dir)->creat_sqnum); + + nm.len = le16_to_cpu(dent->nlen); +- over = filldir(dirent, dent->name, nm.len, file->f_pos, ++ over = filldir(dirent, dent->name, nm.len, pos, + le64_to_cpu(dent->inum), + vfs_dent_type(dent->type)); + if (over) +@@ -435,7 +435,7 @@ static int ubifs_readdir(struct file *fi + } + + kfree(file->private_data); +- file->f_pos = key_hash_flash(c, &dent->key); ++ file->f_pos = pos = key_hash_flash(c, &dent->key); + file->private_data = dent; + cond_resched(); + }