diff options
| -rw-r--r-- | patches/cve/4.14.x.scc | 2 | ||||
| -rw-r--r-- | patches/cve/CVE-2018-16884-sunrpc-use-after-free-in-svc_process_common.patch | 167 |
2 files changed, 169 insertions, 0 deletions
diff --git a/patches/cve/4.14.x.scc b/patches/cve/4.14.x.scc index 36143b1..41bfe7a 100644 --- a/patches/cve/4.14.x.scc +++ b/patches/cve/4.14.x.scc | |||
| @@ -19,3 +19,5 @@ patch CVE-2018-19824-ALSA-usb-audio-Fix-UAF-decrement-if-card-has-no-live.patch | |||
| 19 | patch CVE-2018-20169-USB-check-usb_get_extra_descriptor-for-proper-size.patch | 19 | patch CVE-2018-20169-USB-check-usb_get_extra_descriptor-for-proper-size.patch |
| 20 | CVEs fixed in 4.14.91: | 20 | CVEs fixed in 4.14.91: |
| 21 | patch CVE-2018-19985-USB-hso-Fix-OOB-memory-access-in-hso_probe-hso_get_c.patch | 21 | patch CVE-2018-19985-USB-hso-Fix-OOB-memory-access-in-hso_probe-hso_get_c.patch |
| 22 | CVEs fixed in 4.14.94: | ||
| 23 | patch CVE-2018-16884-sunrpc-use-after-free-in-svc_process_common.patch | ||
diff --git a/patches/cve/CVE-2018-16884-sunrpc-use-after-free-in-svc_process_common.patch b/patches/cve/CVE-2018-16884-sunrpc-use-after-free-in-svc_process_common.patch new file mode 100644 index 0000000..36878cb --- /dev/null +++ b/patches/cve/CVE-2018-16884-sunrpc-use-after-free-in-svc_process_common.patch | |||
| @@ -0,0 +1,167 @@ | |||
| 1 | From 65dba32522065b79a16393efc75f8006c2c3dbb8 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Vasily Averin <vvs@virtuozzo.com> | ||
| 3 | Date: Mon, 24 Dec 2018 14:44:52 +0300 | ||
| 4 | Subject: [PATCH] sunrpc: use-after-free in svc_process_common() | ||
| 5 | |||
| 6 | commit d4b09acf924b84bae77cad090a9d108e70b43643 upstream. | ||
| 7 | |||
| 8 | if node have NFSv41+ mounts inside several net namespaces | ||
| 9 | it can lead to use-after-free in svc_process_common() | ||
| 10 | |||
| 11 | svc_process_common() | ||
| 12 | /* Setup reply header */ | ||
| 13 | rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); <<< HERE | ||
| 14 | |||
| 15 | svc_process_common() can use incorrect rqstp->rq_xprt, | ||
| 16 | its caller function bc_svc_process() takes it from serv->sv_bc_xprt. | ||
| 17 | The problem is that serv is global structure but sv_bc_xprt | ||
| 18 | is assigned per-netnamespace. | ||
| 19 | |||
| 20 | According to Trond, the whole "let's set up rqstp->rq_xprt | ||
| 21 | for the back channel" is nothing but a giant hack in order | ||
| 22 | to work around the fact that svc_process_common() uses it | ||
| 23 | to find the xpt_ops, and perform a couple of (meaningless | ||
| 24 | for the back channel) tests of xpt_flags. | ||
| 25 | |||
| 26 | All we really need in svc_process_common() is to be able to run | ||
| 27 | rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr() | ||
| 28 | |||
| 29 | Bruce J Fields points that this xpo_prep_reply_hdr() call | ||
| 30 | is an awfully roundabout way just to do "svc_putnl(resv, 0);" | ||
| 31 | in the tcp case. | ||
| 32 | |||
| 33 | This patch does not initialiuze rqstp->rq_xprt in bc_svc_process(), | ||
| 34 | now it calls svc_process_common() with rqstp->rq_xprt = NULL. | ||
| 35 | |||
| 36 | To adjust reply header svc_process_common() just check | ||
| 37 | rqstp->rq_prot and calls svc_tcp_prep_reply_hdr() for tcp case. | ||
| 38 | |||
| 39 | To handle rqstp->rq_xprt = NULL case in functions called from | ||
| 40 | svc_process_common() patch intruduces net namespace pointer | ||
| 41 | svc_rqst->rq_bc_net and adjust SVC_NET() definition. | ||
| 42 | Some other function was also adopted to properly handle described case. | ||
| 43 | |||
| 44 | CVE: CVE-2018-16884 | ||
| 45 | Upstream-Status: Backport | ||
| 46 | |||
| 47 | Signed-off-by: Vasily Averin <vvs@virtuozzo.com> | ||
| 48 | Cc: stable@vger.kernel.org | ||
| 49 | Fixes: 23c20ecd4475 ("NFS: callback up - users counting cleanup") | ||
| 50 | Signed-off-by: J. Bruce Fields <bfields@redhat.com> | ||
| 51 | v2: - added lost extern svc_tcp_prep_reply_hdr() | ||
| 52 | - dropped trace_svc_process() changes | ||
| 53 | Signed-off-by: Vasily Averin <vvs@virtuozzo.com> | ||
| 54 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
| 55 | Signed-off-by: Andreas Wellving <andreas.wellving@enea.com> | ||
| 56 | --- | ||
| 57 | include/linux/sunrpc/svc.h | 5 ++++- | ||
| 58 | net/sunrpc/svc.c | 11 +++++++---- | ||
| 59 | net/sunrpc/svc_xprt.c | 5 +++-- | ||
| 60 | net/sunrpc/svcsock.c | 2 +- | ||
| 61 | 4 files changed, 15 insertions(+), 8 deletions(-) | ||
| 62 | |||
| 63 | diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h | ||
| 64 | index 3b9f0d1dbb80..e1aa80c4d6db 100644 | ||
| 65 | --- a/include/linux/sunrpc/svc.h | ||
| 66 | +++ b/include/linux/sunrpc/svc.h | ||
| 67 | @@ -292,9 +292,12 @@ struct svc_rqst { | ||
| 68 | struct svc_cacherep * rq_cacherep; /* cache info */ | ||
| 69 | struct task_struct *rq_task; /* service thread */ | ||
| 70 | spinlock_t rq_lock; /* per-request lock */ | ||
| 71 | + struct net *rq_bc_net; /* pointer to backchannel's | ||
| 72 | + * net namespace | ||
| 73 | + */ | ||
| 74 | }; | ||
| 75 | |||
| 76 | -#define SVC_NET(svc_rqst) (svc_rqst->rq_xprt->xpt_net) | ||
| 77 | +#define SVC_NET(rqst) (rqst->rq_xprt ? rqst->rq_xprt->xpt_net : rqst->rq_bc_net) | ||
| 78 | |||
| 79 | /* | ||
| 80 | * Rigorous type checking on sockaddr type conversions | ||
| 81 | diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c | ||
| 82 | index aa04666f929d..3a9a03717212 100644 | ||
| 83 | --- a/net/sunrpc/svc.c | ||
| 84 | +++ b/net/sunrpc/svc.c | ||
| 85 | @@ -1144,6 +1144,8 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) | ||
| 86 | static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {} | ||
| 87 | #endif | ||
| 88 | |||
| 89 | +extern void svc_tcp_prep_reply_hdr(struct svc_rqst *); | ||
| 90 | + | ||
| 91 | /* | ||
| 92 | * Common routine for processing the RPC request. | ||
| 93 | */ | ||
| 94 | @@ -1172,7 +1174,8 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) | ||
| 95 | clear_bit(RQ_DROPME, &rqstp->rq_flags); | ||
| 96 | |||
| 97 | /* Setup reply header */ | ||
| 98 | - rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); | ||
| 99 | + if (rqstp->rq_prot == IPPROTO_TCP) | ||
| 100 | + svc_tcp_prep_reply_hdr(rqstp); | ||
| 101 | |||
| 102 | svc_putu32(resv, rqstp->rq_xid); | ||
| 103 | |||
| 104 | @@ -1244,7 +1247,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) | ||
| 105 | * for lower versions. RPC_PROG_MISMATCH seems to be the closest | ||
| 106 | * fit. | ||
| 107 | */ | ||
| 108 | - if (versp->vs_need_cong_ctrl && | ||
| 109 | + if (versp->vs_need_cong_ctrl && rqstp->rq_xprt && | ||
| 110 | !test_bit(XPT_CONG_CTRL, &rqstp->rq_xprt->xpt_flags)) | ||
| 111 | goto err_bad_vers; | ||
| 112 | |||
| 113 | @@ -1335,7 +1338,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) | ||
| 114 | return 0; | ||
| 115 | |||
| 116 | close: | ||
| 117 | - if (test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags)) | ||
| 118 | + if (rqstp->rq_xprt && test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags)) | ||
| 119 | svc_close_xprt(rqstp->rq_xprt); | ||
| 120 | dprintk("svc: svc_process close\n"); | ||
| 121 | return 0; | ||
| 122 | @@ -1462,10 +1465,10 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, | ||
| 123 | dprintk("svc: %s(%p)\n", __func__, req); | ||
| 124 | |||
| 125 | /* Build the svc_rqst used by the common processing routine */ | ||
| 126 | - rqstp->rq_xprt = serv->sv_bc_xprt; | ||
| 127 | rqstp->rq_xid = req->rq_xid; | ||
| 128 | rqstp->rq_prot = req->rq_xprt->prot; | ||
| 129 | rqstp->rq_server = serv; | ||
| 130 | + rqstp->rq_bc_net = req->rq_xprt->xprt_net; | ||
| 131 | |||
| 132 | rqstp->rq_addrlen = sizeof(req->rq_xprt->addr); | ||
| 133 | memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen); | ||
| 134 | diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c | ||
| 135 | index ea7b5a3a53f0..7e5f849b44cd 100644 | ||
| 136 | --- a/net/sunrpc/svc_xprt.c | ||
| 137 | +++ b/net/sunrpc/svc_xprt.c | ||
| 138 | @@ -510,10 +510,11 @@ static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool) | ||
| 139 | */ | ||
| 140 | void svc_reserve(struct svc_rqst *rqstp, int space) | ||
| 141 | { | ||
| 142 | + struct svc_xprt *xprt = rqstp->rq_xprt; | ||
| 143 | + | ||
| 144 | space += rqstp->rq_res.head[0].iov_len; | ||
| 145 | |||
| 146 | - if (space < rqstp->rq_reserved) { | ||
| 147 | - struct svc_xprt *xprt = rqstp->rq_xprt; | ||
| 148 | + if (xprt && space < rqstp->rq_reserved) { | ||
| 149 | atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved); | ||
| 150 | rqstp->rq_reserved = space; | ||
| 151 | |||
| 152 | diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c | ||
| 153 | index c83df30e9655..d6771f3b715b 100644 | ||
| 154 | --- a/net/sunrpc/svcsock.c | ||
| 155 | +++ b/net/sunrpc/svcsock.c | ||
| 156 | @@ -1207,7 +1207,7 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp) | ||
| 157 | /* | ||
| 158 | * Setup response header. TCP has a 4B record length field. | ||
| 159 | */ | ||
| 160 | -static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp) | ||
| 161 | +void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp) | ||
| 162 | { | ||
| 163 | struct kvec *resv = &rqstp->rq_res.head[0]; | ||
| 164 | |||
| 165 | -- | ||
| 166 | 2.19.2 | ||
| 167 | |||
