diff options
author | David Ahern <dsa@cumulusnetworks.com> | 2015-08-24 17:17:17 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-08-24 17:48:10 -0400 |
commit | ba51b6be38c122f7dab40965b4397aaf6188a464 (patch) | |
tree | 0a6558d48be086558e55f083261148f55632c61a /net/key | |
parent | b6df7d61c8776a882dd47ba4714d1445dd7ef2d9 (diff) |
net: Fix RCU splat in af_key
Hit the following splat testing VRF change for ipsec:
[ 113.475692] ===============================
[ 113.476194] [ INFO: suspicious RCU usage. ]
[ 113.476667] 4.2.0-rc6-1+deb7u2+clUNRELEASED #3.2.65-1+deb7u2+clUNRELEASED Not tainted
[ 113.477545] -------------------------------
[ 113.478013] /work/monster-14/dsa/kernel.git/include/linux/rcupdate.h:568 Illegal context switch in RCU read-side critical section!
[ 113.479288]
[ 113.479288] other info that might help us debug this:
[ 113.479288]
[ 113.480207]
[ 113.480207] rcu_scheduler_active = 1, debug_locks = 1
[ 113.480931] 2 locks held by setkey/6829:
[ 113.481371] #0: (&net->xfrm.xfrm_cfg_mutex){+.+.+.}, at: [<ffffffff814e9887>] pfkey_sendmsg+0xfb/0x213
[ 113.482509] #1: (rcu_read_lock){......}, at: [<ffffffff814e767f>] rcu_read_lock+0x0/0x6e
[ 113.483509]
[ 113.483509] stack backtrace:
[ 113.484041] CPU: 0 PID: 6829 Comm: setkey Not tainted 4.2.0-rc6-1+deb7u2+clUNRELEASED #3.2.65-1+deb7u2+clUNRELEASED
[ 113.485422] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5.1-0-g8936dbb-20141113_115728-nilsson.home.kraxel.org 04/01/2014
[ 113.486845] 0000000000000001 ffff88001d4c7a98 ffffffff81518af2 ffffffff81086962
[ 113.487732] ffff88001d538480 ffff88001d4c7ac8 ffffffff8107ae75 ffffffff8180a154
[ 113.488628] 0000000000000b30 0000000000000000 00000000000000d0 ffff88001d4c7ad8
[ 113.489525] Call Trace:
[ 113.489813] [<ffffffff81518af2>] dump_stack+0x4c/0x65
[ 113.490389] [<ffffffff81086962>] ? console_unlock+0x3d6/0x405
[ 113.491039] [<ffffffff8107ae75>] lockdep_rcu_suspicious+0xfa/0x103
[ 113.491735] [<ffffffff81064032>] rcu_preempt_sleep_check+0x45/0x47
[ 113.492442] [<ffffffff8106404d>] ___might_sleep+0x19/0x1c8
[ 113.493077] [<ffffffff81064268>] __might_sleep+0x6c/0x82
[ 113.493681] [<ffffffff81133190>] cache_alloc_debugcheck_before.isra.50+0x1d/0x24
[ 113.494508] [<ffffffff81134876>] kmem_cache_alloc+0x31/0x18f
[ 113.495149] [<ffffffff814012b5>] skb_clone+0x64/0x80
[ 113.495712] [<ffffffff814e6f71>] pfkey_broadcast_one+0x3d/0xff
[ 113.496380] [<ffffffff814e7b84>] pfkey_broadcast+0xb5/0x11e
[ 113.497024] [<ffffffff814e82d1>] pfkey_register+0x191/0x1b1
[ 113.497653] [<ffffffff814e9770>] pfkey_process+0x162/0x17e
[ 113.498274] [<ffffffff814e9895>] pfkey_sendmsg+0x109/0x213
In pfkey_sendmsg the net mutex is taken and then pfkey_broadcast takes
the RCU lock.
Since pfkey_broadcast takes the RCU lock the allocation argument is
pointless since GFP_ATOMIC must be used between the rcu_read_{,un}lock.
The one call outside of rcu can be done with GFP_KERNEL.
Fixes: 7f6b9dbd5afbd ("af_key: locking change")
Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/key')
-rw-r--r-- | net/key/af_key.c | 46 |
1 files changed, 23 insertions, 23 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c index b397f0aa9005..83a70688784b 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -219,7 +219,7 @@ static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2, | |||
219 | #define BROADCAST_ONE 1 | 219 | #define BROADCAST_ONE 1 |
220 | #define BROADCAST_REGISTERED 2 | 220 | #define BROADCAST_REGISTERED 2 |
221 | #define BROADCAST_PROMISC_ONLY 4 | 221 | #define BROADCAST_PROMISC_ONLY 4 |
222 | static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, | 222 | static int pfkey_broadcast(struct sk_buff *skb, |
223 | int broadcast_flags, struct sock *one_sk, | 223 | int broadcast_flags, struct sock *one_sk, |
224 | struct net *net) | 224 | struct net *net) |
225 | { | 225 | { |
@@ -244,7 +244,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, | |||
244 | * socket. | 244 | * socket. |
245 | */ | 245 | */ |
246 | if (pfk->promisc) | 246 | if (pfk->promisc) |
247 | pfkey_broadcast_one(skb, &skb2, allocation, sk); | 247 | pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk); |
248 | 248 | ||
249 | /* the exact target will be processed later */ | 249 | /* the exact target will be processed later */ |
250 | if (sk == one_sk) | 250 | if (sk == one_sk) |
@@ -259,7 +259,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, | |||
259 | continue; | 259 | continue; |
260 | } | 260 | } |
261 | 261 | ||
262 | err2 = pfkey_broadcast_one(skb, &skb2, allocation, sk); | 262 | err2 = pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk); |
263 | 263 | ||
264 | /* Error is cleare after succecful sending to at least one | 264 | /* Error is cleare after succecful sending to at least one |
265 | * registered KM */ | 265 | * registered KM */ |
@@ -269,7 +269,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, | |||
269 | rcu_read_unlock(); | 269 | rcu_read_unlock(); |
270 | 270 | ||
271 | if (one_sk != NULL) | 271 | if (one_sk != NULL) |
272 | err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk); | 272 | err = pfkey_broadcast_one(skb, &skb2, GFP_KERNEL, one_sk); |
273 | 273 | ||
274 | kfree_skb(skb2); | 274 | kfree_skb(skb2); |
275 | kfree_skb(skb); | 275 | kfree_skb(skb); |
@@ -292,7 +292,7 @@ static int pfkey_do_dump(struct pfkey_sock *pfk) | |||
292 | hdr = (struct sadb_msg *) pfk->dump.skb->data; | 292 | hdr = (struct sadb_msg *) pfk->dump.skb->data; |
293 | hdr->sadb_msg_seq = 0; | 293 | hdr->sadb_msg_seq = 0; |
294 | hdr->sadb_msg_errno = rc; | 294 | hdr->sadb_msg_errno = rc; |
295 | pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, | 295 | pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE, |
296 | &pfk->sk, sock_net(&pfk->sk)); | 296 | &pfk->sk, sock_net(&pfk->sk)); |
297 | pfk->dump.skb = NULL; | 297 | pfk->dump.skb = NULL; |
298 | } | 298 | } |
@@ -333,7 +333,7 @@ static int pfkey_error(const struct sadb_msg *orig, int err, struct sock *sk) | |||
333 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / | 333 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / |
334 | sizeof(uint64_t)); | 334 | sizeof(uint64_t)); |
335 | 335 | ||
336 | pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk, sock_net(sk)); | 336 | pfkey_broadcast(skb, BROADCAST_ONE, sk, sock_net(sk)); |
337 | 337 | ||
338 | return 0; | 338 | return 0; |
339 | } | 339 | } |
@@ -1365,7 +1365,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, const struct sadb_ | |||
1365 | 1365 | ||
1366 | xfrm_state_put(x); | 1366 | xfrm_state_put(x); |
1367 | 1367 | ||
1368 | pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk, net); | 1368 | pfkey_broadcast(resp_skb, BROADCAST_ONE, sk, net); |
1369 | 1369 | ||
1370 | return 0; | 1370 | return 0; |
1371 | } | 1371 | } |
@@ -1452,7 +1452,7 @@ static int key_notify_sa(struct xfrm_state *x, const struct km_event *c) | |||
1452 | hdr->sadb_msg_seq = c->seq; | 1452 | hdr->sadb_msg_seq = c->seq; |
1453 | hdr->sadb_msg_pid = c->portid; | 1453 | hdr->sadb_msg_pid = c->portid; |
1454 | 1454 | ||
1455 | pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xs_net(x)); | 1455 | pfkey_broadcast(skb, BROADCAST_ALL, NULL, xs_net(x)); |
1456 | 1456 | ||
1457 | return 0; | 1457 | return 0; |
1458 | } | 1458 | } |
@@ -1565,7 +1565,7 @@ static int pfkey_get(struct sock *sk, struct sk_buff *skb, const struct sadb_msg | |||
1565 | out_hdr->sadb_msg_reserved = 0; | 1565 | out_hdr->sadb_msg_reserved = 0; |
1566 | out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; | 1566 | out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; |
1567 | out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; | 1567 | out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; |
1568 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, sock_net(sk)); | 1568 | pfkey_broadcast(out_skb, BROADCAST_ONE, sk, sock_net(sk)); |
1569 | 1569 | ||
1570 | return 0; | 1570 | return 0; |
1571 | } | 1571 | } |
@@ -1670,7 +1670,7 @@ static int pfkey_register(struct sock *sk, struct sk_buff *skb, const struct sad | |||
1670 | return -ENOBUFS; | 1670 | return -ENOBUFS; |
1671 | } | 1671 | } |
1672 | 1672 | ||
1673 | pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk, sock_net(sk)); | 1673 | pfkey_broadcast(supp_skb, BROADCAST_REGISTERED, sk, sock_net(sk)); |
1674 | 1674 | ||
1675 | return 0; | 1675 | return 0; |
1676 | } | 1676 | } |
@@ -1689,7 +1689,7 @@ static int unicast_flush_resp(struct sock *sk, const struct sadb_msg *ihdr) | |||
1689 | hdr->sadb_msg_errno = (uint8_t) 0; | 1689 | hdr->sadb_msg_errno = (uint8_t) 0; |
1690 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); | 1690 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); |
1691 | 1691 | ||
1692 | return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ONE, sk, sock_net(sk)); | 1692 | return pfkey_broadcast(skb, BROADCAST_ONE, sk, sock_net(sk)); |
1693 | } | 1693 | } |
1694 | 1694 | ||
1695 | static int key_notify_sa_flush(const struct km_event *c) | 1695 | static int key_notify_sa_flush(const struct km_event *c) |
@@ -1710,7 +1710,7 @@ static int key_notify_sa_flush(const struct km_event *c) | |||
1710 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); | 1710 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); |
1711 | hdr->sadb_msg_reserved = 0; | 1711 | hdr->sadb_msg_reserved = 0; |
1712 | 1712 | ||
1713 | pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net); | 1713 | pfkey_broadcast(skb, BROADCAST_ALL, NULL, c->net); |
1714 | 1714 | ||
1715 | return 0; | 1715 | return 0; |
1716 | } | 1716 | } |
@@ -1767,7 +1767,7 @@ static int dump_sa(struct xfrm_state *x, int count, void *ptr) | |||
1767 | out_hdr->sadb_msg_pid = pfk->dump.msg_portid; | 1767 | out_hdr->sadb_msg_pid = pfk->dump.msg_portid; |
1768 | 1768 | ||
1769 | if (pfk->dump.skb) | 1769 | if (pfk->dump.skb) |
1770 | pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, | 1770 | pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE, |
1771 | &pfk->sk, sock_net(&pfk->sk)); | 1771 | &pfk->sk, sock_net(&pfk->sk)); |
1772 | pfk->dump.skb = out_skb; | 1772 | pfk->dump.skb = out_skb; |
1773 | 1773 | ||
@@ -1847,7 +1847,7 @@ static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, const struct sadb | |||
1847 | new_hdr->sadb_msg_errno = 0; | 1847 | new_hdr->sadb_msg_errno = 0; |
1848 | } | 1848 | } |
1849 | 1849 | ||
1850 | pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ALL, NULL, sock_net(sk)); | 1850 | pfkey_broadcast(skb, BROADCAST_ALL, NULL, sock_net(sk)); |
1851 | return 0; | 1851 | return 0; |
1852 | } | 1852 | } |
1853 | 1853 | ||
@@ -2181,7 +2181,7 @@ static int key_notify_policy(struct xfrm_policy *xp, int dir, const struct km_ev | |||
2181 | out_hdr->sadb_msg_errno = 0; | 2181 | out_hdr->sadb_msg_errno = 0; |
2182 | out_hdr->sadb_msg_seq = c->seq; | 2182 | out_hdr->sadb_msg_seq = c->seq; |
2183 | out_hdr->sadb_msg_pid = c->portid; | 2183 | out_hdr->sadb_msg_pid = c->portid; |
2184 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xp_net(xp)); | 2184 | pfkey_broadcast(out_skb, BROADCAST_ALL, NULL, xp_net(xp)); |
2185 | return 0; | 2185 | return 0; |
2186 | 2186 | ||
2187 | } | 2187 | } |
@@ -2401,7 +2401,7 @@ static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struc | |||
2401 | out_hdr->sadb_msg_errno = 0; | 2401 | out_hdr->sadb_msg_errno = 0; |
2402 | out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; | 2402 | out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; |
2403 | out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; | 2403 | out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; |
2404 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, xp_net(xp)); | 2404 | pfkey_broadcast(out_skb, BROADCAST_ONE, sk, xp_net(xp)); |
2405 | err = 0; | 2405 | err = 0; |
2406 | 2406 | ||
2407 | out: | 2407 | out: |
@@ -2655,7 +2655,7 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) | |||
2655 | out_hdr->sadb_msg_pid = pfk->dump.msg_portid; | 2655 | out_hdr->sadb_msg_pid = pfk->dump.msg_portid; |
2656 | 2656 | ||
2657 | if (pfk->dump.skb) | 2657 | if (pfk->dump.skb) |
2658 | pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, | 2658 | pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE, |
2659 | &pfk->sk, sock_net(&pfk->sk)); | 2659 | &pfk->sk, sock_net(&pfk->sk)); |
2660 | pfk->dump.skb = out_skb; | 2660 | pfk->dump.skb = out_skb; |
2661 | 2661 | ||
@@ -2708,7 +2708,7 @@ static int key_notify_policy_flush(const struct km_event *c) | |||
2708 | hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; | 2708 | hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; |
2709 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); | 2709 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); |
2710 | hdr->sadb_msg_reserved = 0; | 2710 | hdr->sadb_msg_reserved = 0; |
2711 | pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net); | 2711 | pfkey_broadcast(skb_out, BROADCAST_ALL, NULL, c->net); |
2712 | return 0; | 2712 | return 0; |
2713 | 2713 | ||
2714 | } | 2714 | } |
@@ -2770,7 +2770,7 @@ static int pfkey_process(struct sock *sk, struct sk_buff *skb, const struct sadb | |||
2770 | void *ext_hdrs[SADB_EXT_MAX]; | 2770 | void *ext_hdrs[SADB_EXT_MAX]; |
2771 | int err; | 2771 | int err; |
2772 | 2772 | ||
2773 | pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, | 2773 | pfkey_broadcast(skb_clone(skb, GFP_KERNEL), |
2774 | BROADCAST_PROMISC_ONLY, NULL, sock_net(sk)); | 2774 | BROADCAST_PROMISC_ONLY, NULL, sock_net(sk)); |
2775 | 2775 | ||
2776 | memset(ext_hdrs, 0, sizeof(ext_hdrs)); | 2776 | memset(ext_hdrs, 0, sizeof(ext_hdrs)); |
@@ -2992,7 +2992,7 @@ static int key_notify_sa_expire(struct xfrm_state *x, const struct km_event *c) | |||
2992 | out_hdr->sadb_msg_seq = 0; | 2992 | out_hdr->sadb_msg_seq = 0; |
2993 | out_hdr->sadb_msg_pid = 0; | 2993 | out_hdr->sadb_msg_pid = 0; |
2994 | 2994 | ||
2995 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x)); | 2995 | pfkey_broadcast(out_skb, BROADCAST_REGISTERED, NULL, xs_net(x)); |
2996 | return 0; | 2996 | return 0; |
2997 | } | 2997 | } |
2998 | 2998 | ||
@@ -3182,7 +3182,7 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct | |||
3182 | xfrm_ctx->ctx_len); | 3182 | xfrm_ctx->ctx_len); |
3183 | } | 3183 | } |
3184 | 3184 | ||
3185 | return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x)); | 3185 | return pfkey_broadcast(skb, BROADCAST_REGISTERED, NULL, xs_net(x)); |
3186 | } | 3186 | } |
3187 | 3187 | ||
3188 | static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, | 3188 | static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, |
@@ -3380,7 +3380,7 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, | |||
3380 | n_port->sadb_x_nat_t_port_port = sport; | 3380 | n_port->sadb_x_nat_t_port_port = sport; |
3381 | n_port->sadb_x_nat_t_port_reserved = 0; | 3381 | n_port->sadb_x_nat_t_port_reserved = 0; |
3382 | 3382 | ||
3383 | return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x)); | 3383 | return pfkey_broadcast(skb, BROADCAST_REGISTERED, NULL, xs_net(x)); |
3384 | } | 3384 | } |
3385 | 3385 | ||
3386 | #ifdef CONFIG_NET_KEY_MIGRATE | 3386 | #ifdef CONFIG_NET_KEY_MIGRATE |
@@ -3572,7 +3572,7 @@ static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, | |||
3572 | } | 3572 | } |
3573 | 3573 | ||
3574 | /* broadcast migrate message to sockets */ | 3574 | /* broadcast migrate message to sockets */ |
3575 | pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, &init_net); | 3575 | pfkey_broadcast(skb, BROADCAST_ALL, NULL, &init_net); |
3576 | 3576 | ||
3577 | return 0; | 3577 | return 0; |
3578 | 3578 | ||