diff options
author | Yuejie Shi <syjcnss@gmail.com> | 2017-03-31 03:10:20 -0400 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2017-04-03 02:05:17 -0400 |
commit | 89e357d83c06b6fac581c3ca7f0ee3ae7e67109e (patch) | |
tree | 95c3425ed24cca1ce0b806197c690ca42c1be36b /net/key | |
parent | 75514b6654859e0130b512396dc964d2a9e84967 (diff) |
af_key: Add lock to key dump
A dump may come in the middle of another dump, modifying its dump
structure members. This race condition will result in NULL pointer
dereference in kernel. So add a lock to prevent that race.
Fixes: 83321d6b9872 ("[AF_KEY]: Dump SA/SP entries non-atomically")
Signed-off-by: Yuejie Shi <syjcnss@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net/key')
-rw-r--r-- | net/key/af_key.c | 46 |
1 files changed, 38 insertions, 8 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c index c6252ed42c1d..1b0ea80133f1 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -63,6 +63,7 @@ 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 | ||
68 | static inline struct pfkey_sock *pfkey_sk(struct sock *sk) | 69 | static inline struct pfkey_sock *pfkey_sk(struct sock *sk) |
@@ -139,6 +140,7 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol, | |||
139 | { | 140 | { |
140 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); | 141 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); |
141 | struct sock *sk; | 142 | struct sock *sk; |
143 | struct pfkey_sock *pfk; | ||
142 | int err; | 144 | int err; |
143 | 145 | ||
144 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) | 146 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
@@ -153,6 +155,9 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol, | |||
153 | if (sk == NULL) | 155 | if (sk == NULL) |
154 | goto out; | 156 | goto out; |
155 | 157 | ||
158 | pfk = pfkey_sk(sk); | ||
159 | mutex_init(&pfk->dump_lock); | ||
160 | |||
156 | sock->ops = &pfkey_ops; | 161 | sock->ops = &pfkey_ops; |
157 | sock_init_data(sock, sk); | 162 | sock_init_data(sock, sk); |
158 | 163 | ||
@@ -281,13 +286,23 @@ static int pfkey_do_dump(struct pfkey_sock *pfk) | |||
281 | struct sadb_msg *hdr; | 286 | struct sadb_msg *hdr; |
282 | int rc; | 287 | int rc; |
283 | 288 | ||
289 | mutex_lock(&pfk->dump_lock); | ||
290 | if (!pfk->dump.dump) { | ||
291 | rc = 0; | ||
292 | goto out; | ||
293 | } | ||
294 | |||
284 | rc = pfk->dump.dump(pfk); | 295 | rc = pfk->dump.dump(pfk); |
285 | if (rc == -ENOBUFS) | 296 | if (rc == -ENOBUFS) { |
286 | return 0; | 297 | rc = 0; |
298 | goto out; | ||
299 | } | ||
287 | 300 | ||
288 | if (pfk->dump.skb) { | 301 | if (pfk->dump.skb) { |
289 | if (!pfkey_can_dump(&pfk->sk)) | 302 | if (!pfkey_can_dump(&pfk->sk)) { |
290 | return 0; | 303 | rc = 0; |
304 | goto out; | ||
305 | } | ||
291 | 306 | ||
292 | hdr = (struct sadb_msg *) pfk->dump.skb->data; | 307 | hdr = (struct sadb_msg *) pfk->dump.skb->data; |
293 | hdr->sadb_msg_seq = 0; | 308 | hdr->sadb_msg_seq = 0; |
@@ -298,6 +313,9 @@ static int pfkey_do_dump(struct pfkey_sock *pfk) | |||
298 | } | 313 | } |
299 | 314 | ||
300 | pfkey_terminate_dump(pfk); | 315 | pfkey_terminate_dump(pfk); |
316 | |||
317 | out: | ||
318 | mutex_unlock(&pfk->dump_lock); | ||
301 | return rc; | 319 | return rc; |
302 | } | 320 | } |
303 | 321 | ||
@@ -1793,19 +1811,26 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_ms | |||
1793 | struct xfrm_address_filter *filter = NULL; | 1811 | struct xfrm_address_filter *filter = NULL; |
1794 | struct pfkey_sock *pfk = pfkey_sk(sk); | 1812 | struct pfkey_sock *pfk = pfkey_sk(sk); |
1795 | 1813 | ||
1796 | if (pfk->dump.dump != NULL) | 1814 | mutex_lock(&pfk->dump_lock); |
1815 | if (pfk->dump.dump != NULL) { | ||
1816 | mutex_unlock(&pfk->dump_lock); | ||
1797 | return -EBUSY; | 1817 | return -EBUSY; |
1818 | } | ||
1798 | 1819 | ||
1799 | proto = pfkey_satype2proto(hdr->sadb_msg_satype); | 1820 | proto = pfkey_satype2proto(hdr->sadb_msg_satype); |
1800 | if (proto == 0) | 1821 | if (proto == 0) { |
1822 | mutex_unlock(&pfk->dump_lock); | ||
1801 | return -EINVAL; | 1823 | return -EINVAL; |
1824 | } | ||
1802 | 1825 | ||
1803 | if (ext_hdrs[SADB_X_EXT_FILTER - 1]) { | 1826 | if (ext_hdrs[SADB_X_EXT_FILTER - 1]) { |
1804 | struct sadb_x_filter *xfilter = ext_hdrs[SADB_X_EXT_FILTER - 1]; | 1827 | struct sadb_x_filter *xfilter = ext_hdrs[SADB_X_EXT_FILTER - 1]; |
1805 | 1828 | ||
1806 | filter = kmalloc(sizeof(*filter), GFP_KERNEL); | 1829 | filter = kmalloc(sizeof(*filter), GFP_KERNEL); |
1807 | if (filter == NULL) | 1830 | if (filter == NULL) { |
1831 | mutex_unlock(&pfk->dump_lock); | ||
1808 | return -ENOMEM; | 1832 | return -ENOMEM; |
1833 | } | ||
1809 | 1834 | ||
1810 | memcpy(&filter->saddr, &xfilter->sadb_x_filter_saddr, | 1835 | memcpy(&filter->saddr, &xfilter->sadb_x_filter_saddr, |
1811 | sizeof(xfrm_address_t)); | 1836 | sizeof(xfrm_address_t)); |
@@ -1821,6 +1846,7 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_ms | |||
1821 | pfk->dump.dump = pfkey_dump_sa; | 1846 | pfk->dump.dump = pfkey_dump_sa; |
1822 | pfk->dump.done = pfkey_dump_sa_done; | 1847 | pfk->dump.done = pfkey_dump_sa_done; |
1823 | xfrm_state_walk_init(&pfk->dump.u.state, proto, filter); | 1848 | xfrm_state_walk_init(&pfk->dump.u.state, proto, filter); |
1849 | mutex_unlock(&pfk->dump_lock); | ||
1824 | 1850 | ||
1825 | return pfkey_do_dump(pfk); | 1851 | return pfkey_do_dump(pfk); |
1826 | } | 1852 | } |
@@ -2679,14 +2705,18 @@ static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb | |||
2679 | { | 2705 | { |
2680 | struct pfkey_sock *pfk = pfkey_sk(sk); | 2706 | struct pfkey_sock *pfk = pfkey_sk(sk); |
2681 | 2707 | ||
2682 | if (pfk->dump.dump != NULL) | 2708 | mutex_lock(&pfk->dump_lock); |
2709 | if (pfk->dump.dump != NULL) { | ||
2710 | mutex_unlock(&pfk->dump_lock); | ||
2683 | return -EBUSY; | 2711 | return -EBUSY; |
2712 | } | ||
2684 | 2713 | ||
2685 | pfk->dump.msg_version = hdr->sadb_msg_version; | 2714 | pfk->dump.msg_version = hdr->sadb_msg_version; |
2686 | pfk->dump.msg_portid = hdr->sadb_msg_pid; | 2715 | pfk->dump.msg_portid = hdr->sadb_msg_pid; |
2687 | pfk->dump.dump = pfkey_dump_sp; | 2716 | pfk->dump.dump = pfkey_dump_sp; |
2688 | pfk->dump.done = pfkey_dump_sp_done; | 2717 | pfk->dump.done = pfkey_dump_sp_done; |
2689 | xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN); | 2718 | xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN); |
2719 | mutex_unlock(&pfk->dump_lock); | ||
2690 | 2720 | ||
2691 | return pfkey_do_dump(pfk); | 2721 | return pfkey_do_dump(pfk); |
2692 | } | 2722 | } |