af_key: Fix send_acquire race with pfkey_register

[ Upstream commit 7f57f8165c ]

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: syzbot+1e9af9185d8850e2c2fa@syzkaller.appspotmail.com
Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Herbert Xu 2022-10-25 14:06:48 +08:00 committed by Greg Kroah-Hartman
parent fcc6154094
commit 4625ee5acf
1 changed files with 22 additions and 10 deletions

View File

@ -2940,7 +2940,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);
@ -2958,7 +2958,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++) {
@ -2969,16 +2969,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 = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop));
@ -3007,13 +3008,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 = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop));
@ -3055,8 +3060,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)
@ -3186,6 +3194,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)
@ -3197,16 +3206,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;
@ -3262,10 +3271,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) {