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

Commit dd56c671 authored by Herbert Xu's avatar Herbert Xu Committed by Greg Kroah-Hartman
Browse files

af_key: Fix send_acquire race with pfkey_register



[ Upstream commit 7f57f8165cb6d2c206e2b9ada53b9e2d6d8af42f ]

The function pfkey_send_acquire may race with pfkey_register
(which could even be in a different name space).  This may result
in a buffer overrun.

Allocating the maximum amount of memory that could be used prevents
this.

Reported-by: default avatar <syzbot+1e9af9185d8850e2c2fa@syzkaller.appspotmail.com>
Fixes: 1da177e4 ("Linux-2.6.12-rc2")
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Reviewed-by: default avatarSabrina Dubroca <sd@queasysnail.net>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 9221a53b
Loading
Loading
Loading
Loading
+22 −10
Original line number Diff line number Diff line
@@ -2909,7 +2909,7 @@ static int count_ah_combs(const struct xfrm_tmpl *t)
			break;
		if (!aalg->pfkey_supported)
			continue;
		if (aalg_tmpl_set(t, aalg) && aalg->available)
		if (aalg_tmpl_set(t, aalg))
			sz += sizeof(struct sadb_comb);
	}
	return sz + sizeof(struct sadb_prop);
@@ -2927,7 +2927,7 @@ static int count_esp_combs(const struct xfrm_tmpl *t)
		if (!ealg->pfkey_supported)
			continue;

		if (!(ealg_tmpl_set(t, ealg) && ealg->available))
		if (!(ealg_tmpl_set(t, ealg)))
			continue;

		for (k = 1; ; k++) {
@@ -2938,16 +2938,17 @@ static int count_esp_combs(const struct xfrm_tmpl *t)
			if (!aalg->pfkey_supported)
				continue;

			if (aalg_tmpl_set(t, aalg) && aalg->available)
			if (aalg_tmpl_set(t, aalg))
				sz += sizeof(struct sadb_comb);
		}
	}
	return sz + sizeof(struct sadb_prop);
}

static void dump_ah_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
static int dump_ah_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
{
	struct sadb_prop *p;
	int sz = 0;
	int i;

	p = skb_put(skb, sizeof(struct sadb_prop));
@@ -2975,13 +2976,17 @@ static void dump_ah_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
			c->sadb_comb_soft_addtime = 20*60*60;
			c->sadb_comb_hard_usetime = 8*60*60;
			c->sadb_comb_soft_usetime = 7*60*60;
			sz += sizeof(*c);
		}
	}

	return sz + sizeof(*p);
}

static void dump_esp_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
static int dump_esp_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
{
	struct sadb_prop *p;
	int sz = 0;
	int i, k;

	p = skb_put(skb, sizeof(struct sadb_prop));
@@ -3023,8 +3028,11 @@ static void dump_esp_combs(struct sk_buff *skb, const struct xfrm_tmpl *t)
			c->sadb_comb_soft_addtime = 20*60*60;
			c->sadb_comb_hard_usetime = 8*60*60;
			c->sadb_comb_soft_usetime = 7*60*60;
			sz += sizeof(*c);
		}
	}

	return sz + sizeof(*p);
}

static int key_notify_policy_expire(struct xfrm_policy *xp, const struct km_event *c)
@@ -3154,6 +3162,7 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
	struct sadb_x_sec_ctx *sec_ctx;
	struct xfrm_sec_ctx *xfrm_ctx;
	int ctx_size = 0;
	int alg_size = 0;

	sockaddr_size = pfkey_sockaddr_size(x->props.family);
	if (!sockaddr_size)
@@ -3165,16 +3174,16 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
		sizeof(struct sadb_x_policy);

	if (x->id.proto == IPPROTO_AH)
		size += count_ah_combs(t);
		alg_size = count_ah_combs(t);
	else if (x->id.proto == IPPROTO_ESP)
		size += count_esp_combs(t);
		alg_size = count_esp_combs(t);

	if ((xfrm_ctx = x->security)) {
		ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len);
		size +=  sizeof(struct sadb_x_sec_ctx) + ctx_size;
	}

	skb =  alloc_skb(size + 16, GFP_ATOMIC);
	skb =  alloc_skb(size + alg_size + 16, GFP_ATOMIC);
	if (skb == NULL)
		return -ENOMEM;

@@ -3228,10 +3237,13 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
	pol->sadb_x_policy_priority = xp->priority;

	/* Set sadb_comb's. */
	alg_size = 0;
	if (x->id.proto == IPPROTO_AH)
		dump_ah_combs(skb, t);
		alg_size = dump_ah_combs(skb, t);
	else if (x->id.proto == IPPROTO_ESP)
		dump_esp_combs(skb, t);
		alg_size = dump_esp_combs(skb, t);

	hdr->sadb_msg_len += alg_size / 8;

	/* security context */
	if (xfrm_ctx) {