summaryrefslogtreecommitdiffstats
path: root/net/key
diff options
context:
space:
mode:
authorYuejie Shi <syjcnss@gmail.com>2017-03-31 03:10:20 -0400
committerSteffen Klassert <steffen.klassert@secunet.com>2017-04-03 02:05:17 -0400
commit89e357d83c06b6fac581c3ca7f0ee3ae7e67109e (patch)
tree95c3425ed24cca1ce0b806197c690ca42c1be36b /net/key
parent75514b6654859e0130b512396dc964d2a9e84967 (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.c46
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
68static inline struct pfkey_sock *pfkey_sk(struct sock *sk) 69static 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
317out:
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}