diff options
Diffstat (limited to 'net/key/af_key.c')
-rw-r--r-- | net/key/af_key.c | 154 |
1 files changed, 121 insertions, 33 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c index d628df97e02e..362fe317e1f3 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -58,6 +58,7 @@ struct pfkey_sock { | |||
58 | struct xfrm_policy_walk policy; | 58 | struct xfrm_policy_walk policy; |
59 | struct xfrm_state_walk state; | 59 | struct xfrm_state_walk state; |
60 | } u; | 60 | } u; |
61 | struct sk_buff *skb; | ||
61 | } dump; | 62 | } dump; |
62 | }; | 63 | }; |
63 | 64 | ||
@@ -73,22 +74,22 @@ static int pfkey_can_dump(struct sock *sk) | |||
73 | return 0; | 74 | return 0; |
74 | } | 75 | } |
75 | 76 | ||
76 | static int pfkey_do_dump(struct pfkey_sock *pfk) | 77 | static void pfkey_terminate_dump(struct pfkey_sock *pfk) |
77 | { | 78 | { |
78 | int rc; | 79 | if (pfk->dump.dump) { |
79 | 80 | if (pfk->dump.skb) { | |
80 | rc = pfk->dump.dump(pfk); | 81 | kfree_skb(pfk->dump.skb); |
81 | if (rc == -ENOBUFS) | 82 | pfk->dump.skb = NULL; |
82 | return 0; | 83 | } |
83 | 84 | pfk->dump.done(pfk); | |
84 | pfk->dump.done(pfk); | 85 | pfk->dump.dump = NULL; |
85 | pfk->dump.dump = NULL; | 86 | pfk->dump.done = NULL; |
86 | pfk->dump.done = NULL; | 87 | } |
87 | return rc; | ||
88 | } | 88 | } |
89 | 89 | ||
90 | static void pfkey_sock_destruct(struct sock *sk) | 90 | static void pfkey_sock_destruct(struct sock *sk) |
91 | { | 91 | { |
92 | pfkey_terminate_dump(pfkey_sk(sk)); | ||
92 | skb_queue_purge(&sk->sk_receive_queue); | 93 | skb_queue_purge(&sk->sk_receive_queue); |
93 | 94 | ||
94 | if (!sock_flag(sk, SOCK_DEAD)) { | 95 | if (!sock_flag(sk, SOCK_DEAD)) { |
@@ -310,6 +311,31 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, | |||
310 | return err; | 311 | return err; |
311 | } | 312 | } |
312 | 313 | ||
314 | static int pfkey_do_dump(struct pfkey_sock *pfk) | ||
315 | { | ||
316 | struct sadb_msg *hdr; | ||
317 | int rc; | ||
318 | |||
319 | rc = pfk->dump.dump(pfk); | ||
320 | if (rc == -ENOBUFS) | ||
321 | return 0; | ||
322 | |||
323 | if (pfk->dump.skb) { | ||
324 | if (!pfkey_can_dump(&pfk->sk)) | ||
325 | return 0; | ||
326 | |||
327 | hdr = (struct sadb_msg *) pfk->dump.skb->data; | ||
328 | hdr->sadb_msg_seq = 0; | ||
329 | hdr->sadb_msg_errno = rc; | ||
330 | pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, | ||
331 | &pfk->sk); | ||
332 | pfk->dump.skb = NULL; | ||
333 | } | ||
334 | |||
335 | pfkey_terminate_dump(pfk); | ||
336 | return rc; | ||
337 | } | ||
338 | |||
313 | static inline void pfkey_hdr_dup(struct sadb_msg *new, struct sadb_msg *orig) | 339 | static inline void pfkey_hdr_dup(struct sadb_msg *new, struct sadb_msg *orig) |
314 | { | 340 | { |
315 | *new = *orig; | 341 | *new = *orig; |
@@ -372,6 +398,7 @@ static u8 sadb_ext_min_len[] = { | |||
372 | [SADB_X_EXT_NAT_T_DPORT] = (u8) sizeof(struct sadb_x_nat_t_port), | 398 | [SADB_X_EXT_NAT_T_DPORT] = (u8) sizeof(struct sadb_x_nat_t_port), |
373 | [SADB_X_EXT_NAT_T_OA] = (u8) sizeof(struct sadb_address), | 399 | [SADB_X_EXT_NAT_T_OA] = (u8) sizeof(struct sadb_address), |
374 | [SADB_X_EXT_SEC_CTX] = (u8) sizeof(struct sadb_x_sec_ctx), | 400 | [SADB_X_EXT_SEC_CTX] = (u8) sizeof(struct sadb_x_sec_ctx), |
401 | [SADB_X_EXT_KMADDRESS] = (u8) sizeof(struct sadb_x_kmaddress), | ||
375 | }; | 402 | }; |
376 | 403 | ||
377 | /* Verify sadb_address_{len,prefixlen} against sa_family. */ | 404 | /* Verify sadb_address_{len,prefixlen} against sa_family. */ |
@@ -1736,9 +1763,14 @@ static int dump_sa(struct xfrm_state *x, int count, void *ptr) | |||
1736 | out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); | 1763 | out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); |
1737 | out_hdr->sadb_msg_errno = 0; | 1764 | out_hdr->sadb_msg_errno = 0; |
1738 | out_hdr->sadb_msg_reserved = 0; | 1765 | out_hdr->sadb_msg_reserved = 0; |
1739 | out_hdr->sadb_msg_seq = count; | 1766 | out_hdr->sadb_msg_seq = count + 1; |
1740 | out_hdr->sadb_msg_pid = pfk->dump.msg_pid; | 1767 | out_hdr->sadb_msg_pid = pfk->dump.msg_pid; |
1741 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk); | 1768 | |
1769 | if (pfk->dump.skb) | ||
1770 | pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, | ||
1771 | &pfk->sk); | ||
1772 | pfk->dump.skb = out_skb; | ||
1773 | |||
1742 | return 0; | 1774 | return 0; |
1743 | } | 1775 | } |
1744 | 1776 | ||
@@ -2237,7 +2269,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h | |||
2237 | return 0; | 2269 | return 0; |
2238 | 2270 | ||
2239 | out: | 2271 | out: |
2240 | xp->dead = 1; | 2272 | xp->walk.dead = 1; |
2241 | xfrm_policy_destroy(xp); | 2273 | xfrm_policy_destroy(xp); |
2242 | return err; | 2274 | return err; |
2243 | } | 2275 | } |
@@ -2353,24 +2385,21 @@ static int pfkey_sockaddr_pair_size(sa_family_t family) | |||
2353 | return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2); | 2385 | return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2); |
2354 | } | 2386 | } |
2355 | 2387 | ||
2356 | static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq, | 2388 | static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len, |
2357 | xfrm_address_t *saddr, xfrm_address_t *daddr, | 2389 | xfrm_address_t *saddr, xfrm_address_t *daddr, |
2358 | u16 *family) | 2390 | u16 *family) |
2359 | { | 2391 | { |
2360 | u8 *sa = (u8 *) (rq + 1); | ||
2361 | int af, socklen; | 2392 | int af, socklen; |
2362 | 2393 | ||
2363 | if (rq->sadb_x_ipsecrequest_len < | 2394 | if (ext_len < pfkey_sockaddr_pair_size(sa->sa_family)) |
2364 | pfkey_sockaddr_pair_size(((struct sockaddr *)sa)->sa_family)) | ||
2365 | return -EINVAL; | 2395 | return -EINVAL; |
2366 | 2396 | ||
2367 | af = pfkey_sockaddr_extract((struct sockaddr *) sa, | 2397 | af = pfkey_sockaddr_extract(sa, saddr); |
2368 | saddr); | ||
2369 | if (!af) | 2398 | if (!af) |
2370 | return -EINVAL; | 2399 | return -EINVAL; |
2371 | 2400 | ||
2372 | socklen = pfkey_sockaddr_len(af); | 2401 | socklen = pfkey_sockaddr_len(af); |
2373 | if (pfkey_sockaddr_extract((struct sockaddr *) (sa + socklen), | 2402 | if (pfkey_sockaddr_extract((struct sockaddr *) (((u8 *)sa) + socklen), |
2374 | daddr) != af) | 2403 | daddr) != af) |
2375 | return -EINVAL; | 2404 | return -EINVAL; |
2376 | 2405 | ||
@@ -2390,7 +2419,9 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, | |||
2390 | return -EINVAL; | 2419 | return -EINVAL; |
2391 | 2420 | ||
2392 | /* old endoints */ | 2421 | /* old endoints */ |
2393 | err = parse_sockaddr_pair(rq1, &m->old_saddr, &m->old_daddr, | 2422 | err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1), |
2423 | rq1->sadb_x_ipsecrequest_len, | ||
2424 | &m->old_saddr, &m->old_daddr, | ||
2394 | &m->old_family); | 2425 | &m->old_family); |
2395 | if (err) | 2426 | if (err) |
2396 | return err; | 2427 | return err; |
@@ -2403,7 +2434,9 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, | |||
2403 | return -EINVAL; | 2434 | return -EINVAL; |
2404 | 2435 | ||
2405 | /* new endpoints */ | 2436 | /* new endpoints */ |
2406 | err = parse_sockaddr_pair(rq2, &m->new_saddr, &m->new_daddr, | 2437 | err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1), |
2438 | rq2->sadb_x_ipsecrequest_len, | ||
2439 | &m->new_saddr, &m->new_daddr, | ||
2407 | &m->new_family); | 2440 | &m->new_family); |
2408 | if (err) | 2441 | if (err) |
2409 | return err; | 2442 | return err; |
@@ -2429,29 +2462,40 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, | |||
2429 | int i, len, ret, err = -EINVAL; | 2462 | int i, len, ret, err = -EINVAL; |
2430 | u8 dir; | 2463 | u8 dir; |
2431 | struct sadb_address *sa; | 2464 | struct sadb_address *sa; |
2465 | struct sadb_x_kmaddress *kma; | ||
2432 | struct sadb_x_policy *pol; | 2466 | struct sadb_x_policy *pol; |
2433 | struct sadb_x_ipsecrequest *rq; | 2467 | struct sadb_x_ipsecrequest *rq; |
2434 | struct xfrm_selector sel; | 2468 | struct xfrm_selector sel; |
2435 | struct xfrm_migrate m[XFRM_MAX_DEPTH]; | 2469 | struct xfrm_migrate m[XFRM_MAX_DEPTH]; |
2470 | struct xfrm_kmaddress k; | ||
2436 | 2471 | ||
2437 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1], | 2472 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1], |
2438 | ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) || | 2473 | ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) || |
2439 | !ext_hdrs[SADB_X_EXT_POLICY - 1]) { | 2474 | !ext_hdrs[SADB_X_EXT_POLICY - 1]) { |
2440 | err = -EINVAL; | 2475 | err = -EINVAL; |
2441 | goto out; | 2476 | goto out; |
2442 | } | 2477 | } |
2443 | 2478 | ||
2479 | kma = ext_hdrs[SADB_X_EXT_KMADDRESS - 1]; | ||
2444 | pol = ext_hdrs[SADB_X_EXT_POLICY - 1]; | 2480 | pol = ext_hdrs[SADB_X_EXT_POLICY - 1]; |
2445 | if (!pol) { | ||
2446 | err = -EINVAL; | ||
2447 | goto out; | ||
2448 | } | ||
2449 | 2481 | ||
2450 | if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) { | 2482 | if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) { |
2451 | err = -EINVAL; | 2483 | err = -EINVAL; |
2452 | goto out; | 2484 | goto out; |
2453 | } | 2485 | } |
2454 | 2486 | ||
2487 | if (kma) { | ||
2488 | /* convert sadb_x_kmaddress to xfrm_kmaddress */ | ||
2489 | k.reserved = kma->sadb_x_kmaddress_reserved; | ||
2490 | ret = parse_sockaddr_pair((struct sockaddr *)(kma + 1), | ||
2491 | 8*(kma->sadb_x_kmaddress_len) - sizeof(*kma), | ||
2492 | &k.local, &k.remote, &k.family); | ||
2493 | if (ret < 0) { | ||
2494 | err = ret; | ||
2495 | goto out; | ||
2496 | } | ||
2497 | } | ||
2498 | |||
2455 | dir = pol->sadb_x_policy_dir - 1; | 2499 | dir = pol->sadb_x_policy_dir - 1; |
2456 | memset(&sel, 0, sizeof(sel)); | 2500 | memset(&sel, 0, sizeof(sel)); |
2457 | 2501 | ||
@@ -2496,7 +2540,8 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, | |||
2496 | goto out; | 2540 | goto out; |
2497 | } | 2541 | } |
2498 | 2542 | ||
2499 | return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i); | 2543 | return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i, |
2544 | kma ? &k : NULL); | ||
2500 | 2545 | ||
2501 | out: | 2546 | out: |
2502 | return err; | 2547 | return err; |
@@ -2575,9 +2620,14 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) | |||
2575 | out_hdr->sadb_msg_type = SADB_X_SPDDUMP; | 2620 | out_hdr->sadb_msg_type = SADB_X_SPDDUMP; |
2576 | out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; | 2621 | out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; |
2577 | out_hdr->sadb_msg_errno = 0; | 2622 | out_hdr->sadb_msg_errno = 0; |
2578 | out_hdr->sadb_msg_seq = count; | 2623 | out_hdr->sadb_msg_seq = count + 1; |
2579 | out_hdr->sadb_msg_pid = pfk->dump.msg_pid; | 2624 | out_hdr->sadb_msg_pid = pfk->dump.msg_pid; |
2580 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk); | 2625 | |
2626 | if (pfk->dump.skb) | ||
2627 | pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, | ||
2628 | &pfk->sk); | ||
2629 | pfk->dump.skb = out_skb; | ||
2630 | |||
2581 | return 0; | 2631 | return 0; |
2582 | } | 2632 | } |
2583 | 2633 | ||
@@ -3283,6 +3333,32 @@ static int set_sadb_address(struct sk_buff *skb, int sasize, int type, | |||
3283 | return 0; | 3333 | return 0; |
3284 | } | 3334 | } |
3285 | 3335 | ||
3336 | |||
3337 | static int set_sadb_kmaddress(struct sk_buff *skb, struct xfrm_kmaddress *k) | ||
3338 | { | ||
3339 | struct sadb_x_kmaddress *kma; | ||
3340 | u8 *sa; | ||
3341 | int family = k->family; | ||
3342 | int socklen = pfkey_sockaddr_len(family); | ||
3343 | int size_req; | ||
3344 | |||
3345 | size_req = (sizeof(struct sadb_x_kmaddress) + | ||
3346 | pfkey_sockaddr_pair_size(family)); | ||
3347 | |||
3348 | kma = (struct sadb_x_kmaddress *)skb_put(skb, size_req); | ||
3349 | memset(kma, 0, size_req); | ||
3350 | kma->sadb_x_kmaddress_len = size_req / 8; | ||
3351 | kma->sadb_x_kmaddress_exttype = SADB_X_EXT_KMADDRESS; | ||
3352 | kma->sadb_x_kmaddress_reserved = k->reserved; | ||
3353 | |||
3354 | sa = (u8 *)(kma + 1); | ||
3355 | if (!pfkey_sockaddr_fill(&k->local, 0, (struct sockaddr *)sa, family) || | ||
3356 | !pfkey_sockaddr_fill(&k->remote, 0, (struct sockaddr *)(sa+socklen), family)) | ||
3357 | return -EINVAL; | ||
3358 | |||
3359 | return 0; | ||
3360 | } | ||
3361 | |||
3286 | static int set_ipsecrequest(struct sk_buff *skb, | 3362 | static int set_ipsecrequest(struct sk_buff *skb, |
3287 | uint8_t proto, uint8_t mode, int level, | 3363 | uint8_t proto, uint8_t mode, int level, |
3288 | uint32_t reqid, uint8_t family, | 3364 | uint32_t reqid, uint8_t family, |
@@ -3315,7 +3391,8 @@ static int set_ipsecrequest(struct sk_buff *skb, | |||
3315 | 3391 | ||
3316 | #ifdef CONFIG_NET_KEY_MIGRATE | 3392 | #ifdef CONFIG_NET_KEY_MIGRATE |
3317 | static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 3393 | static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
3318 | struct xfrm_migrate *m, int num_bundles) | 3394 | struct xfrm_migrate *m, int num_bundles, |
3395 | struct xfrm_kmaddress *k) | ||
3319 | { | 3396 | { |
3320 | int i; | 3397 | int i; |
3321 | int sasize_sel; | 3398 | int sasize_sel; |
@@ -3332,6 +3409,12 @@ static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | |||
3332 | if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH) | 3409 | if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH) |
3333 | return -EINVAL; | 3410 | return -EINVAL; |
3334 | 3411 | ||
3412 | if (k != NULL) { | ||
3413 | /* addresses for KM */ | ||
3414 | size += PFKEY_ALIGN8(sizeof(struct sadb_x_kmaddress) + | ||
3415 | pfkey_sockaddr_pair_size(k->family)); | ||
3416 | } | ||
3417 | |||
3335 | /* selector */ | 3418 | /* selector */ |
3336 | sasize_sel = pfkey_sockaddr_size(sel->family); | 3419 | sasize_sel = pfkey_sockaddr_size(sel->family); |
3337 | if (!sasize_sel) | 3420 | if (!sasize_sel) |
@@ -3368,6 +3451,10 @@ static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | |||
3368 | hdr->sadb_msg_seq = 0; | 3451 | hdr->sadb_msg_seq = 0; |
3369 | hdr->sadb_msg_pid = 0; | 3452 | hdr->sadb_msg_pid = 0; |
3370 | 3453 | ||
3454 | /* Addresses to be used by KM for negotiation, if ext is available */ | ||
3455 | if (k != NULL && (set_sadb_kmaddress(skb, k) < 0)) | ||
3456 | return -EINVAL; | ||
3457 | |||
3371 | /* selector src */ | 3458 | /* selector src */ |
3372 | set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel); | 3459 | set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel); |
3373 | 3460 | ||
@@ -3413,7 +3500,8 @@ err: | |||
3413 | } | 3500 | } |
3414 | #else | 3501 | #else |
3415 | static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 3502 | static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
3416 | struct xfrm_migrate *m, int num_bundles) | 3503 | struct xfrm_migrate *m, int num_bundles, |
3504 | struct xfrm_kmaddress *k) | ||
3417 | { | 3505 | { |
3418 | return -ENOPROTOOPT; | 3506 | return -ENOPROTOOPT; |
3419 | } | 3507 | } |