Skip to content

Commit 7ad6d36

Browse files
herbertxgregkh
authored andcommitted
af_key: Fix sadb_x_ipsecrequest parsing
commit 096f41d upstream. The parsing of sadb_x_ipsecrequest is broken in a number of ways. First of all we're not verifying sadb_x_ipsecrequest_len. This is needed when the structure carries addresses at the end. Worse we don't even look at the length when we parse those optional addresses. The migration code had similar parsing code that's better but it also has some deficiencies. The length is overcounted first of all as it includes the header itself. It also fails to check the length before dereferencing the sa_family field. This patch fixes those problems in parse_sockaddr_pair and then uses it in parse_ipsecrequest. Reported-by: Andrey Konovalov <[email protected]> Signed-off-by: Herbert Xu <[email protected]> Signed-off-by: Steffen Klassert <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b8c6a93 commit 7ad6d36

File tree

1 file changed

+26
-21
lines changed

1 file changed

+26
-21
lines changed

net/key/af_key.c

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ struct pfkey_sock {
6565
} dump;
6666
};
6767

68+
static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
69+
xfrm_address_t *saddr, xfrm_address_t *daddr,
70+
u16 *family);
71+
6872
static inline struct pfkey_sock *pfkey_sk(struct sock *sk)
6973
{
7074
return (struct pfkey_sock *)sk;
@@ -1922,19 +1926,14 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
19221926

19231927
/* addresses present only in tunnel mode */
19241928
if (t->mode == XFRM_MODE_TUNNEL) {
1925-
u8 *sa = (u8 *) (rq + 1);
1926-
int family, socklen;
1929+
int err;
19271930

1928-
family = pfkey_sockaddr_extract((struct sockaddr *)sa,
1929-
&t->saddr);
1930-
if (!family)
1931-
return -EINVAL;
1932-
1933-
socklen = pfkey_sockaddr_len(family);
1934-
if (pfkey_sockaddr_extract((struct sockaddr *)(sa + socklen),
1935-
&t->id.daddr) != family)
1936-
return -EINVAL;
1937-
t->encap_family = family;
1931+
err = parse_sockaddr_pair(
1932+
(struct sockaddr *)(rq + 1),
1933+
rq->sadb_x_ipsecrequest_len - sizeof(*rq),
1934+
&t->saddr, &t->id.daddr, &t->encap_family);
1935+
if (err)
1936+
return err;
19381937
} else
19391938
t->encap_family = xp->family;
19401939

@@ -1954,7 +1953,11 @@ parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol)
19541953
if (pol->sadb_x_policy_len * 8 < sizeof(struct sadb_x_policy))
19551954
return -EINVAL;
19561955

1957-
while (len >= sizeof(struct sadb_x_ipsecrequest)) {
1956+
while (len >= sizeof(*rq)) {
1957+
if (len < rq->sadb_x_ipsecrequest_len ||
1958+
rq->sadb_x_ipsecrequest_len < sizeof(*rq))
1959+
return -EINVAL;
1960+
19581961
if ((err = parse_ipsecrequest(xp, rq)) < 0)
19591962
return err;
19601963
len -= rq->sadb_x_ipsecrequest_len;
@@ -2417,7 +2420,6 @@ static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struc
24172420
return err;
24182421
}
24192422

2420-
#ifdef CONFIG_NET_KEY_MIGRATE
24212423
static int pfkey_sockaddr_pair_size(sa_family_t family)
24222424
{
24232425
return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2);
@@ -2429,7 +2431,7 @@ static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
24292431
{
24302432
int af, socklen;
24312433

2432-
if (ext_len < pfkey_sockaddr_pair_size(sa->sa_family))
2434+
if (ext_len < 2 || ext_len < pfkey_sockaddr_pair_size(sa->sa_family))
24332435
return -EINVAL;
24342436

24352437
af = pfkey_sockaddr_extract(sa, saddr);
@@ -2445,20 +2447,22 @@ static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
24452447
return 0;
24462448
}
24472449

2450+
#ifdef CONFIG_NET_KEY_MIGRATE
24482451
static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
24492452
struct xfrm_migrate *m)
24502453
{
24512454
int err;
24522455
struct sadb_x_ipsecrequest *rq2;
24532456
int mode;
24542457

2455-
if (len <= sizeof(struct sadb_x_ipsecrequest) ||
2456-
len < rq1->sadb_x_ipsecrequest_len)
2458+
if (len < sizeof(*rq1) ||
2459+
len < rq1->sadb_x_ipsecrequest_len ||
2460+
rq1->sadb_x_ipsecrequest_len < sizeof(*rq1))
24572461
return -EINVAL;
24582462

24592463
/* old endoints */
24602464
err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1),
2461-
rq1->sadb_x_ipsecrequest_len,
2465+
rq1->sadb_x_ipsecrequest_len - sizeof(*rq1),
24622466
&m->old_saddr, &m->old_daddr,
24632467
&m->old_family);
24642468
if (err)
@@ -2467,13 +2471,14 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
24672471
rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len);
24682472
len -= rq1->sadb_x_ipsecrequest_len;
24692473

2470-
if (len <= sizeof(struct sadb_x_ipsecrequest) ||
2471-
len < rq2->sadb_x_ipsecrequest_len)
2474+
if (len <= sizeof(*rq2) ||
2475+
len < rq2->sadb_x_ipsecrequest_len ||
2476+
rq2->sadb_x_ipsecrequest_len < sizeof(*rq2))
24722477
return -EINVAL;
24732478

24742479
/* new endpoints */
24752480
err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1),
2476-
rq2->sadb_x_ipsecrequest_len,
2481+
rq2->sadb_x_ipsecrequest_len - sizeof(*rq2),
24772482
&m->new_saddr, &m->new_daddr,
24782483
&m->new_family);
24792484
if (err)

0 commit comments

Comments
 (0)