diff options
author | David S. Miller <davem@davemloft.net> | 2017-04-20 16:19:46 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-04-20 16:19:46 -0400 |
commit | 12a0a6c05471176a453e324d0d5e51c6f381ad63 (patch) | |
tree | 25bca6aabd24d4cefe0bd827f1b1e6a731857f69 | |
parent | 9d386cd9a755c8293e8916264d4d053878a7c9c7 (diff) | |
parent | 096f41d3a8fcbb8dde7f71379b1ca85fe213eded (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says:
====================
pull request (net): ipsec 2017-04-19
Two fixes for af_key:
1) Add a lock to key dump to prevent a NULL pointer dereference.
From Yuejie Shi.
2) Fix slab-out-of-bounds in parse_ipsecrequests.
From Herbert Xu.
Please pull or let me know if there are problems.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/key/af_key.c | 93 |
1 files changed, 64 insertions, 29 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c index c6252ed42c1d..be8cecc65002 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -63,8 +63,13 @@ struct pfkey_sock { | |||
63 | } u; | 63 | } u; |
64 | struct sk_buff *skb; | 64 | struct sk_buff *skb; |
65 | } dump; | 65 | } dump; |
66 | struct mutex dump_lock; | ||
66 | }; | 67 | }; |
67 | 68 | ||
69 | static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len, | ||
70 | xfrm_address_t *saddr, xfrm_address_t *daddr, | ||
71 | u16 *family); | ||
72 | |||
68 | static inline struct pfkey_sock *pfkey_sk(struct sock *sk) | 73 | static inline struct pfkey_sock *pfkey_sk(struct sock *sk) |
69 | { | 74 | { |
70 | return (struct pfkey_sock *)sk; | 75 | return (struct pfkey_sock *)sk; |
@@ -139,6 +144,7 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol, | |||
139 | { | 144 | { |
140 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); | 145 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); |
141 | struct sock *sk; | 146 | struct sock *sk; |
147 | struct pfkey_sock *pfk; | ||
142 | int err; | 148 | int err; |
143 | 149 | ||
144 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) | 150 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
@@ -153,6 +159,9 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol, | |||
153 | if (sk == NULL) | 159 | if (sk == NULL) |
154 | goto out; | 160 | goto out; |
155 | 161 | ||
162 | pfk = pfkey_sk(sk); | ||
163 | mutex_init(&pfk->dump_lock); | ||
164 | |||
156 | sock->ops = &pfkey_ops; | 165 | sock->ops = &pfkey_ops; |
157 | sock_init_data(sock, sk); | 166 | sock_init_data(sock, sk); |
158 | 167 | ||
@@ -281,13 +290,23 @@ static int pfkey_do_dump(struct pfkey_sock *pfk) | |||
281 | struct sadb_msg *hdr; | 290 | struct sadb_msg *hdr; |
282 | int rc; | 291 | int rc; |
283 | 292 | ||
293 | mutex_lock(&pfk->dump_lock); | ||
294 | if (!pfk->dump.dump) { | ||
295 | rc = 0; | ||
296 | goto out; | ||
297 | } | ||
298 | |||
284 | rc = pfk->dump.dump(pfk); | 299 | rc = pfk->dump.dump(pfk); |
285 | if (rc == -ENOBUFS) | 300 | if (rc == -ENOBUFS) { |
286 | return 0; | 301 | rc = 0; |
302 | goto out; | ||
303 | } | ||
287 | 304 | ||
288 | if (pfk->dump.skb) { | 305 | if (pfk->dump.skb) { |
289 | if (!pfkey_can_dump(&pfk->sk)) | 306 | if (!pfkey_can_dump(&pfk->sk)) { |
290 | return 0; | 307 | rc = 0; |
308 | goto out; | ||
309 | } | ||
291 | 310 | ||
292 | hdr = (struct sadb_msg *) pfk->dump.skb->data; | 311 | hdr = (struct sadb_msg *) pfk->dump.skb->data; |
293 | hdr->sadb_msg_seq = 0; | 312 | hdr->sadb_msg_seq = 0; |
@@ -298,6 +317,9 @@ static int pfkey_do_dump(struct pfkey_sock *pfk) | |||
298 | } | 317 | } |
299 | 318 | ||
300 | pfkey_terminate_dump(pfk); | 319 | pfkey_terminate_dump(pfk); |
320 | |||
321 | out: | ||
322 | mutex_unlock(&pfk->dump_lock); | ||
301 | return rc; | 323 | return rc; |
302 | } | 324 | } |
303 | 325 | ||
@@ -1793,19 +1815,26 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_ms | |||
1793 | struct xfrm_address_filter *filter = NULL; | 1815 | struct xfrm_address_filter *filter = NULL; |
1794 | struct pfkey_sock *pfk = pfkey_sk(sk); | 1816 | struct pfkey_sock *pfk = pfkey_sk(sk); |
1795 | 1817 | ||
1796 | if (pfk->dump.dump != NULL) | 1818 | mutex_lock(&pfk->dump_lock); |
1819 | if (pfk->dump.dump != NULL) { | ||
1820 | mutex_unlock(&pfk->dump_lock); | ||
1797 | return -EBUSY; | 1821 | return -EBUSY; |
1822 | } | ||
1798 | 1823 | ||
1799 | proto = pfkey_satype2proto(hdr->sadb_msg_satype); | 1824 | proto = pfkey_satype2proto(hdr->sadb_msg_satype); |
1800 | if (proto == 0) | 1825 | if (proto == 0) { |
1826 | mutex_unlock(&pfk->dump_lock); | ||
1801 | return -EINVAL; | 1827 | return -EINVAL; |
1828 | } | ||
1802 | 1829 | ||
1803 | if (ext_hdrs[SADB_X_EXT_FILTER - 1]) { | 1830 | if (ext_hdrs[SADB_X_EXT_FILTER - 1]) { |
1804 | struct sadb_x_filter *xfilter = ext_hdrs[SADB_X_EXT_FILTER - 1]; | 1831 | struct sadb_x_filter *xfilter = ext_hdrs[SADB_X_EXT_FILTER - 1]; |
1805 | 1832 | ||
1806 | filter = kmalloc(sizeof(*filter), GFP_KERNEL); | 1833 | filter = kmalloc(sizeof(*filter), GFP_KERNEL); |
1807 | if (filter == NULL) | 1834 | if (filter == NULL) { |
1835 | mutex_unlock(&pfk->dump_lock); | ||
1808 | return -ENOMEM; | 1836 | return -ENOMEM; |
1837 | } | ||
1809 | 1838 | ||
1810 | memcpy(&filter->saddr, &xfilter->sadb_x_filter_saddr, | 1839 | memcpy(&filter->saddr, &xfilter->sadb_x_filter_saddr, |
1811 | sizeof(xfrm_address_t)); | 1840 | sizeof(xfrm_address_t)); |
@@ -1821,6 +1850,7 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_ms | |||
1821 | pfk->dump.dump = pfkey_dump_sa; | 1850 | pfk->dump.dump = pfkey_dump_sa; |
1822 | pfk->dump.done = pfkey_dump_sa_done; | 1851 | pfk->dump.done = pfkey_dump_sa_done; |
1823 | xfrm_state_walk_init(&pfk->dump.u.state, proto, filter); | 1852 | xfrm_state_walk_init(&pfk->dump.u.state, proto, filter); |
1853 | mutex_unlock(&pfk->dump_lock); | ||
1824 | 1854 | ||
1825 | return pfkey_do_dump(pfk); | 1855 | return pfkey_do_dump(pfk); |
1826 | } | 1856 | } |
@@ -1913,19 +1943,14 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) | |||
1913 | 1943 | ||
1914 | /* addresses present only in tunnel mode */ | 1944 | /* addresses present only in tunnel mode */ |
1915 | if (t->mode == XFRM_MODE_TUNNEL) { | 1945 | if (t->mode == XFRM_MODE_TUNNEL) { |
1916 | u8 *sa = (u8 *) (rq + 1); | 1946 | int err; |
1917 | int family, socklen; | ||
1918 | 1947 | ||
1919 | family = pfkey_sockaddr_extract((struct sockaddr *)sa, | 1948 | err = parse_sockaddr_pair( |
1920 | &t->saddr); | 1949 | (struct sockaddr *)(rq + 1), |
1921 | if (!family) | 1950 | rq->sadb_x_ipsecrequest_len - sizeof(*rq), |
1922 | return -EINVAL; | 1951 | &t->saddr, &t->id.daddr, &t->encap_family); |
1923 | 1952 | if (err) | |
1924 | socklen = pfkey_sockaddr_len(family); | 1953 | return err; |
1925 | if (pfkey_sockaddr_extract((struct sockaddr *)(sa + socklen), | ||
1926 | &t->id.daddr) != family) | ||
1927 | return -EINVAL; | ||
1928 | t->encap_family = family; | ||
1929 | } else | 1954 | } else |
1930 | t->encap_family = xp->family; | 1955 | t->encap_family = xp->family; |
1931 | 1956 | ||
@@ -1945,7 +1970,11 @@ parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol) | |||
1945 | 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)) |
1946 | return -EINVAL; | 1971 | return -EINVAL; |
1947 | 1972 | ||
1948 | 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 | |||
1949 | if ((err = parse_ipsecrequest(xp, rq)) < 0) | 1978 | if ((err = parse_ipsecrequest(xp, rq)) < 0) |
1950 | return err; | 1979 | return err; |
1951 | len -= rq->sadb_x_ipsecrequest_len; | 1980 | len -= rq->sadb_x_ipsecrequest_len; |
@@ -2408,7 +2437,6 @@ out: | |||
2408 | return err; | 2437 | return err; |
2409 | } | 2438 | } |
2410 | 2439 | ||
2411 | #ifdef CONFIG_NET_KEY_MIGRATE | ||
2412 | static int pfkey_sockaddr_pair_size(sa_family_t family) | 2440 | static int pfkey_sockaddr_pair_size(sa_family_t family) |
2413 | { | 2441 | { |
2414 | return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2); | 2442 | return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2); |
@@ -2420,7 +2448,7 @@ static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len, | |||
2420 | { | 2448 | { |
2421 | int af, socklen; | 2449 | int af, socklen; |
2422 | 2450 | ||
2423 | if (ext_len < pfkey_sockaddr_pair_size(sa->sa_family)) | 2451 | if (ext_len < 2 || ext_len < pfkey_sockaddr_pair_size(sa->sa_family)) |
2424 | return -EINVAL; | 2452 | return -EINVAL; |
2425 | 2453 | ||
2426 | af = pfkey_sockaddr_extract(sa, saddr); | 2454 | af = pfkey_sockaddr_extract(sa, saddr); |
@@ -2436,6 +2464,7 @@ static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len, | |||
2436 | return 0; | 2464 | return 0; |
2437 | } | 2465 | } |
2438 | 2466 | ||
2467 | #ifdef CONFIG_NET_KEY_MIGRATE | ||
2439 | static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, | 2468 | static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, |
2440 | struct xfrm_migrate *m) | 2469 | struct xfrm_migrate *m) |
2441 | { | 2470 | { |
@@ -2443,13 +2472,14 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, | |||
2443 | struct sadb_x_ipsecrequest *rq2; | 2472 | struct sadb_x_ipsecrequest *rq2; |
2444 | int mode; | 2473 | int mode; |
2445 | 2474 | ||
2446 | if (len <= sizeof(struct sadb_x_ipsecrequest) || | 2475 | if (len < sizeof(*rq1) || |
2447 | len < rq1->sadb_x_ipsecrequest_len) | 2476 | len < rq1->sadb_x_ipsecrequest_len || |
2477 | rq1->sadb_x_ipsecrequest_len < sizeof(*rq1)) | ||
2448 | return -EINVAL; | 2478 | return -EINVAL; |
2449 | 2479 | ||
2450 | /* old endoints */ | 2480 | /* old endoints */ |
2451 | err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1), | 2481 | err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1), |
2452 | rq1->sadb_x_ipsecrequest_len, | 2482 | rq1->sadb_x_ipsecrequest_len - sizeof(*rq1), |
2453 | &m->old_saddr, &m->old_daddr, | 2483 | &m->old_saddr, &m->old_daddr, |
2454 | &m->old_family); | 2484 | &m->old_family); |
2455 | if (err) | 2485 | if (err) |
@@ -2458,13 +2488,14 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, | |||
2458 | 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); |
2459 | len -= rq1->sadb_x_ipsecrequest_len; | 2489 | len -= rq1->sadb_x_ipsecrequest_len; |
2460 | 2490 | ||
2461 | if (len <= sizeof(struct sadb_x_ipsecrequest) || | 2491 | if (len <= sizeof(*rq2) || |
2462 | len < rq2->sadb_x_ipsecrequest_len) | 2492 | len < rq2->sadb_x_ipsecrequest_len || |
2493 | rq2->sadb_x_ipsecrequest_len < sizeof(*rq2)) | ||
2463 | return -EINVAL; | 2494 | return -EINVAL; |
2464 | 2495 | ||
2465 | /* new endpoints */ | 2496 | /* new endpoints */ |
2466 | err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1), | 2497 | err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1), |
2467 | rq2->sadb_x_ipsecrequest_len, | 2498 | rq2->sadb_x_ipsecrequest_len - sizeof(*rq2), |
2468 | &m->new_saddr, &m->new_daddr, | 2499 | &m->new_saddr, &m->new_daddr, |
2469 | &m->new_family); | 2500 | &m->new_family); |
2470 | if (err) | 2501 | if (err) |
@@ -2679,14 +2710,18 @@ static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb | |||
2679 | { | 2710 | { |
2680 | struct pfkey_sock *pfk = pfkey_sk(sk); | 2711 | struct pfkey_sock *pfk = pfkey_sk(sk); |
2681 | 2712 | ||
2682 | if (pfk->dump.dump != NULL) | 2713 | mutex_lock(&pfk->dump_lock); |
2714 | if (pfk->dump.dump != NULL) { | ||
2715 | mutex_unlock(&pfk->dump_lock); | ||
2683 | return -EBUSY; | 2716 | return -EBUSY; |
2717 | } | ||
2684 | 2718 | ||
2685 | pfk->dump.msg_version = hdr->sadb_msg_version; | 2719 | pfk->dump.msg_version = hdr->sadb_msg_version; |
2686 | pfk->dump.msg_portid = hdr->sadb_msg_pid; | 2720 | pfk->dump.msg_portid = hdr->sadb_msg_pid; |
2687 | pfk->dump.dump = pfkey_dump_sp; | 2721 | pfk->dump.dump = pfkey_dump_sp; |
2688 | pfk->dump.done = pfkey_dump_sp_done; | 2722 | pfk->dump.done = pfkey_dump_sp_done; |
2689 | xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN); | 2723 | xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN); |
2724 | mutex_unlock(&pfk->dump_lock); | ||
2690 | 2725 | ||
2691 | return pfkey_do_dump(pfk); | 2726 | return pfkey_do_dump(pfk); |
2692 | } | 2727 | } |