summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2017-04-13 06:35:59 -0400
committerSteffen Klassert <steffen.klassert@secunet.com>2017-04-18 02:26:03 -0400
commit096f41d3a8fcbb8dde7f71379b1ca85fe213eded (patch)
tree7a44309e40adeb5fcd793826b55047d4189f9a84 /net
parent89e357d83c06b6fac581c3ca7f0ee3ae7e67109e (diff)
af_key: Fix sadb_x_ipsecrequest parsing
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 <andreyknvl@google.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net')
-rw-r--r--net/key/af_key.c47
1 files changed, 26 insertions, 21 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 1b0ea80133f1..be8cecc65002 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -66,6 +66,10 @@ struct pfkey_sock {
66 struct mutex dump_lock; 66 struct mutex dump_lock;
67}; 67};
68 68
69static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
70 xfrm_address_t *saddr, xfrm_address_t *daddr,
71 u16 *family);
72
69static inline struct pfkey_sock *pfkey_sk(struct sock *sk) 73static inline struct pfkey_sock *pfkey_sk(struct sock *sk)
70{ 74{
71 return (struct pfkey_sock *)sk; 75 return (struct pfkey_sock *)sk;
@@ -1939,19 +1943,14 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
1939 1943
1940 /* addresses present only in tunnel mode */ 1944 /* addresses present only in tunnel mode */
1941 if (t->mode == XFRM_MODE_TUNNEL) { 1945 if (t->mode == XFRM_MODE_TUNNEL) {
1942 u8 *sa = (u8 *) (rq + 1); 1946 int err;
1943 int family, socklen;
1944 1947
1945 family = pfkey_sockaddr_extract((struct sockaddr *)sa, 1948 err = parse_sockaddr_pair(
1946 &t->saddr); 1949 (struct sockaddr *)(rq + 1),
1947 if (!family) 1950 rq->sadb_x_ipsecrequest_len - sizeof(*rq),
1948 return -EINVAL; 1951 &t->saddr, &t->id.daddr, &t->encap_family);
1949 1952 if (err)
1950 socklen = pfkey_sockaddr_len(family); 1953 return err;
1951 if (pfkey_sockaddr_extract((struct sockaddr *)(sa + socklen),
1952 &t->id.daddr) != family)
1953 return -EINVAL;
1954 t->encap_family = family;
1955 } else 1954 } else
1956 t->encap_family = xp->family; 1955 t->encap_family = xp->family;
1957 1956
@@ -1971,7 +1970,11 @@ parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol)
1971 if (pol->sadb_x_policy_len * 8 < sizeof(struct sadb_x_policy)) 1970 if (pol->sadb_x_policy_len * 8 < sizeof(struct sadb_x_policy))
1972 return -EINVAL; 1971 return -EINVAL;
1973 1972
1974 while (len >= sizeof(struct sadb_x_ipsecrequest)) { 1973 while (len >= sizeof(*rq)) {
1974 if (len < rq->sadb_x_ipsecrequest_len ||
1975 rq->sadb_x_ipsecrequest_len < sizeof(*rq))
1976 return -EINVAL;
1977
1975 if ((err = parse_ipsecrequest(xp, rq)) < 0) 1978 if ((err = parse_ipsecrequest(xp, rq)) < 0)
1976 return err; 1979 return err;
1977 len -= rq->sadb_x_ipsecrequest_len; 1980 len -= rq->sadb_x_ipsecrequest_len;
@@ -2434,7 +2437,6 @@ out:
2434 return err; 2437 return err;
2435} 2438}
2436 2439
2437#ifdef CONFIG_NET_KEY_MIGRATE
2438static int pfkey_sockaddr_pair_size(sa_family_t family) 2440static int pfkey_sockaddr_pair_size(sa_family_t family)
2439{ 2441{
2440 return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2); 2442 return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2);
@@ -2446,7 +2448,7 @@ static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
2446{ 2448{
2447 int af, socklen; 2449 int af, socklen;
2448 2450
2449 if (ext_len < pfkey_sockaddr_pair_size(sa->sa_family)) 2451 if (ext_len < 2 || ext_len < pfkey_sockaddr_pair_size(sa->sa_family))
2450 return -EINVAL; 2452 return -EINVAL;
2451 2453
2452 af = pfkey_sockaddr_extract(sa, saddr); 2454 af = pfkey_sockaddr_extract(sa, saddr);
@@ -2462,6 +2464,7 @@ static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
2462 return 0; 2464 return 0;
2463} 2465}
2464 2466
2467#ifdef CONFIG_NET_KEY_MIGRATE
2465static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, 2468static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
2466 struct xfrm_migrate *m) 2469 struct xfrm_migrate *m)
2467{ 2470{
@@ -2469,13 +2472,14 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
2469 struct sadb_x_ipsecrequest *rq2; 2472 struct sadb_x_ipsecrequest *rq2;
2470 int mode; 2473 int mode;
2471 2474
2472 if (len <= sizeof(struct sadb_x_ipsecrequest) || 2475 if (len < sizeof(*rq1) ||
2473 len < rq1->sadb_x_ipsecrequest_len) 2476 len < rq1->sadb_x_ipsecrequest_len ||
2477 rq1->sadb_x_ipsecrequest_len < sizeof(*rq1))
2474 return -EINVAL; 2478 return -EINVAL;
2475 2479
2476 /* old endoints */ 2480 /* old endoints */
2477 err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1), 2481 err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1),
2478 rq1->sadb_x_ipsecrequest_len, 2482 rq1->sadb_x_ipsecrequest_len - sizeof(*rq1),
2479 &m->old_saddr, &m->old_daddr, 2483 &m->old_saddr, &m->old_daddr,
2480 &m->old_family); 2484 &m->old_family);
2481 if (err) 2485 if (err)
@@ -2484,13 +2488,14 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
2484 rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len); 2488 rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len);
2485 len -= rq1->sadb_x_ipsecrequest_len; 2489 len -= rq1->sadb_x_ipsecrequest_len;
2486 2490
2487 if (len <= sizeof(struct sadb_x_ipsecrequest) || 2491 if (len <= sizeof(*rq2) ||
2488 len < rq2->sadb_x_ipsecrequest_len) 2492 len < rq2->sadb_x_ipsecrequest_len ||
2493 rq2->sadb_x_ipsecrequest_len < sizeof(*rq2))
2489 return -EINVAL; 2494 return -EINVAL;
2490 2495
2491 /* new endpoints */ 2496 /* new endpoints */
2492 err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1), 2497 err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1),
2493 rq2->sadb_x_ipsecrequest_len, 2498 rq2->sadb_x_ipsecrequest_len - sizeof(*rq2),
2494 &m->new_saddr, &m->new_daddr, 2499 &m->new_saddr, &m->new_daddr,
2495 &m->new_family); 2500 &m->new_family);
2496 if (err) 2501 if (err)