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 | ||
