From: Greg Kroah-Hartman Date: Mon, 15 Sep 2014 19:19:00 +0000 (-0700) Subject: 3.16-stable patches X-Git-Tag: v3.10.55~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=75f1c465d87b59821c2b3cc943444623440e1e0e;p=thirdparty%2Fkernel%2Fstable-queue.git 3.16-stable patches added patches: cifs-fix-smb2-readdir-error-handling.patch keys-fix-termination-condition-in-assoc-array-garbage-collection.patch keys-fix-use-after-free-in-assoc_array_gc.patch --- diff --git a/queue-3.16/cifs-fix-smb2-readdir-error-handling.patch b/queue-3.16/cifs-fix-smb2-readdir-error-handling.patch new file mode 100644 index 00000000000..494d15421df --- /dev/null +++ b/queue-3.16/cifs-fix-smb2-readdir-error-handling.patch @@ -0,0 +1,165 @@ +From 52755808d4525f4d5b86d112d36ffc7a46f3fb48 Mon Sep 17 00:00:00 2001 +From: Pavel Shilovsky +Date: Mon, 18 Aug 2014 20:49:57 +0400 +Subject: CIFS: Fix SMB2 readdir error handling + +From: Pavel Shilovsky + +commit 52755808d4525f4d5b86d112d36ffc7a46f3fb48 upstream. + +SMB2 servers indicates the end of a directory search with +STATUS_NO_MORE_FILE error code that is not processed now. +This causes generic/257 xfstest to fail. Fix this by triggering +the end of search by this error code in SMB2_query_directory. + +Also when negotiating CIFS protocol we tell the server to close +the search automatically at the end and there is no need to do +it itself. In the case of SMB2 protocol, we need to close it +explicitly - separate close directory checks for different +protocols. + +Signed-off-by: Pavel Shilovsky +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cifs/cifsglob.h | 2 ++ + fs/cifs/file.c | 2 +- + fs/cifs/readdir.c | 2 +- + fs/cifs/smb1ops.c | 7 +++++++ + fs/cifs/smb2maperror.c | 2 +- + fs/cifs/smb2ops.c | 9 +++++++++ + fs/cifs/smb2pdu.c | 9 ++++----- + 7 files changed, 25 insertions(+), 8 deletions(-) + +--- a/fs/cifs/cifsglob.h ++++ b/fs/cifs/cifsglob.h +@@ -399,6 +399,8 @@ struct smb_version_operations { + const struct cifs_fid *, u32 *); + int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *, + int); ++ /* check if we need to issue closedir */ ++ bool (*dir_needs_close)(struct cifsFileInfo *); + }; + + struct smb_version_values { +--- a/fs/cifs/file.c ++++ b/fs/cifs/file.c +@@ -762,7 +762,7 @@ int cifs_closedir(struct inode *inode, s + + cifs_dbg(FYI, "Freeing private data in close dir\n"); + spin_lock(&cifs_file_list_lock); +- if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { ++ if (server->ops->dir_needs_close(cfile)) { + cfile->invalidHandle = true; + spin_unlock(&cifs_file_list_lock); + if (server->ops->close_dir) +--- a/fs/cifs/readdir.c ++++ b/fs/cifs/readdir.c +@@ -593,7 +593,7 @@ find_cifs_entry(const unsigned int xid, + /* close and restart search */ + cifs_dbg(FYI, "search backing up - close and restart search\n"); + spin_lock(&cifs_file_list_lock); +- if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { ++ if (server->ops->dir_needs_close(cfile)) { + cfile->invalidHandle = true; + spin_unlock(&cifs_file_list_lock); + if (server->ops->close_dir) +--- a/fs/cifs/smb1ops.c ++++ b/fs/cifs/smb1ops.c +@@ -1009,6 +1009,12 @@ cifs_is_read_op(__u32 oplock) + return oplock == OPLOCK_READ; + } + ++static bool ++cifs_dir_needs_close(struct cifsFileInfo *cfile) ++{ ++ return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle; ++} ++ + struct smb_version_operations smb1_operations = { + .send_cancel = send_nt_cancel, + .compare_fids = cifs_compare_fids, +@@ -1078,6 +1084,7 @@ struct smb_version_operations smb1_opera + .query_mf_symlink = cifs_query_mf_symlink, + .create_mf_symlink = cifs_create_mf_symlink, + .is_read_op = cifs_is_read_op, ++ .dir_needs_close = cifs_dir_needs_close, + #ifdef CONFIG_CIFS_XATTR + .query_all_EAs = CIFSSMBQAllEAs, + .set_EA = CIFSSMBSetEA, +--- a/fs/cifs/smb2maperror.c ++++ b/fs/cifs/smb2maperror.c +@@ -214,7 +214,7 @@ static const struct status_to_posix_erro + {STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"}, + {STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"}, + {STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"}, +- {STATUS_NO_MORE_FILES, -EIO, "STATUS_NO_MORE_FILES"}, ++ {STATUS_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"}, + {STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"}, + {STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"}, + {STATUS_NO_INHERITANCE, -EIO, "STATUS_NO_INHERITANCE"}, +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -1104,6 +1104,12 @@ smb3_parse_lease_buf(void *buf, unsigned + return le32_to_cpu(lc->lcontext.LeaseState); + } + ++static bool ++smb2_dir_needs_close(struct cifsFileInfo *cfile) ++{ ++ return !cfile->invalidHandle; ++} ++ + struct smb_version_operations smb20_operations = { + .compare_fids = smb2_compare_fids, + .setup_request = smb2_setup_request, +@@ -1177,6 +1183,7 @@ struct smb_version_operations smb20_oper + .create_lease_buf = smb2_create_lease_buf, + .parse_lease_buf = smb2_parse_lease_buf, + .clone_range = smb2_clone_range, ++ .dir_needs_close = smb2_dir_needs_close, + }; + + struct smb_version_operations smb21_operations = { +@@ -1252,6 +1259,7 @@ struct smb_version_operations smb21_oper + .create_lease_buf = smb2_create_lease_buf, + .parse_lease_buf = smb2_parse_lease_buf, + .clone_range = smb2_clone_range, ++ .dir_needs_close = smb2_dir_needs_close, + }; + + struct smb_version_operations smb30_operations = { +@@ -1330,6 +1338,7 @@ struct smb_version_operations smb30_oper + .parse_lease_buf = smb3_parse_lease_buf, + .clone_range = smb2_clone_range, + .validate_negotiate = smb3_validate_negotiate, ++ .dir_needs_close = smb2_dir_needs_close, + }; + + struct smb_version_values smb20_values = { +--- a/fs/cifs/smb2pdu.c ++++ b/fs/cifs/smb2pdu.c +@@ -2142,6 +2142,10 @@ SMB2_query_directory(const unsigned int + rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base; + + if (rc) { ++ if (rc == -ENODATA && rsp->hdr.Status == STATUS_NO_MORE_FILES) { ++ srch_inf->endOfSearch = true; ++ rc = 0; ++ } + cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); + goto qdir_exit; + } +@@ -2179,11 +2183,6 @@ SMB2_query_directory(const unsigned int + else + cifs_dbg(VFS, "illegal search buffer type\n"); + +- if (rsp->hdr.Status == STATUS_NO_MORE_FILES) +- srch_inf->endOfSearch = 1; +- else +- srch_inf->endOfSearch = 0; +- + return rc; + + qdir_exit: diff --git a/queue-3.16/keys-fix-termination-condition-in-assoc-array-garbage-collection.patch b/queue-3.16/keys-fix-termination-condition-in-assoc-array-garbage-collection.patch new file mode 100644 index 00000000000..7eff8b6e79e --- /dev/null +++ b/queue-3.16/keys-fix-termination-condition-in-assoc-array-garbage-collection.patch @@ -0,0 +1,108 @@ +From 95389b08d93d5c06ec63ab49bd732b0069b7c35e Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Wed, 10 Sep 2014 22:22:00 +0100 +Subject: KEYS: Fix termination condition in assoc array garbage collection + +From: David Howells + +commit 95389b08d93d5c06ec63ab49bd732b0069b7c35e upstream. + +This fixes CVE-2014-3631. + +It is possible for an associative array to end up with a shortcut node at the +root of the tree if there are more than fan-out leaves in the tree, but they +all crowd into the same slot in the lowest level (ie. they all have the same +first nibble of their index keys). + +When assoc_array_gc() returns back up the tree after scanning some leaves, it +can fall off of the root and crash because it assumes that the back pointer +from a shortcut (after label ascend_old_tree) must point to a normal node - +which isn't true of a shortcut node at the root. + +Should we find we're ascending rootwards over a shortcut, we should check to +see if the backpointer is zero - and if it is, we have completed the scan. + +This particular bug cannot occur if the root node is not a shortcut - ie. if +you have fewer than 17 keys in a keyring or if you have at least two keys that +sit into separate slots (eg. a keyring and a non keyring). + +This can be reproduced by: + + ring=`keyctl newring bar @s` + for ((i=1; i<=18; i++)); do last_key=`keyctl newring foo$i $ring`; done + keyctl timeout $last_key 2 + +Doing this: + + echo 3 >/proc/sys/kernel/keys/gc_delay + +first will speed things up. + +If we do fall off of the top of the tree, we get the following oops: + +BUG: unable to handle kernel NULL pointer dereference at 0000000000000018 +IP: [] assoc_array_gc+0x2f7/0x540 +PGD dae15067 PUD cfc24067 PMD 0 +Oops: 0000 [#1] SMP +Modules linked in: xt_nat xt_mark nf_conntrack_netbios_ns nf_conntrack_broadcast ip6t_rpfilter ip6t_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_ni +CPU: 0 PID: 26011 Comm: kworker/0:1 Not tainted 3.14.9-200.fc20.x86_64 #1 +Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 +Workqueue: events key_garbage_collector +task: ffff8800918bd580 ti: ffff8800aac14000 task.ti: ffff8800aac14000 +RIP: 0010:[] [] assoc_array_gc+0x2f7/0x540 +RSP: 0018:ffff8800aac15d40 EFLAGS: 00010206 +RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff8800aaecacc0 +RDX: ffff8800daecf440 RSI: 0000000000000001 RDI: ffff8800aadc2bc0 +RBP: ffff8800aac15da8 R08: 0000000000000001 R09: 0000000000000003 +R10: ffffffff8136ccc7 R11: 0000000000000000 R12: 0000000000000000 +R13: 0000000000000000 R14: 0000000000000070 R15: 0000000000000001 +FS: 0000000000000000(0000) GS:ffff88011fc00000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b +CR2: 0000000000000018 CR3: 00000000db10d000 CR4: 00000000000006f0 +Stack: + ffff8800aac15d50 0000000000000011 ffff8800aac15db8 ffffffff812e2a70 + ffff880091a00600 0000000000000000 ffff8800aadc2bc3 00000000cd42c987 + ffff88003702df20 ffff88003702dfa0 0000000053b65c09 ffff8800aac15fd8 +Call Trace: + [] ? keyring_detect_cycle_iterator+0x30/0x30 + [] keyring_gc+0x75/0x80 + [] key_garbage_collector+0x154/0x3c0 + [] process_one_work+0x176/0x430 + [] worker_thread+0x11b/0x3a0 + [] ? rescuer_thread+0x3b0/0x3b0 + [] kthread+0xd8/0xf0 + [] ? insert_kthread_work+0x40/0x40 + [] ret_from_fork+0x7c/0xb0 + [] ? insert_kthread_work+0x40/0x40 +Code: 08 4c 8b 22 0f 84 bf 00 00 00 41 83 c7 01 49 83 e4 fc 41 83 ff 0f 4c 89 65 c0 0f 8f 5a fe ff ff 48 8b 45 c0 4d 63 cf 49 83 c1 02 <4e> 8b 34 c8 4d 85 f6 0f 84 be 00 00 00 41 f6 c6 01 0f 84 92 +RIP [] assoc_array_gc+0x2f7/0x540 + RSP +CR2: 0000000000000018 +---[ end trace 1129028a088c0cbd ]--- + +Signed-off-by: David Howells +Acked-by: Don Zickus +Signed-off-by: James Morris +Signed-off-by: Greg Kroah-Hartman + +--- + lib/assoc_array.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/lib/assoc_array.c ++++ b/lib/assoc_array.c +@@ -1723,11 +1723,13 @@ ascend_old_tree: + shortcut = assoc_array_ptr_to_shortcut(ptr); + slot = shortcut->parent_slot; + cursor = shortcut->back_pointer; ++ if (!cursor) ++ goto gc_complete; + } else { + slot = node->parent_slot; + cursor = ptr; + } +- BUG_ON(!ptr); ++ BUG_ON(!cursor); + node = assoc_array_ptr_to_node(cursor); + slot++; + goto continue_node; diff --git a/queue-3.16/keys-fix-use-after-free-in-assoc_array_gc.patch b/queue-3.16/keys-fix-use-after-free-in-assoc_array_gc.patch new file mode 100644 index 00000000000..4db701b2f56 --- /dev/null +++ b/queue-3.16/keys-fix-use-after-free-in-assoc_array_gc.patch @@ -0,0 +1,38 @@ +From 27419604f51a97d497853f14142c1059d46eb597 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 2 Sep 2014 13:52:20 +0100 +Subject: KEYS: Fix use-after-free in assoc_array_gc() + +From: David Howells + +commit 27419604f51a97d497853f14142c1059d46eb597 upstream. + +An edit script should be considered inaccessible by a function once it has +called assoc_array_apply_edit() or assoc_array_cancel_edit(). + +However, assoc_array_gc() is accessing the edit script just after the +gc_complete: label. + +Reported-by: Andreea-Cristina Bernat +Signed-off-by: David Howells +Reviewed-by: Andreea-Cristina Bernat +cc: shemming@brocade.com +cc: paulmck@linux.vnet.ibm.com +Signed-off-by: James Morris +Signed-off-by: Greg Kroah-Hartman + +--- + lib/assoc_array.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/lib/assoc_array.c ++++ b/lib/assoc_array.c +@@ -1735,7 +1735,7 @@ ascend_old_tree: + gc_complete: + edit->set[0].to = new_root; + assoc_array_apply_edit(edit); +- edit->array->nr_leaves_on_tree = nr_leaves_on_tree; ++ array->nr_leaves_on_tree = nr_leaves_on_tree; + return 0; + + enomem: diff --git a/queue-3.16/series b/queue-3.16/series index 9142039db43..a1a8fc8be2d 100644 --- a/queue-3.16/series +++ b/queue-3.16/series @@ -153,3 +153,6 @@ ib-srp-fix-deadlock-between-host-removal-and-multipathd.patch drm-nouveau-dis-enable-vblank-irqs-during-suspend-resume.patch drm-nouveau-bump-version-from-1.1.1-to-1.1.2.patch vfs-fix-bad-hashing-of-dentries.patch +cifs-fix-smb2-readdir-error-handling.patch +keys-fix-use-after-free-in-assoc_array_gc.patch +keys-fix-termination-condition-in-assoc-array-garbage-collection.patch