Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 12e35946 authored by Michal Kubecek's avatar Michal Kubecek Committed by Steffen Klassert
Browse files

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: default avatarMichal Kubecek <mkubecek@suse.cz>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
Acked-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent e9e4ea74
Loading
Loading
Loading
Loading
+6 −6
Original line number Original line Diff line number Diff line
@@ -141,14 +141,14 @@ static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb)
	const int plen = skb->len;
	const int plen = skb->len;
	int dlen = IPCOMP_SCRATCH_SIZE;
	int dlen = IPCOMP_SCRATCH_SIZE;
	u8 *start = skb->data;
	u8 *start = skb->data;
	const int cpu = get_cpu();
	struct crypto_comp *tfm;
	u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu);
	u8 *scratch;
	struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu);
	int err;
	int err;


	local_bh_disable();
	local_bh_disable();
	scratch = *this_cpu_ptr(ipcomp_scratches);
	tfm = *this_cpu_ptr(ipcd->tfms);
	err = crypto_comp_compress(tfm, start, plen, scratch, &dlen);
	err = crypto_comp_compress(tfm, start, plen, scratch, &dlen);
	local_bh_enable();
	if (err)
	if (err)
		goto out;
		goto out;


@@ -158,13 +158,13 @@ static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb)
	}
	}


	memcpy(start + sizeof(struct ip_comp_hdr), scratch, dlen);
	memcpy(start + sizeof(struct ip_comp_hdr), scratch, dlen);
	put_cpu();
	local_bh_enable();


	pskb_trim(skb, dlen + sizeof(struct ip_comp_hdr));
	pskb_trim(skb, dlen + sizeof(struct ip_comp_hdr));
	return 0;
	return 0;


out:
out:
	put_cpu();
	local_bh_enable();
	return err;
	return err;
}
}