diff options
Diffstat (limited to 'net/key/af_key.c')
-rw-r--r-- | net/key/af_key.c | 143 |
1 files changed, 110 insertions, 33 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c index e9ef9af4a53b..1fb0fe42a72e 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -48,6 +48,17 @@ struct pfkey_sock { | |||
48 | struct sock sk; | 48 | struct sock sk; |
49 | int registered; | 49 | int registered; |
50 | int promisc; | 50 | int promisc; |
51 | |||
52 | struct { | ||
53 | uint8_t msg_version; | ||
54 | uint32_t msg_pid; | ||
55 | int (*dump)(struct pfkey_sock *sk); | ||
56 | void (*done)(struct pfkey_sock *sk); | ||
57 | union { | ||
58 | struct xfrm_policy_walk policy; | ||
59 | struct xfrm_state_walk state; | ||
60 | } u; | ||
61 | } dump; | ||
51 | }; | 62 | }; |
52 | 63 | ||
53 | static inline struct pfkey_sock *pfkey_sk(struct sock *sk) | 64 | static inline struct pfkey_sock *pfkey_sk(struct sock *sk) |
@@ -55,6 +66,27 @@ static inline struct pfkey_sock *pfkey_sk(struct sock *sk) | |||
55 | return (struct pfkey_sock *)sk; | 66 | return (struct pfkey_sock *)sk; |
56 | } | 67 | } |
57 | 68 | ||
69 | static int pfkey_can_dump(struct sock *sk) | ||
70 | { | ||
71 | if (3 * atomic_read(&sk->sk_rmem_alloc) <= 2 * sk->sk_rcvbuf) | ||
72 | return 1; | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int pfkey_do_dump(struct pfkey_sock *pfk) | ||
77 | { | ||
78 | int rc; | ||
79 | |||
80 | rc = pfk->dump.dump(pfk); | ||
81 | if (rc == -ENOBUFS) | ||
82 | return 0; | ||
83 | |||
84 | pfk->dump.done(pfk); | ||
85 | pfk->dump.dump = NULL; | ||
86 | pfk->dump.done = NULL; | ||
87 | return rc; | ||
88 | } | ||
89 | |||
58 | static void pfkey_sock_destruct(struct sock *sk) | 90 | static void pfkey_sock_destruct(struct sock *sk) |
59 | { | 91 | { |
60 | skb_queue_purge(&sk->sk_receive_queue); | 92 | skb_queue_purge(&sk->sk_receive_queue); |
@@ -1709,45 +1741,60 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd | |||
1709 | return 0; | 1741 | return 0; |
1710 | } | 1742 | } |
1711 | 1743 | ||
1712 | struct pfkey_dump_data | ||
1713 | { | ||
1714 | struct sk_buff *skb; | ||
1715 | struct sadb_msg *hdr; | ||
1716 | struct sock *sk; | ||
1717 | }; | ||
1718 | |||
1719 | static int dump_sa(struct xfrm_state *x, int count, void *ptr) | 1744 | static int dump_sa(struct xfrm_state *x, int count, void *ptr) |
1720 | { | 1745 | { |
1721 | struct pfkey_dump_data *data = ptr; | 1746 | struct pfkey_sock *pfk = ptr; |
1722 | struct sk_buff *out_skb; | 1747 | struct sk_buff *out_skb; |
1723 | struct sadb_msg *out_hdr; | 1748 | struct sadb_msg *out_hdr; |
1724 | 1749 | ||
1750 | if (!pfkey_can_dump(&pfk->sk)) | ||
1751 | return -ENOBUFS; | ||
1752 | |||
1725 | out_skb = pfkey_xfrm_state2msg(x); | 1753 | out_skb = pfkey_xfrm_state2msg(x); |
1726 | if (IS_ERR(out_skb)) | 1754 | if (IS_ERR(out_skb)) |
1727 | return PTR_ERR(out_skb); | 1755 | return PTR_ERR(out_skb); |
1728 | 1756 | ||
1729 | out_hdr = (struct sadb_msg *) out_skb->data; | 1757 | out_hdr = (struct sadb_msg *) out_skb->data; |
1730 | out_hdr->sadb_msg_version = data->hdr->sadb_msg_version; | 1758 | out_hdr->sadb_msg_version = pfk->dump.msg_version; |
1731 | out_hdr->sadb_msg_type = SADB_DUMP; | 1759 | out_hdr->sadb_msg_type = SADB_DUMP; |
1732 | out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); | 1760 | out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); |
1733 | out_hdr->sadb_msg_errno = 0; | 1761 | out_hdr->sadb_msg_errno = 0; |
1734 | out_hdr->sadb_msg_reserved = 0; | 1762 | out_hdr->sadb_msg_reserved = 0; |
1735 | out_hdr->sadb_msg_seq = count; | 1763 | out_hdr->sadb_msg_seq = count; |
1736 | out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid; | 1764 | out_hdr->sadb_msg_pid = pfk->dump.msg_pid; |
1737 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); | 1765 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk); |
1738 | return 0; | 1766 | return 0; |
1739 | } | 1767 | } |
1740 | 1768 | ||
1769 | static int pfkey_dump_sa(struct pfkey_sock *pfk) | ||
1770 | { | ||
1771 | return xfrm_state_walk(&pfk->dump.u.state, dump_sa, (void *) pfk); | ||
1772 | } | ||
1773 | |||
1774 | static void pfkey_dump_sa_done(struct pfkey_sock *pfk) | ||
1775 | { | ||
1776 | xfrm_state_walk_done(&pfk->dump.u.state); | ||
1777 | } | ||
1778 | |||
1741 | static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 1779 | static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) |
1742 | { | 1780 | { |
1743 | u8 proto; | 1781 | u8 proto; |
1744 | struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; | 1782 | struct pfkey_sock *pfk = pfkey_sk(sk); |
1783 | |||
1784 | if (pfk->dump.dump != NULL) | ||
1785 | return -EBUSY; | ||
1745 | 1786 | ||
1746 | proto = pfkey_satype2proto(hdr->sadb_msg_satype); | 1787 | proto = pfkey_satype2proto(hdr->sadb_msg_satype); |
1747 | if (proto == 0) | 1788 | if (proto == 0) |
1748 | return -EINVAL; | 1789 | return -EINVAL; |
1749 | 1790 | ||
1750 | return xfrm_state_walk(proto, dump_sa, &data); | 1791 | pfk->dump.msg_version = hdr->sadb_msg_version; |
1792 | pfk->dump.msg_pid = hdr->sadb_msg_pid; | ||
1793 | pfk->dump.dump = pfkey_dump_sa; | ||
1794 | pfk->dump.done = pfkey_dump_sa_done; | ||
1795 | xfrm_state_walk_init(&pfk->dump.u.state, proto); | ||
1796 | |||
1797 | return pfkey_do_dump(pfk); | ||
1751 | } | 1798 | } |
1752 | 1799 | ||
1753 | static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 1800 | static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) |
@@ -1780,7 +1827,9 @@ static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr) | |||
1780 | 1827 | ||
1781 | static u32 gen_reqid(void) | 1828 | static u32 gen_reqid(void) |
1782 | { | 1829 | { |
1830 | struct xfrm_policy_walk walk; | ||
1783 | u32 start; | 1831 | u32 start; |
1832 | int rc; | ||
1784 | static u32 reqid = IPSEC_MANUAL_REQID_MAX; | 1833 | static u32 reqid = IPSEC_MANUAL_REQID_MAX; |
1785 | 1834 | ||
1786 | start = reqid; | 1835 | start = reqid; |
@@ -1788,8 +1837,10 @@ static u32 gen_reqid(void) | |||
1788 | ++reqid; | 1837 | ++reqid; |
1789 | if (reqid == 0) | 1838 | if (reqid == 0) |
1790 | reqid = IPSEC_MANUAL_REQID_MAX+1; | 1839 | reqid = IPSEC_MANUAL_REQID_MAX+1; |
1791 | if (xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, check_reqid, | 1840 | xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); |
1792 | (void*)&reqid) != -EEXIST) | 1841 | rc = xfrm_policy_walk(&walk, check_reqid, (void*)&reqid); |
1842 | xfrm_policy_walk_done(&walk); | ||
1843 | if (rc != -EEXIST) | ||
1793 | return reqid; | 1844 | return reqid; |
1794 | } while (reqid != start); | 1845 | } while (reqid != start); |
1795 | return 0; | 1846 | return 0; |
@@ -2241,7 +2292,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h | |||
2241 | goto out; | 2292 | goto out; |
2242 | } | 2293 | } |
2243 | 2294 | ||
2244 | err = security_xfrm_policy_alloc(xp, uctx); | 2295 | err = security_xfrm_policy_alloc(&xp->security, uctx); |
2245 | kfree(uctx); | 2296 | kfree(uctx); |
2246 | 2297 | ||
2247 | if (err) | 2298 | if (err) |
@@ -2301,10 +2352,11 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg | |||
2301 | int err; | 2352 | int err; |
2302 | struct sadb_address *sa; | 2353 | struct sadb_address *sa; |
2303 | struct sadb_x_policy *pol; | 2354 | struct sadb_x_policy *pol; |
2304 | struct xfrm_policy *xp, tmp; | 2355 | struct xfrm_policy *xp; |
2305 | struct xfrm_selector sel; | 2356 | struct xfrm_selector sel; |
2306 | struct km_event c; | 2357 | struct km_event c; |
2307 | struct sadb_x_sec_ctx *sec_ctx; | 2358 | struct sadb_x_sec_ctx *sec_ctx; |
2359 | struct xfrm_sec_ctx *pol_ctx; | ||
2308 | 2360 | ||
2309 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], | 2361 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], |
2310 | ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || | 2362 | ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || |
@@ -2334,25 +2386,23 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg | |||
2334 | sel.dport_mask = htons(0xffff); | 2386 | sel.dport_mask = htons(0xffff); |
2335 | 2387 | ||
2336 | sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; | 2388 | sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; |
2337 | memset(&tmp, 0, sizeof(struct xfrm_policy)); | ||
2338 | |||
2339 | if (sec_ctx != NULL) { | 2389 | if (sec_ctx != NULL) { |
2340 | struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); | 2390 | struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); |
2341 | 2391 | ||
2342 | if (!uctx) | 2392 | if (!uctx) |
2343 | return -ENOMEM; | 2393 | return -ENOMEM; |
2344 | 2394 | ||
2345 | err = security_xfrm_policy_alloc(&tmp, uctx); | 2395 | err = security_xfrm_policy_alloc(&pol_ctx, uctx); |
2346 | kfree(uctx); | 2396 | kfree(uctx); |
2347 | |||
2348 | if (err) | 2397 | if (err) |
2349 | return err; | 2398 | return err; |
2350 | } | 2399 | } else |
2351 | 2400 | pol_ctx = NULL; | |
2352 | xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, pol->sadb_x_policy_dir-1, | ||
2353 | &sel, tmp.security, 1, &err); | ||
2354 | security_xfrm_policy_free(&tmp); | ||
2355 | 2401 | ||
2402 | xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, | ||
2403 | pol->sadb_x_policy_dir - 1, &sel, pol_ctx, | ||
2404 | 1, &err); | ||
2405 | security_xfrm_policy_free(pol_ctx); | ||
2356 | if (xp == NULL) | 2406 | if (xp == NULL) |
2357 | return -ENOENT; | 2407 | return -ENOENT; |
2358 | 2408 | ||
@@ -2638,11 +2688,14 @@ out: | |||
2638 | 2688 | ||
2639 | static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) | 2689 | static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) |
2640 | { | 2690 | { |
2641 | struct pfkey_dump_data *data = ptr; | 2691 | struct pfkey_sock *pfk = ptr; |
2642 | struct sk_buff *out_skb; | 2692 | struct sk_buff *out_skb; |
2643 | struct sadb_msg *out_hdr; | 2693 | struct sadb_msg *out_hdr; |
2644 | int err; | 2694 | int err; |
2645 | 2695 | ||
2696 | if (!pfkey_can_dump(&pfk->sk)) | ||
2697 | return -ENOBUFS; | ||
2698 | |||
2646 | out_skb = pfkey_xfrm_policy2msg_prep(xp); | 2699 | out_skb = pfkey_xfrm_policy2msg_prep(xp); |
2647 | if (IS_ERR(out_skb)) | 2700 | if (IS_ERR(out_skb)) |
2648 | return PTR_ERR(out_skb); | 2701 | return PTR_ERR(out_skb); |
@@ -2652,21 +2705,40 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) | |||
2652 | return err; | 2705 | return err; |
2653 | 2706 | ||
2654 | out_hdr = (struct sadb_msg *) out_skb->data; | 2707 | out_hdr = (struct sadb_msg *) out_skb->data; |
2655 | out_hdr->sadb_msg_version = data->hdr->sadb_msg_version; | 2708 | out_hdr->sadb_msg_version = pfk->dump.msg_version; |
2656 | out_hdr->sadb_msg_type = SADB_X_SPDDUMP; | 2709 | out_hdr->sadb_msg_type = SADB_X_SPDDUMP; |
2657 | out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; | 2710 | out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; |
2658 | out_hdr->sadb_msg_errno = 0; | 2711 | out_hdr->sadb_msg_errno = 0; |
2659 | out_hdr->sadb_msg_seq = count; | 2712 | out_hdr->sadb_msg_seq = count; |
2660 | out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid; | 2713 | out_hdr->sadb_msg_pid = pfk->dump.msg_pid; |
2661 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); | 2714 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk); |
2662 | return 0; | 2715 | return 0; |
2663 | } | 2716 | } |
2664 | 2717 | ||
2718 | static int pfkey_dump_sp(struct pfkey_sock *pfk) | ||
2719 | { | ||
2720 | return xfrm_policy_walk(&pfk->dump.u.policy, dump_sp, (void *) pfk); | ||
2721 | } | ||
2722 | |||
2723 | static void pfkey_dump_sp_done(struct pfkey_sock *pfk) | ||
2724 | { | ||
2725 | xfrm_policy_walk_done(&pfk->dump.u.policy); | ||
2726 | } | ||
2727 | |||
2665 | static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 2728 | static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) |
2666 | { | 2729 | { |
2667 | struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; | 2730 | struct pfkey_sock *pfk = pfkey_sk(sk); |
2731 | |||
2732 | if (pfk->dump.dump != NULL) | ||
2733 | return -EBUSY; | ||
2734 | |||
2735 | pfk->dump.msg_version = hdr->sadb_msg_version; | ||
2736 | pfk->dump.msg_pid = hdr->sadb_msg_pid; | ||
2737 | pfk->dump.dump = pfkey_dump_sp; | ||
2738 | pfk->dump.done = pfkey_dump_sp_done; | ||
2739 | xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN); | ||
2668 | 2740 | ||
2669 | return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data); | 2741 | return pfkey_do_dump(pfk); |
2670 | } | 2742 | } |
2671 | 2743 | ||
2672 | static int key_notify_policy_flush(struct km_event *c) | 2744 | static int key_notify_policy_flush(struct km_event *c) |
@@ -3225,7 +3297,7 @@ static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, | |||
3225 | if ((*dir = verify_sec_ctx_len(p))) | 3297 | if ((*dir = verify_sec_ctx_len(p))) |
3226 | goto out; | 3298 | goto out; |
3227 | uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); | 3299 | uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); |
3228 | *dir = security_xfrm_policy_alloc(xp, uctx); | 3300 | *dir = security_xfrm_policy_alloc(&xp->security, uctx); |
3229 | kfree(uctx); | 3301 | kfree(uctx); |
3230 | 3302 | ||
3231 | if (*dir) | 3303 | if (*dir) |
@@ -3671,6 +3743,7 @@ static int pfkey_recvmsg(struct kiocb *kiocb, | |||
3671 | int flags) | 3743 | int flags) |
3672 | { | 3744 | { |
3673 | struct sock *sk = sock->sk; | 3745 | struct sock *sk = sock->sk; |
3746 | struct pfkey_sock *pfk = pfkey_sk(sk); | ||
3674 | struct sk_buff *skb; | 3747 | struct sk_buff *skb; |
3675 | int copied, err; | 3748 | int copied, err; |
3676 | 3749 | ||
@@ -3698,6 +3771,10 @@ static int pfkey_recvmsg(struct kiocb *kiocb, | |||
3698 | 3771 | ||
3699 | err = (flags & MSG_TRUNC) ? skb->len : copied; | 3772 | err = (flags & MSG_TRUNC) ? skb->len : copied; |
3700 | 3773 | ||
3774 | if (pfk->dump.dump != NULL && | ||
3775 | 3 * atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) | ||
3776 | pfkey_do_dump(pfk); | ||
3777 | |||
3701 | out_free: | 3778 | out_free: |
3702 | skb_free_datagram(sk, skb); | 3779 | skb_free_datagram(sk, skb); |
3703 | out: | 3780 | out: |