diff options
author | Jeremy Cline <jcline@redhat.com> | 2019-01-09 10:45:44 -0500 |
---|---|---|
committer | Jeremy Cline <jcline@redhat.com> | 2019-01-09 12:50:12 -0500 |
commit | 1b52baea418bd86ec9b0b09fe52980cf8e985e8d (patch) | |
tree | c61bb15de930e2cc83c98d21f42831029eece9e0 | |
parent | 8674faa8b3921c456ac2f81f25aa2a6826d85802 (diff) | |
download | kernel-1b52baea418bd86ec9b0b09fe52980cf8e985e8d.tar.gz kernel-1b52baea418bd86ec9b0b09fe52980cf8e985e8d.tar.xz kernel-1b52baea418bd86ec9b0b09fe52980cf8e985e8d.zip |
Fix CVE-2018-16884 (rhbz 1660375 1660825)
-rw-r--r-- | CVE-2018-16884.patch | 230 | ||||
-rw-r--r-- | kernel.spec | 6 |
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) |