diff options
author | Andreas Wellving <andreas.wellving@enea.com> | 2019-07-10 14:34:02 +0200 |
---|---|---|
committer | Adrian Stratulat <adrian.stratulat@enea.com> | 2019-07-12 10:50:28 +0200 |
commit | ed745d7145a2b8fdc9145cd4af961f99a90b846a (patch) | |
tree | fd3e356769d6602546138f6be5295f4816e683a4 | |
parent | e1a607a34c7f712935cb12d758f17e2cc6f6804c (diff) | |
download | enea-kernel-cache-ed745d7145a2b8fdc9145cd4af961f99a90b846a.tar.gz |
sunrpc: CVE-2018-16884
sunrpc: use-after-free in svc_process_common()
References:
https://nvd.nist.gov/vuln/detail/CVE-2018-16884
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.9.y&id=37c791a031ece3afeb9c8b023397473a5349f171
Change-Id: I14973f204941ead7362a993f9cb84ed708cb8ac1
Signed-off-by: Andreas Wellving <andreas.wellving@enea.com>
-rw-r--r-- | patches/cve/4.9.x.scc | 3 | ||||
-rw-r--r-- | patches/cve/CVE-2018-16884-sunrpc-use-after-free-in-svc_process_common.patch | 159 |
2 files changed, 162 insertions, 0 deletions
diff --git a/patches/cve/4.9.x.scc b/patches/cve/4.9.x.scc index 0e01c9a..58d731a 100644 --- a/patches/cve/4.9.x.scc +++ b/patches/cve/4.9.x.scc | |||
@@ -63,3 +63,6 @@ patch CVE-2018-18690-xfs-don-t-fail-when-converting-shortform-attr-to-lon.patch | |||
63 | 63 | ||
64 | #CVEs fixed in 4.9.145: | 64 | #CVEs fixed in 4.9.145: |
65 | patch CVE-2018-20169-USB-check-usb_get_extra_descriptor-for-proper-size.patch | 65 | patch CVE-2018-20169-USB-check-usb_get_extra_descriptor-for-proper-size.patch |
66 | |||
67 | #CVEs fixed in 4.9.151: | ||
68 | 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..d6caa86 --- /dev/null +++ b/patches/cve/CVE-2018-16884-sunrpc-use-after-free-in-svc_process_common.patch | |||
@@ -0,0 +1,159 @@ | |||
1 | From 37c791a031ece3afeb9c8b023397473a5349f171 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 [https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.9.y&id=37c791a031ece3afeb9c8b023397473a5349f171] | ||
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 | - context fixes in svc_process_common() | ||
54 | Signed-off-by: Vasily Averin <vvs@virtuozzo.com> | ||
55 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
56 | Signed-off-by: Andreas Wellving <andreas.wellving@enea.com> | ||
57 | --- | ||
58 | include/linux/sunrpc/svc.h | 5 ++++- | ||
59 | net/sunrpc/svc.c | 9 ++++++--- | ||
60 | net/sunrpc/svc_xprt.c | 5 +++-- | ||
61 | net/sunrpc/svcsock.c | 2 +- | ||
62 | 4 files changed, 14 insertions(+), 7 deletions(-) | ||
63 | |||
64 | diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h | ||
65 | index 102c84dcc11a..63eed9ac8fd7 100644 | ||
66 | --- a/include/linux/sunrpc/svc.h | ||
67 | +++ b/include/linux/sunrpc/svc.h | ||
68 | @@ -291,9 +291,12 @@ struct svc_rqst { | ||
69 | struct svc_cacherep * rq_cacherep; /* cache info */ | ||
70 | struct task_struct *rq_task; /* service thread */ | ||
71 | spinlock_t rq_lock; /* per-request lock */ | ||
72 | + struct net *rq_bc_net; /* pointer to backchannel's | ||
73 | + * net namespace | ||
74 | + */ | ||
75 | }; | ||
76 | |||
77 | -#define SVC_NET(svc_rqst) (svc_rqst->rq_xprt->xpt_net) | ||
78 | +#define SVC_NET(rqst) (rqst->rq_xprt ? rqst->rq_xprt->xpt_net : rqst->rq_bc_net) | ||
79 | |||
80 | /* | ||
81 | * Rigorous type checking on sockaddr type conversions | ||
82 | diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c | ||
83 | index 272c34551979..eea18a124e4f 100644 | ||
84 | --- a/net/sunrpc/svc.c | ||
85 | +++ b/net/sunrpc/svc.c | ||
86 | @@ -1137,6 +1137,8 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) | ||
87 | static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {} | ||
88 | #endif | ||
89 | |||
90 | +extern void svc_tcp_prep_reply_hdr(struct svc_rqst *); | ||
91 | + | ||
92 | /* | ||
93 | * Common routine for processing the RPC request. | ||
94 | */ | ||
95 | @@ -1166,7 +1168,8 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) | ||
96 | clear_bit(RQ_DROPME, &rqstp->rq_flags); | ||
97 | |||
98 | /* Setup reply header */ | ||
99 | - rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); | ||
100 | + if (rqstp->rq_prot == IPPROTO_TCP) | ||
101 | + svc_tcp_prep_reply_hdr(rqstp); | ||
102 | |||
103 | svc_putu32(resv, rqstp->rq_xid); | ||
104 | |||
105 | @@ -1312,7 +1315,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) | ||
106 | return 0; | ||
107 | |||
108 | close: | ||
109 | - if (test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags)) | ||
110 | + if (rqstp->rq_xprt && test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags)) | ||
111 | svc_close_xprt(rqstp->rq_xprt); | ||
112 | dprintk("svc: svc_process close\n"); | ||
113 | return 0; | ||
114 | @@ -1439,10 +1442,10 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, | ||
115 | dprintk("svc: %s(%p)\n", __func__, req); | ||
116 | |||
117 | /* Build the svc_rqst used by the common processing routine */ | ||
118 | - rqstp->rq_xprt = serv->sv_bc_xprt; | ||
119 | rqstp->rq_xid = req->rq_xid; | ||
120 | rqstp->rq_prot = req->rq_xprt->prot; | ||
121 | rqstp->rq_server = serv; | ||
122 | + rqstp->rq_bc_net = req->rq_xprt->xprt_net; | ||
123 | |||
124 | rqstp->rq_addrlen = sizeof(req->rq_xprt->addr); | ||
125 | memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen); | ||
126 | diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c | ||
127 | index 064f20bb845a..42ce3ed21637 100644 | ||
128 | --- a/net/sunrpc/svc_xprt.c | ||
129 | +++ b/net/sunrpc/svc_xprt.c | ||
130 | @@ -510,10 +510,11 @@ static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool) | ||
131 | */ | ||
132 | void svc_reserve(struct svc_rqst *rqstp, int space) | ||
133 | { | ||
134 | + struct svc_xprt *xprt = rqstp->rq_xprt; | ||
135 | + | ||
136 | space += rqstp->rq_res.head[0].iov_len; | ||
137 | |||
138 | - if (space < rqstp->rq_reserved) { | ||
139 | - struct svc_xprt *xprt = rqstp->rq_xprt; | ||
140 | + if (xprt && space < rqstp->rq_reserved) { | ||
141 | atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved); | ||
142 | rqstp->rq_reserved = space; | ||
143 | |||
144 | diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c | ||
145 | index 33f599cb0936..fd7fbe91955e 100644 | ||
146 | --- a/net/sunrpc/svcsock.c | ||
147 | +++ b/net/sunrpc/svcsock.c | ||
148 | @@ -1195,7 +1195,7 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp) | ||
149 | /* | ||
150 | * Setup response header. TCP has a 4B record length field. | ||
151 | */ | ||
152 | -static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp) | ||
153 | +void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp) | ||
154 | { | ||
155 | struct kvec *resv = &rqstp->rq_res.head[0]; | ||
156 | |||
157 | -- | ||
158 | 2.20.1 | ||
159 | |||