From: Greg Kroah-Hartman Date: Mon, 8 Oct 2018 17:54:11 +0000 (+0200) Subject: 3.18-stable patches X-Git-Tag: v4.4.160~16 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ec98735755acf74703457d90065c33771b97d6c5;p=thirdparty%2Fkernel%2Fstable-queue.git 3.18-stable patches added patches: crypto-mxs-dcp-fix-wait-logic-on-chan-threads.patch ocfs2-fix-locking-for-res-tracking-and-dlm-tracking_list.patch proc-restrict-kernel-stack-dumps-to-root.patch smb2-fix-missing-files-in-root-share-directory-listing.patch --- diff --git a/queue-3.18/crypto-mxs-dcp-fix-wait-logic-on-chan-threads.patch b/queue-3.18/crypto-mxs-dcp-fix-wait-logic-on-chan-threads.patch new file mode 100644 index 00000000000..1d9c683f041 --- /dev/null +++ b/queue-3.18/crypto-mxs-dcp-fix-wait-logic-on-chan-threads.patch @@ -0,0 +1,154 @@ +From d80771c08363ad7fbf0f56f5301e7ca65065c582 Mon Sep 17 00:00:00 2001 +From: Leonard Crestez +Date: Fri, 21 Sep 2018 18:03:18 +0300 +Subject: crypto: mxs-dcp - Fix wait logic on chan threads + +From: Leonard Crestez + +commit d80771c08363ad7fbf0f56f5301e7ca65065c582 upstream. + +When compiling with CONFIG_DEBUG_ATOMIC_SLEEP=y the mxs-dcp driver +prints warnings such as: + +WARNING: CPU: 0 PID: 120 at kernel/sched/core.c:7736 __might_sleep+0x98/0x9c +do not call blocking ops when !TASK_RUNNING; state=1 set at [<8081978c>] dcp_chan_thread_sha+0x3c/0x2ec + +The problem is that blocking ops will manipulate current->state +themselves so it is not allowed to call them between +set_current_state(TASK_INTERRUPTIBLE) and schedule(). + +Fix this by converting the per-chan mutex to a spinlock (it only +protects tiny list ops anyway) and rearranging the wait logic so that +callbacks are called current->state as TASK_RUNNING. Those callbacks +will indeed call blocking ops themselves so this is required. + +Cc: +Signed-off-by: Leonard Crestez +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/crypto/mxs-dcp.c | 53 ++++++++++++++++++++++++++--------------------- + 1 file changed, 30 insertions(+), 23 deletions(-) + +--- a/drivers/crypto/mxs-dcp.c ++++ b/drivers/crypto/mxs-dcp.c +@@ -63,7 +63,7 @@ struct dcp { + struct dcp_coherent_block *coh; + + struct completion completion[DCP_MAX_CHANS]; +- struct mutex mutex[DCP_MAX_CHANS]; ++ spinlock_t lock[DCP_MAX_CHANS]; + struct task_struct *thread[DCP_MAX_CHANS]; + struct crypto_queue queue[DCP_MAX_CHANS]; + }; +@@ -349,13 +349,20 @@ static int dcp_chan_thread_aes(void *dat + + int ret; + +- do { +- __set_current_state(TASK_INTERRUPTIBLE); ++ while (!kthread_should_stop()) { ++ set_current_state(TASK_INTERRUPTIBLE); + +- mutex_lock(&sdcp->mutex[chan]); ++ spin_lock(&sdcp->lock[chan]); + backlog = crypto_get_backlog(&sdcp->queue[chan]); + arq = crypto_dequeue_request(&sdcp->queue[chan]); +- mutex_unlock(&sdcp->mutex[chan]); ++ spin_unlock(&sdcp->lock[chan]); ++ ++ if (!backlog && !arq) { ++ schedule(); ++ continue; ++ } ++ ++ set_current_state(TASK_RUNNING); + + if (backlog) + backlog->complete(backlog, -EINPROGRESS); +@@ -363,11 +370,8 @@ static int dcp_chan_thread_aes(void *dat + if (arq) { + ret = mxs_dcp_aes_block_crypt(arq); + arq->complete(arq, ret); +- continue; + } +- +- schedule(); +- } while (!kthread_should_stop()); ++ } + + return 0; + } +@@ -407,9 +411,9 @@ static int mxs_dcp_aes_enqueue(struct ab + rctx->ecb = ecb; + actx->chan = DCP_CHAN_CRYPTO; + +- mutex_lock(&sdcp->mutex[actx->chan]); ++ spin_lock(&sdcp->lock[actx->chan]); + ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base); +- mutex_unlock(&sdcp->mutex[actx->chan]); ++ spin_unlock(&sdcp->lock[actx->chan]); + + wake_up_process(sdcp->thread[actx->chan]); + +@@ -645,13 +649,20 @@ static int dcp_chan_thread_sha(void *dat + struct ahash_request *req; + int ret, fini; + +- do { +- __set_current_state(TASK_INTERRUPTIBLE); ++ while (!kthread_should_stop()) { ++ set_current_state(TASK_INTERRUPTIBLE); + +- mutex_lock(&sdcp->mutex[chan]); ++ spin_lock(&sdcp->lock[chan]); + backlog = crypto_get_backlog(&sdcp->queue[chan]); + arq = crypto_dequeue_request(&sdcp->queue[chan]); +- mutex_unlock(&sdcp->mutex[chan]); ++ spin_unlock(&sdcp->lock[chan]); ++ ++ if (!backlog && !arq) { ++ schedule(); ++ continue; ++ } ++ ++ set_current_state(TASK_RUNNING); + + if (backlog) + backlog->complete(backlog, -EINPROGRESS); +@@ -663,12 +674,8 @@ static int dcp_chan_thread_sha(void *dat + ret = dcp_sha_req_to_buf(arq); + fini = rctx->fini; + arq->complete(arq, ret); +- if (!fini) +- continue; + } +- +- schedule(); +- } while (!kthread_should_stop()); ++ } + + return 0; + } +@@ -726,9 +733,9 @@ static int dcp_sha_update_fx(struct ahas + rctx->init = 1; + } + +- mutex_lock(&sdcp->mutex[actx->chan]); ++ spin_lock(&sdcp->lock[actx->chan]); + ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base); +- mutex_unlock(&sdcp->mutex[actx->chan]); ++ spin_unlock(&sdcp->lock[actx->chan]); + + wake_up_process(sdcp->thread[actx->chan]); + mutex_unlock(&actx->mutex); +@@ -984,7 +991,7 @@ static int mxs_dcp_probe(struct platform + platform_set_drvdata(pdev, sdcp); + + for (i = 0; i < DCP_MAX_CHANS; i++) { +- mutex_init(&sdcp->mutex[i]); ++ spin_lock_init(&sdcp->lock[i]); + init_completion(&sdcp->completion[i]); + crypto_init_queue(&sdcp->queue[i], 50); + } diff --git a/queue-3.18/ocfs2-fix-locking-for-res-tracking-and-dlm-tracking_list.patch b/queue-3.18/ocfs2-fix-locking-for-res-tracking-and-dlm-tracking_list.patch new file mode 100644 index 00000000000..b9568b03578 --- /dev/null +++ b/queue-3.18/ocfs2-fix-locking-for-res-tracking-and-dlm-tracking_list.patch @@ -0,0 +1,47 @@ +From cbe355f57c8074bc4f452e5b6e35509044c6fa23 Mon Sep 17 00:00:00 2001 +From: Ashish Samant +Date: Fri, 5 Oct 2018 15:52:15 -0700 +Subject: ocfs2: fix locking for res->tracking and dlm->tracking_list + +From: Ashish Samant + +commit cbe355f57c8074bc4f452e5b6e35509044c6fa23 upstream. + +In dlm_init_lockres() we access and modify res->tracking and +dlm->tracking_list without holding dlm->track_lock. This can cause list +corruptions and can end up in kernel panic. + +Fix this by locking res->tracking and dlm->tracking_list with +dlm->track_lock instead of dlm->spinlock. + +Link: http://lkml.kernel.org/r/1529951192-4686-1-git-send-email-ashish.samant@oracle.com +Signed-off-by: Ashish Samant +Reviewed-by: Changwei Ge +Acked-by: Joseph Qi +Acked-by: Jun Piao +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ocfs2/dlm/dlmmaster.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/ocfs2/dlm/dlmmaster.c ++++ b/fs/ocfs2/dlm/dlmmaster.c +@@ -599,9 +599,9 @@ static void dlm_init_lockres(struct dlm_ + + res->last_used = 0; + +- spin_lock(&dlm->spinlock); ++ spin_lock(&dlm->track_lock); + list_add_tail(&res->tracking, &dlm->tracking_list); +- spin_unlock(&dlm->spinlock); ++ spin_unlock(&dlm->track_lock); + + memset(res->lvb, 0, DLM_LVB_LEN); + memset(res->refmap, 0, sizeof(res->refmap)); diff --git a/queue-3.18/proc-restrict-kernel-stack-dumps-to-root.patch b/queue-3.18/proc-restrict-kernel-stack-dumps-to-root.patch new file mode 100644 index 00000000000..b04455da97f --- /dev/null +++ b/queue-3.18/proc-restrict-kernel-stack-dumps-to-root.patch @@ -0,0 +1,73 @@ +From f8a00cef17206ecd1b30d3d9f99e10d9fa707aa7 Mon Sep 17 00:00:00 2001 +From: Jann Horn +Date: Fri, 5 Oct 2018 15:51:58 -0700 +Subject: proc: restrict kernel stack dumps to root + +From: Jann Horn + +commit f8a00cef17206ecd1b30d3d9f99e10d9fa707aa7 upstream. + +Currently, you can use /proc/self/task/*/stack to cause a stack walk on +a task you control while it is running on another CPU. That means that +the stack can change under the stack walker. The stack walker does +have guards against going completely off the rails and into random +kernel memory, but it can interpret random data from your kernel stack +as instruction pointers and stack pointers. This can cause exposure of +kernel stack contents to userspace. + +Restrict the ability to inspect kernel stacks of arbitrary tasks to root +in order to prevent a local attacker from exploiting racy stack unwinding +to leak kernel task stack contents. See the added comment for a longer +rationale. + +There don't seem to be any users of this userspace API that can't +gracefully bail out if reading from the file fails. Therefore, I believe +that this change is unlikely to break things. In the case that this patch +does end up needing a revert, the next-best solution might be to fake a +single-entry stack based on wchan. + +Link: http://lkml.kernel.org/r/20180927153316.200286-1-jannh@google.com +Fixes: 2ec220e27f50 ("proc: add /proc/*/stack") +Signed-off-by: Jann Horn +Acked-by: Kees Cook +Cc: Alexey Dobriyan +Cc: Ken Chen +Cc: Will Deacon +Cc: Laura Abbott +Cc: Andy Lutomirski +Cc: Catalin Marinas +Cc: Josh Poimboeuf +Cc: Thomas Gleixner +Cc: Ingo Molnar +Cc: "H . Peter Anvin" +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman + +--- + fs/proc/base.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -279,6 +279,20 @@ static int proc_pid_stack(struct seq_fil + int err; + int i; + ++ /* ++ * The ability to racily run the kernel stack unwinder on a running task ++ * and then observe the unwinder output is scary; while it is useful for ++ * debugging kernel issues, it can also allow an attacker to leak kernel ++ * stack contents. ++ * Doing this in a manner that is at least safe from races would require ++ * some work to ensure that the remote task can not be scheduled; and ++ * even then, this would still expose the unwinder as local attack ++ * surface. ++ * Therefore, this interface is restricted to root. ++ */ ++ if (!file_ns_capable(m->file, &init_user_ns, CAP_SYS_ADMIN)) ++ return -EACCES; ++ + entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL); + if (!entries) + return -ENOMEM; diff --git a/queue-3.18/series b/queue-3.18/series index a80e4483e21..6681bcc7bcb 100644 --- a/queue-3.18/series +++ b/queue-3.18/series @@ -94,3 +94,7 @@ s390-qeth-don-t-dump-past-end-of-unknown-hw-header.patch cifs-read-overflow-in-is_valid_oplock_break.patch xen-manage-don-t-complain-about-an-empty-value-in-control-sysrq-node.patch xen-fix-gcc-warning-and-remove-duplicate-evtchn_row-evtchn_col-usage.patch +smb2-fix-missing-files-in-root-share-directory-listing.patch +crypto-mxs-dcp-fix-wait-logic-on-chan-threads.patch +proc-restrict-kernel-stack-dumps-to-root.patch +ocfs2-fix-locking-for-res-tracking-and-dlm-tracking_list.patch diff --git a/queue-3.18/smb2-fix-missing-files-in-root-share-directory-listing.patch b/queue-3.18/smb2-fix-missing-files-in-root-share-directory-listing.patch new file mode 100644 index 00000000000..260836f04a2 --- /dev/null +++ b/queue-3.18/smb2-fix-missing-files-in-root-share-directory-listing.patch @@ -0,0 +1,175 @@ +From 0595751f267994c3c7027377058e4185b3a28e75 Mon Sep 17 00:00:00 2001 +From: Aurelien Aptel +Date: Thu, 17 May 2018 16:35:07 +0200 +Subject: smb2: fix missing files in root share directory listing + +From: Aurelien Aptel + +commit 0595751f267994c3c7027377058e4185b3a28e75 upstream. + +When mounting a Windows share that is the root of a drive (eg. C$) +the server does not return . and .. directory entries. This results in +the smb2 code path erroneously skipping the 2 first entries. + +Pseudo-code of the readdir() code path: + +cifs_readdir(struct file, struct dir_context) + initiate_cifs_search <-- if no reponse cached yet + server->ops->query_dir_first + + dir_emit_dots + dir_emit <-- adds "." and ".." if we're at pos=0 + + find_cifs_entry + initiate_cifs_search <-- if pos < start of current response + (restart search) + server->ops->query_dir_next <-- if pos > end of current response + (fetch next search res) + + for(...) <-- loops over cur response entries + starting at pos + cifs_filldir <-- skip . and .., emit entry + cifs_fill_dirent + dir_emit + pos++ + +A) dir_emit_dots() always adds . & .. + and sets the current dir pos to 2 (0 and 1 are done). + +Therefore we always want the index_to_find to be 2 regardless of if +the response has . and .. + +B) smb1 code initializes index_of_last_entry with a +2 offset + + in cifssmb.c CIFSFindFirst(): + psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + + psrch_inf->entries_in_buffer; + +Later in find_cifs_entry() we want to find the next dir entry at pos=2 +as a result of (A) + + first_entry_in_buffer = cfile->srch_inf.index_of_last_entry - + cfile->srch_inf.entries_in_buffer; + +This var is the dir pos that the first entry in the buffer will +have therefore it must be 2 in the first call. + +If we don't offset index_of_last_entry by 2 (like in (B)), +first_entry_in_buffer=0 but we were instructed to get pos=2 so this +code in find_cifs_entry() skips the 2 first which is ok for non-root +shares, as it skips . and .. from the response but is not ok for root +shares where the 2 first are actual files + + pos_in_buf = index_to_find - first_entry_in_buffer; + // pos_in_buf=2 + // we skip 2 first response entries :( + for (i = 0; (i < (pos_in_buf)) && (cur_ent != NULL); i++) { + /* go entry by entry figuring out which is first */ + cur_ent = nxt_dir_entry(cur_ent, end_of_smb, + cfile->srch_inf.info_level); + } + +C) cifs_filldir() skips . and .. so we can safely ignore them for now. + +Sample program: + +int main(int argc, char **argv) +{ + const char *path = argc >= 2 ? argv[1] : "."; + DIR *dh; + struct dirent *de; + + printf("listing path <%s>\n", path); + dh = opendir(path); + if (!dh) { + printf("opendir error %d\n", errno); + return 1; + } + + while (1) { + de = readdir(dh); + if (!de) { + if (errno) { + printf("readdir error %d\n", errno); + return 1; + } + printf("end of listing\n"); + break; + } + printf("off=%lu <%s>\n", de->d_off, de->d_name); + } + + return 0; +} + +Before the fix with SMB1 on root shares: + +<.> off=1 +<..> off=2 +<$Recycle.Bin> off=3 + off=4 + +and on non-root shares: + +<.> off=1 +<..> off=4 <-- after adding .., the offsets jumps to +2 because +<2536> off=5 we skipped . and .. from response buffer (C) +<411> off=6 but still incremented pos + off=7 + off=8 + +Therefore the fix for smb2 is to mimic smb1 behaviour and offset the +index_of_last_entry by 2. + +Test results comparing smb1 and smb2 before/after the fix on root +share, non-root shares and on large directories (ie. multi-response +dir listing): + +PRE FIX +======= +pre-1-root VS pre-2-root: + ERR pre-2-root is missing [bootmgr, $Recycle.Bin] +pre-1-nonroot VS pre-2-nonroot: + OK~ same files, same order, different offsets +pre-1-nonroot-large VS pre-2-nonroot-large: + OK~ same files, same order, different offsets + +POST FIX +======== +post-1-root VS post-2-root: + OK same files, same order, same offsets +post-1-nonroot VS post-2-nonroot: + OK same files, same order, same offsets +post-1-nonroot-large VS post-2-nonroot-large: + OK same files, same order, same offsets + +REGRESSION? +=========== +pre-1-root VS post-1-root: + OK same files, same order, same offsets +pre-1-nonroot VS post-1-nonroot: + OK same files, same order, same offsets + +BugLink: https://bugzilla.samba.org/show_bug.cgi?id=13107 +Signed-off-by: Aurelien Aptel +Signed-off-by: Paulo Alcantara +Reviewed-by: Ronnie Sahlberg +Signed-off-by: Steve French +CC: Stable +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cifs/smb2ops.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -847,7 +847,7 @@ smb2_query_dir_first(const unsigned int + } + + srch_inf->entries_in_buffer = 0; +- srch_inf->index_of_last_entry = 0; ++ srch_inf->index_of_last_entry = 2; + + rc = SMB2_query_directory(xid, tcon, fid->persistent_fid, + fid->volatile_fid, 0, srch_inf);