Fix CVE-2017-9059 (rhbz 1451386 1451996)
This commit is contained in:
parent
76332f8637
commit
31d96fee60
|
@ -0,0 +1,156 @@
|
|||
From 9e0d87680d689f1758185851c3da6eafb16e71e1 Mon Sep 17 00:00:00 2001
|
||||
From: Trond Myklebust <trond.myklebust@primarydata.com>
|
||||
Date: Wed, 26 Apr 2017 11:55:26 -0400
|
||||
Subject: [PATCH] SUNRPC: Refactor svc_set_num_threads()
|
||||
|
||||
Refactor to separate out the functions of starting and stopping threads
|
||||
so that they can be used in other helpers.
|
||||
|
||||
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
|
||||
Tested-and-reviewed-by: Kinglong Mee <kinglongmee@gmail.com>
|
||||
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
|
||||
---
|
||||
net/sunrpc/svc.c | 96 ++++++++++++++++++++++++++++++++++----------------------
|
||||
1 file changed, 58 insertions(+), 38 deletions(-)
|
||||
|
||||
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
|
||||
index a08aeb5..98dc33a 100644
|
||||
--- a/net/sunrpc/svc.c
|
||||
+++ b/net/sunrpc/svc.c
|
||||
@@ -702,59 +702,32 @@ choose_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
|
||||
return task;
|
||||
}
|
||||
|
||||
-/*
|
||||
- * Create or destroy enough new threads to make the number
|
||||
- * of threads the given number. If `pool' is non-NULL, applies
|
||||
- * only to threads in that pool, otherwise round-robins between
|
||||
- * all pools. Caller must ensure that mutual exclusion between this and
|
||||
- * server startup or shutdown.
|
||||
- *
|
||||
- * Destroying threads relies on the service threads filling in
|
||||
- * rqstp->rq_task, which only the nfs ones do. Assumes the serv
|
||||
- * has been created using svc_create_pooled().
|
||||
- *
|
||||
- * Based on code that used to be in nfsd_svc() but tweaked
|
||||
- * to be pool-aware.
|
||||
- */
|
||||
-int
|
||||
-svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
|
||||
+/* create new threads */
|
||||
+static int
|
||||
+svc_start_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
|
||||
{
|
||||
struct svc_rqst *rqstp;
|
||||
struct task_struct *task;
|
||||
struct svc_pool *chosen_pool;
|
||||
- int error = 0;
|
||||
unsigned int state = serv->sv_nrthreads-1;
|
||||
int node;
|
||||
|
||||
- if (pool == NULL) {
|
||||
- /* The -1 assumes caller has done a svc_get() */
|
||||
- nrservs -= (serv->sv_nrthreads-1);
|
||||
- } else {
|
||||
- spin_lock_bh(&pool->sp_lock);
|
||||
- nrservs -= pool->sp_nrthreads;
|
||||
- spin_unlock_bh(&pool->sp_lock);
|
||||
- }
|
||||
-
|
||||
- /* create new threads */
|
||||
- while (nrservs > 0) {
|
||||
+ do {
|
||||
nrservs--;
|
||||
chosen_pool = choose_pool(serv, pool, &state);
|
||||
|
||||
node = svc_pool_map_get_node(chosen_pool->sp_id);
|
||||
rqstp = svc_prepare_thread(serv, chosen_pool, node);
|
||||
- if (IS_ERR(rqstp)) {
|
||||
- error = PTR_ERR(rqstp);
|
||||
- break;
|
||||
- }
|
||||
+ if (IS_ERR(rqstp))
|
||||
+ return PTR_ERR(rqstp);
|
||||
|
||||
__module_get(serv->sv_ops->svo_module);
|
||||
task = kthread_create_on_node(serv->sv_ops->svo_function, rqstp,
|
||||
node, "%s", serv->sv_name);
|
||||
if (IS_ERR(task)) {
|
||||
- error = PTR_ERR(task);
|
||||
module_put(serv->sv_ops->svo_module);
|
||||
svc_exit_thread(rqstp);
|
||||
- break;
|
||||
+ return PTR_ERR(task);
|
||||
}
|
||||
|
||||
rqstp->rq_task = task;
|
||||
@@ -763,15 +736,62 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
|
||||
|
||||
svc_sock_update_bufs(serv);
|
||||
wake_up_process(task);
|
||||
- }
|
||||
+ } while (nrservs > 0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/* destroy old threads */
|
||||
+static int
|
||||
+svc_signal_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
|
||||
+{
|
||||
+ struct task_struct *task;
|
||||
+ unsigned int state = serv->sv_nrthreads-1;
|
||||
+
|
||||
/* destroy old threads */
|
||||
- while (nrservs < 0 &&
|
||||
- (task = choose_victim(serv, pool, &state)) != NULL) {
|
||||
+ do {
|
||||
+ task = choose_victim(serv, pool, &state);
|
||||
+ if (task == NULL)
|
||||
+ break;
|
||||
send_sig(SIGINT, task, 1);
|
||||
nrservs++;
|
||||
+ } while (nrservs < 0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Create or destroy enough new threads to make the number
|
||||
+ * of threads the given number. If `pool' is non-NULL, applies
|
||||
+ * only to threads in that pool, otherwise round-robins between
|
||||
+ * all pools. Caller must ensure that mutual exclusion between this and
|
||||
+ * server startup or shutdown.
|
||||
+ *
|
||||
+ * Destroying threads relies on the service threads filling in
|
||||
+ * rqstp->rq_task, which only the nfs ones do. Assumes the serv
|
||||
+ * has been created using svc_create_pooled().
|
||||
+ *
|
||||
+ * Based on code that used to be in nfsd_svc() but tweaked
|
||||
+ * to be pool-aware.
|
||||
+ */
|
||||
+int
|
||||
+svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
|
||||
+{
|
||||
+ if (pool == NULL) {
|
||||
+ /* The -1 assumes caller has done a svc_get() */
|
||||
+ nrservs -= (serv->sv_nrthreads-1);
|
||||
+ } else {
|
||||
+ spin_lock_bh(&pool->sp_lock);
|
||||
+ nrservs -= pool->sp_nrthreads;
|
||||
+ spin_unlock_bh(&pool->sp_lock);
|
||||
}
|
||||
|
||||
- return error;
|
||||
+ if (nrservs > 0)
|
||||
+ return svc_start_kthreads(serv, pool, nrservs);
|
||||
+ if (nrservs < 0)
|
||||
+ return svc_signal_kthreads(serv, pool, nrservs);
|
||||
+ return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_set_num_threads);
|
||||
|
||||
--
|
||||
2.9.4
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
From ed6473ddc704a2005b9900ca08e236ebb2d8540a Mon Sep 17 00:00:00 2001
|
||||
From: Trond Myklebust <trond.myklebust@primarydata.com>
|
||||
Date: Wed, 26 Apr 2017 11:55:27 -0400
|
||||
Subject: [PATCH] NFSv4: Fix callback server shutdown
|
||||
|
||||
We want to use kthread_stop() in order to ensure the threads are
|
||||
shut down before we tear down the nfs_callback_info in nfs_callback_down.
|
||||
|
||||
Tested-and-reviewed-by: Kinglong Mee <kinglongmee@gmail.com>
|
||||
Reported-by: Kinglong Mee <kinglongmee@gmail.com>
|
||||
Fixes: bb6aeba736ba9 ("NFSv4.x: Switch to using svc_set_num_threads()...")
|
||||
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
|
||||
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
|
||||
---
|
||||
fs/nfs/callback.c | 24 ++++++++++++++++--------
|
||||
include/linux/sunrpc/svc.h | 1 +
|
||||
net/sunrpc/svc.c | 38 ++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 55 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
|
||||
index c5e27eb..73a1f92 100644
|
||||
--- a/fs/nfs/callback.c
|
||||
+++ b/fs/nfs/callback.c
|
||||
@@ -76,7 +76,10 @@ nfs4_callback_svc(void *vrqstp)
|
||||
|
||||
set_freezable();
|
||||
|
||||
- while (!kthread_should_stop()) {
|
||||
+ while (!kthread_freezable_should_stop(NULL)) {
|
||||
+
|
||||
+ if (signal_pending(current))
|
||||
+ flush_signals(current);
|
||||
/*
|
||||
* Listen for a request on the socket
|
||||
*/
|
||||
@@ -85,6 +88,8 @@ nfs4_callback_svc(void *vrqstp)
|
||||
continue;
|
||||
svc_process(rqstp);
|
||||
}
|
||||
+ svc_exit_thread(rqstp);
|
||||
+ module_put_and_exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -103,9 +108,10 @@ nfs41_callback_svc(void *vrqstp)
|
||||
|
||||
set_freezable();
|
||||
|
||||
- while (!kthread_should_stop()) {
|
||||
- if (try_to_freeze())
|
||||
- continue;
|
||||
+ while (!kthread_freezable_should_stop(NULL)) {
|
||||
+
|
||||
+ if (signal_pending(current))
|
||||
+ flush_signals(current);
|
||||
|
||||
prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE);
|
||||
spin_lock_bh(&serv->sv_cb_lock);
|
||||
@@ -121,11 +127,13 @@ nfs41_callback_svc(void *vrqstp)
|
||||
error);
|
||||
} else {
|
||||
spin_unlock_bh(&serv->sv_cb_lock);
|
||||
- schedule();
|
||||
+ if (!kthread_should_stop())
|
||||
+ schedule();
|
||||
finish_wait(&serv->sv_cb_waitq, &wq);
|
||||
}
|
||||
- flush_signals(current);
|
||||
}
|
||||
+ svc_exit_thread(rqstp);
|
||||
+ module_put_and_exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -221,14 +229,14 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
|
||||
static struct svc_serv_ops nfs40_cb_sv_ops = {
|
||||
.svo_function = nfs4_callback_svc,
|
||||
.svo_enqueue_xprt = svc_xprt_do_enqueue,
|
||||
- .svo_setup = svc_set_num_threads,
|
||||
+ .svo_setup = svc_set_num_threads_sync,
|
||||
.svo_module = THIS_MODULE,
|
||||
};
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
static struct svc_serv_ops nfs41_cb_sv_ops = {
|
||||
.svo_function = nfs41_callback_svc,
|
||||
.svo_enqueue_xprt = svc_xprt_do_enqueue,
|
||||
- .svo_setup = svc_set_num_threads,
|
||||
+ .svo_setup = svc_set_num_threads_sync,
|
||||
.svo_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
|
||||
index 6ef19cf..9463102 100644
|
||||
--- a/include/linux/sunrpc/svc.h
|
||||
+++ b/include/linux/sunrpc/svc.h
|
||||
@@ -473,6 +473,7 @@ void svc_pool_map_put(void);
|
||||
struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
|
||||
struct svc_serv_ops *);
|
||||
int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
|
||||
+int svc_set_num_threads_sync(struct svc_serv *, struct svc_pool *, int);
|
||||
int svc_pool_stats_open(struct svc_serv *serv, struct file *file);
|
||||
void svc_destroy(struct svc_serv *);
|
||||
void svc_shutdown_net(struct svc_serv *, struct net *);
|
||||
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
|
||||
index 98dc33a..bc0f5a0 100644
|
||||
--- a/net/sunrpc/svc.c
|
||||
+++ b/net/sunrpc/svc.c
|
||||
@@ -795,6 +795,44 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_set_num_threads);
|
||||
|
||||
+/* destroy old threads */
|
||||
+static int
|
||||
+svc_stop_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
|
||||
+{
|
||||
+ struct task_struct *task;
|
||||
+ unsigned int state = serv->sv_nrthreads-1;
|
||||
+
|
||||
+ /* destroy old threads */
|
||||
+ do {
|
||||
+ task = choose_victim(serv, pool, &state);
|
||||
+ if (task == NULL)
|
||||
+ break;
|
||||
+ kthread_stop(task);
|
||||
+ nrservs++;
|
||||
+ } while (nrservs < 0);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+svc_set_num_threads_sync(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
|
||||
+{
|
||||
+ if (pool == NULL) {
|
||||
+ /* The -1 assumes caller has done a svc_get() */
|
||||
+ nrservs -= (serv->sv_nrthreads-1);
|
||||
+ } else {
|
||||
+ spin_lock_bh(&pool->sp_lock);
|
||||
+ nrservs -= pool->sp_nrthreads;
|
||||
+ spin_unlock_bh(&pool->sp_lock);
|
||||
+ }
|
||||
+
|
||||
+ if (nrservs > 0)
|
||||
+ return svc_start_kthreads(serv, pool, nrservs);
|
||||
+ if (nrservs < 0)
|
||||
+ return svc_stop_kthreads(serv, pool, nrservs);
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(svc_set_num_threads_sync);
|
||||
+
|
||||
/*
|
||||
* Called from a server thread as it's exiting. Caller must hold the "service
|
||||
* mutex" for the service.
|
||||
--
|
||||
2.9.4
|
||||
|
|
@ -607,6 +607,10 @@ Patch864: dell-laptop-Adds-support-for-keyboard-backlight-timeout-AC-settings.pa
|
|||
#CVE-2017-7487 rhbz 1447734 1450417
|
||||
Patch865: 0001-ipx-call-ipxitf_put-in-ioctl-error-path.patch
|
||||
|
||||
#CVE-2017-9059 rhbz 1451386 1451996
|
||||
Patch866: 0001-SUNRPC-Refactor-svc_set_num_threads.patch
|
||||
Patch867: 0002-NFSv4-Fix-callback-server-shutdown.patch
|
||||
|
||||
# END OF PATCH DEFINITIONS
|
||||
|
||||
%endif
|
||||
|
@ -2176,6 +2180,9 @@ fi
|
|||
#
|
||||
#
|
||||
%changelog
|
||||
* Thu May 18 2017 Justin M. Forbes <jforbes@fedoraproject.org>
|
||||
- Fix CVE-2017-9059 (rhbz 1451386 1451996)
|
||||
|
||||
* Mon May 15 2017 Justin M. Forbes <jforbes@fedoraproject.org> - 4.10.16-100
|
||||
- Linux v4.10.16
|
||||
- Fix CVE-2017-7487 (rhbz 1447734 1450417)
|
||||
|
|
Loading…
Reference in New Issue