diff options
author | Michal Kubecek <mkubecek@suse.cz> | 2013-10-17 09:07:40 -0400 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2013-10-18 04:00:00 -0400 |
commit | 12e3594698f6c3ab6ebacc79f2fb2ad2bb5952b5 (patch) | |
tree | 17915102ba31fd52f0096f77cbb38f587f16b6ec | |
parent | e9e4ea74f06635f2ffc1dffe5ef40c854faa0a90 (diff) |
xfrm: prevent ipcomp scratch buffer race condition
In ipcomp_compress(), sortirq is enabled too early, allowing the
per-cpu scratch buffer to be rewritten by ipcomp_decompress()
(called on the same CPU in softirq context) between populating
the buffer and copying the compressed data to the skb.
v2: as pointed out by Steffen Klassert, if we also move the
local_bh_disable() before reading the per-cpu pointers, we can
get rid of get_cpu()/put_cpu().
v3: removed ipcomp_decompress part (as explained by Herbert Xu,
it cannot be called from process context), get rid of cpu
variable (thanks to Eric Dumazet)
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
-rw-r--r-- | net/xfrm/xfrm_ipcomp.c | 12 |
1 files changed, 6 insertions, 6 deletions
diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c index 2906d520eea7..3be02b680268 100644 --- a/net/xfrm/xfrm_ipcomp.c +++ b/net/xfrm/xfrm_ipcomp.c | |||
@@ -141,14 +141,14 @@ static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb) | |||
141 | const int plen = skb->len; | 141 | const int plen = skb->len; |
142 | int dlen = IPCOMP_SCRATCH_SIZE; | 142 | int dlen = IPCOMP_SCRATCH_SIZE; |
143 | u8 *start = skb->data; | 143 | u8 *start = skb->data; |
144 | const int cpu = get_cpu(); | 144 | struct crypto_comp *tfm; |
145 | u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu); | 145 | u8 *scratch; |
146 | struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu); | ||
147 | int err; | 146 | int err; |
148 | 147 | ||
149 | local_bh_disable(); | 148 | local_bh_disable(); |
149 | scratch = *this_cpu_ptr(ipcomp_scratches); | ||
150 | tfm = *this_cpu_ptr(ipcd->tfms); | ||
150 | err = crypto_comp_compress(tfm, start, plen, scratch, &dlen); | 151 | err = crypto_comp_compress(tfm, start, plen, scratch, &dlen); |
151 | local_bh_enable(); | ||
152 | if (err) | 152 | if (err) |
153 | goto out; | 153 | goto out; |
154 | 154 | ||
@@ -158,13 +158,13 @@ static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb) | |||
158 | } | 158 | } |
159 | 159 | ||
160 | memcpy(start + sizeof(struct ip_comp_hdr), scratch, dlen); | 160 | memcpy(start + sizeof(struct ip_comp_hdr), scratch, dlen); |
161 | put_cpu(); | 161 | local_bh_enable(); |
162 | 162 | ||
163 | pskb_trim(skb, dlen + sizeof(struct ip_comp_hdr)); | 163 | pskb_trim(skb, dlen + sizeof(struct ip_comp_hdr)); |
164 | return 0; | 164 | return 0; |
165 | 165 | ||
166 | out: | 166 | out: |
167 | put_cpu(); | 167 | local_bh_enable(); |
168 | return err; | 168 | return err; |
169 | } | 169 | } |
170 | 170 | ||