summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Cline <jcline@redhat.com>2019-01-09 10:45:44 -0500
committerJeremy Cline <jcline@redhat.com>2019-01-09 12:50:12 -0500
commit1b52baea418bd86ec9b0b09fe52980cf8e985e8d (patch)
treec61bb15de930e2cc83c98d21f42831029eece9e0
parent8674faa8b3921c456ac2f81f25aa2a6826d85802 (diff)
downloadkernel-1b52baea418bd86ec9b0b09fe52980cf8e985e8d.tar.gz
kernel-1b52baea418bd86ec9b0b09fe52980cf8e985e8d.tar.xz
kernel-1b52baea418bd86ec9b0b09fe52980cf8e985e8d.zip
Fix CVE-2018-16884 (rhbz 1660375 1660825)
-rw-r--r--CVE-2018-16884.patch230
-rw-r--r--kernel.spec6
2 files changed, 236 insertions, 0 deletions
diff --git a/CVE-2018-16884.patch b/CVE-2018-16884.patch
new file mode 100644
index 000000000..54832925c
--- /dev/null
+++ b/CVE-2018-16884.patch
@@ -0,0 +1,230 @@
+From 321f89f5812405fd3018b162535ae29bda669909 Mon Sep 17 00:00:00 2001
+From: Vasily Averin <vvs@virtuozzo.com>
+Date: Mon, 24 Dec 2018 14:44:42 +0300
+Subject: [PATCH 1/2] sunrpc: use SVC_NET() in svcauth_gss_* functions
+
+Signed-off-by: Vasily Averin <vvs@virtuozzo.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Jeremy Cline <jcline@redhat.com>
+---
+ net/sunrpc/auth_gss/svcauth_gss.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
+index 860f2a1bbb67..1a65f88d021a 100644
+--- a/net/sunrpc/auth_gss/svcauth_gss.c
++++ b/net/sunrpc/auth_gss/svcauth_gss.c
+@@ -1122,7 +1122,7 @@ static int svcauth_gss_legacy_init(struct svc_rqst *rqstp,
+ struct kvec *resv = &rqstp->rq_res.head[0];
+ struct rsi *rsip, rsikey;
+ int ret;
+- struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);
++ struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
+
+ memset(&rsikey, 0, sizeof(rsikey));
+ ret = gss_read_verf(gc, argv, authp,
+@@ -1233,7 +1233,7 @@ static int svcauth_gss_proxy_init(struct svc_rqst *rqstp,
+ uint64_t handle;
+ int status;
+ int ret;
+- struct net *net = rqstp->rq_xprt->xpt_net;
++ struct net *net = SVC_NET(rqstp);
+ struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+ memset(&ud, 0, sizeof(ud));
+@@ -1424,7 +1424,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
+ __be32 *rpcstart;
+ __be32 *reject_stat = resv->iov_base + resv->iov_len;
+ int ret;
+- struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);
++ struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
+
+ dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n",
+ argv->iov_len);
+@@ -1714,7 +1714,7 @@ svcauth_gss_release(struct svc_rqst *rqstp)
+ struct rpc_gss_wire_cred *gc = &gsd->clcred;
+ struct xdr_buf *resbuf = &rqstp->rq_res;
+ int stat = -EINVAL;
+- struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);
++ struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
+
+ if (gc->gc_proc != RPC_GSS_PROC_DATA)
+ goto out;
+--
+2.20.1
+
+From b7cde4db1cb620368534aaf89c82e3ee10ef4d72 Mon Sep 17 00:00:00 2001
+From: Vasily Averin <vvs@virtuozzo.com>
+Date: Mon, 24 Dec 2018 14:44:52 +0300
+Subject: [PATCH 2/2] sunrpc: use-after-free in svc_process_common()
+
+if node have NFSv41+ mounts inside several net namespaces
+it can lead to use-after-free in svc_process_common()
+
+svc_process_common()
+ /* Setup reply header */
+ rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); <<< HERE
+
+svc_process_common() can use incorrect rqstp->rq_xprt,
+its caller function bc_svc_process() takes it from serv->sv_bc_xprt.
+The problem is that serv is global structure but sv_bc_xprt
+is assigned per-netnamespace.
+
+According to Trond, the whole "let's set up rqstp->rq_xprt
+for the back channel" is nothing but a giant hack in order
+to work around the fact that svc_process_common() uses it
+to find the xpt_ops, and perform a couple of (meaningless
+for the back channel) tests of xpt_flags.
+
+All we really need in svc_process_common() is to be able to run
+rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr()
+
+Bruce J Fields points that this xpo_prep_reply_hdr() call
+is an awfully roundabout way just to do "svc_putnl(resv, 0);"
+in the tcp case.
+
+This patch does not initialiuze rqstp->rq_xprt in bc_svc_process(),
+now it calls svc_process_common() with rqstp->rq_xprt = NULL.
+
+To adjust reply header svc_process_common() just check
+rqstp->rq_prot and calls svc_tcp_prep_reply_hdr() for tcp case.
+
+To handle rqstp->rq_xprt = NULL case in functions called from
+svc_process_common() patch intruduces net namespace pointer
+svc_rqst->rq_bc_net and adjust SVC_NET() definition.
+Some other function was also adopted to properly handle described case.
+
+Signed-off-by: Vasily Averin <vvs@virtuozzo.com>
+Cc: stable@vger.kernel.org
+Fixes: 23c20ecd4475 ("NFS: callback up - users counting cleanup")
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Jeremy Cline <jcline@redhat.com>
+---
+ include/linux/sunrpc/svc.h | 5 ++++-
+ include/trace/events/sunrpc.h | 6 ++++--
+ net/sunrpc/svc.c | 9 +++++----
+ net/sunrpc/svc_xprt.c | 5 +++--
+ net/sunrpc/svcsock.c | 2 +-
+ 5 files changed, 17 insertions(+), 10 deletions(-)
+
+diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
+index 73e130a840ce..fdb6b317d974 100644
+--- a/include/linux/sunrpc/svc.h
++++ b/include/linux/sunrpc/svc.h
+@@ -295,9 +295,12 @@ struct svc_rqst {
+ struct svc_cacherep * rq_cacherep; /* cache info */
+ struct task_struct *rq_task; /* service thread */
+ spinlock_t rq_lock; /* per-request lock */
++ struct net *rq_bc_net; /* pointer to backchannel's
++ * net namespace
++ */
+ };
+
+-#define SVC_NET(svc_rqst) (svc_rqst->rq_xprt->xpt_net)
++#define SVC_NET(rqst) (rqst->rq_xprt ? rqst->rq_xprt->xpt_net : rqst->rq_bc_net)
+
+ /*
+ * Rigorous type checking on sockaddr type conversions
+diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h
+index bbb08a3ef5cc..a2644c494a9c 100644
+--- a/include/trace/events/sunrpc.h
++++ b/include/trace/events/sunrpc.h
+@@ -582,7 +582,8 @@ TRACE_EVENT(svc_process,
+ __field(u32, vers)
+ __field(u32, proc)
+ __string(service, name)
+- __string(addr, rqst->rq_xprt->xpt_remotebuf)
++ __string(addr, rqst->rq_xprt ?
++ rqst->rq_xprt->xpt_remotebuf : "(null)")
+ ),
+
+ TP_fast_assign(
+@@ -590,7 +591,8 @@ TRACE_EVENT(svc_process,
+ __entry->vers = rqst->rq_vers;
+ __entry->proc = rqst->rq_proc;
+ __assign_str(service, name);
+- __assign_str(addr, rqst->rq_xprt->xpt_remotebuf);
++ __assign_str(addr, rqst->rq_xprt ?
++ rqst->rq_xprt->xpt_remotebuf : "(null)");
+ ),
+
+ TP_printk("addr=%s xid=0x%08x service=%s vers=%u proc=%u",
+diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
+index d13e05f1a990..fb647bc01fc5 100644
+--- a/net/sunrpc/svc.c
++++ b/net/sunrpc/svc.c
+@@ -1172,7 +1172,8 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
+ clear_bit(RQ_DROPME, &rqstp->rq_flags);
+
+ /* Setup reply header */
+- rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp);
++ if (rqstp->rq_prot == IPPROTO_TCP)
++ svc_tcp_prep_reply_hdr(rqstp);
+
+ svc_putu32(resv, rqstp->rq_xid);
+
+@@ -1244,7 +1245,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
+ * for lower versions. RPC_PROG_MISMATCH seems to be the closest
+ * fit.
+ */
+- if (versp->vs_need_cong_ctrl &&
++ if (versp->vs_need_cong_ctrl && rqstp->rq_xprt &&
+ !test_bit(XPT_CONG_CTRL, &rqstp->rq_xprt->xpt_flags))
+ goto err_bad_vers;
+
+@@ -1336,7 +1337,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
+ return 0;
+
+ close:
+- if (test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags))
++ if (rqstp->rq_xprt && test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags))
+ svc_close_xprt(rqstp->rq_xprt);
+ dprintk("svc: svc_process close\n");
+ return 0;
+@@ -1459,10 +1460,10 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
+ dprintk("svc: %s(%p)\n", __func__, req);
+
+ /* Build the svc_rqst used by the common processing routine */
+- rqstp->rq_xprt = serv->sv_bc_xprt;
+ rqstp->rq_xid = req->rq_xid;
+ rqstp->rq_prot = req->rq_xprt->prot;
+ rqstp->rq_server = serv;
++ rqstp->rq_bc_net = req->rq_xprt->xprt_net;
+
+ rqstp->rq_addrlen = sizeof(req->rq_xprt->addr);
+ memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen);
+diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
+index 83ccd0221c98..6cf0fd37cbf0 100644
+--- a/net/sunrpc/svc_xprt.c
++++ b/net/sunrpc/svc_xprt.c
+@@ -469,10 +469,11 @@ static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool)
+ */
+ void svc_reserve(struct svc_rqst *rqstp, int space)
+ {
++ struct svc_xprt *xprt = rqstp->rq_xprt;
++
+ space += rqstp->rq_res.head[0].iov_len;
+
+- if (space < rqstp->rq_reserved) {
+- struct svc_xprt *xprt = rqstp->rq_xprt;
++ if (xprt && space < rqstp->rq_reserved) {
+ atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved);
+ rqstp->rq_reserved = space;
+
+diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
+index 5445145e639c..0221f565538e 100644
+--- a/net/sunrpc/svcsock.c
++++ b/net/sunrpc/svcsock.c
+@@ -1198,7 +1198,7 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp)
+ /*
+ * Setup response header. TCP has a 4B record length field.
+ */
+-static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp)
++void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp)
+ {
+ struct kvec *resv = &rqstp->rq_res.head[0];
+
+--
+2.20.1
+
diff --git a/kernel.spec b/kernel.spec
index 90af59ce8..3a5f63314 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -636,6 +636,9 @@ Patch517: 0001-Bluetooth-btsdio-Do-not-bind-to-non-removable-BCM434.patch
# CVE-2019-3701 rhbz 1663729 1663730
Patch518: CVE-2019-3701.patch
+# CVE-2018-16884 rhbz 1660375 1660825
+Patch519: CVE-2018-16884.patch
+
# END OF PATCH DEFINITIONS
%endif
@@ -1887,6 +1890,9 @@ fi
#
#
%changelog
+* Wed Jan 09 2019 Jeremy Cline <jeremy@jcline.org>
+- Fix CVE-2018-16884 (rhbz 1660375 1660825)
+
* Wed Jan 09 2019 Justin M. Forbes <jforbes@fedoraproject.org>
- Fix CVE-2019-3701 (rhbz 1663729 1663730)