diff options
author | Eric Dumazet <edumazet@google.com> | 2017-08-14 13:16:45 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-08-15 01:18:12 -0400 |
commit | 36f41f8fc6d8aa9f8c9072d66ff7cf9055f5e69b (patch) | |
tree | 0360c2ff1fd2e000c9e46f21faddfd3773845850 /net/key | |
parent | 539a06baedd06127389b254f6b9f016ca072da13 (diff) |
af_key: do not use GFP_KERNEL in atomic contexts
pfkey_broadcast() might be called from non process contexts,
we can not use GFP_KERNEL in these cases [1].
This patch partially reverts commit ba51b6be38c1 ("net: Fix RCU splat in
af_key"), only keeping the GFP_ATOMIC forcing under rcu_read_lock()
section.
[1] : syzkaller reported :
in_atomic(): 1, irqs_disabled(): 0, pid: 2932, name: syzkaller183439
3 locks held by syzkaller183439/2932:
#0: (&net->xfrm.xfrm_cfg_mutex){+.+.+.}, at: [<ffffffff83b43888>] pfkey_sendmsg+0x4c8/0x9f0 net/key/af_key.c:3649
#1: (&pfk->dump_lock){+.+.+.}, at: [<ffffffff83b467f6>] pfkey_do_dump+0x76/0x3f0 net/key/af_key.c:293
#2: (&(&net->xfrm.xfrm_policy_lock)->rlock){+...+.}, at: [<ffffffff83957632>] spin_lock_bh include/linux/spinlock.h:304 [inline]
#2: (&(&net->xfrm.xfrm_policy_lock)->rlock){+...+.}, at: [<ffffffff83957632>] xfrm_policy_walk+0x192/0xa30 net/xfrm/xfrm_policy.c:1028
CPU: 0 PID: 2932 Comm: syzkaller183439 Not tainted 4.13.0-rc4+ #24
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
__dump_stack lib/dump_stack.c:16 [inline]
dump_stack+0x194/0x257 lib/dump_stack.c:52
___might_sleep+0x2b2/0x470 kernel/sched/core.c:5994
__might_sleep+0x95/0x190 kernel/sched/core.c:5947
slab_pre_alloc_hook mm/slab.h:416 [inline]
slab_alloc mm/slab.c:3383 [inline]
kmem_cache_alloc+0x24b/0x6e0 mm/slab.c:3559
skb_clone+0x1a0/0x400 net/core/skbuff.c:1037
pfkey_broadcast_one+0x4b2/0x6f0 net/key/af_key.c:207
pfkey_broadcast+0x4ba/0x770 net/key/af_key.c:281
dump_sp+0x3d6/0x500 net/key/af_key.c:2685
xfrm_policy_walk+0x2f1/0xa30 net/xfrm/xfrm_policy.c:1042
pfkey_dump_sp+0x42/0x50 net/key/af_key.c:2695
pfkey_do_dump+0xaa/0x3f0 net/key/af_key.c:299
pfkey_spddump+0x1a0/0x210 net/key/af_key.c:2722
pfkey_process+0x606/0x710 net/key/af_key.c:2814
pfkey_sendmsg+0x4d6/0x9f0 net/key/af_key.c:3650
sock_sendmsg_nosec net/socket.c:633 [inline]
sock_sendmsg+0xca/0x110 net/socket.c:643
___sys_sendmsg+0x755/0x890 net/socket.c:2035
__sys_sendmsg+0xe5/0x210 net/socket.c:2069
SYSC_sendmsg net/socket.c:2080 [inline]
SyS_sendmsg+0x2d/0x50 net/socket.c:2076
entry_SYSCALL_64_fastpath+0x1f/0xbe
RIP: 0033:0x445d79
RSP: 002b:00007f32447c1dc8 EFLAGS: 00000202 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 0000000000445d79
RDX: 0000000000000000 RSI: 000000002023dfc8 RDI: 0000000000000008
RBP: 0000000000000086 R08: 00007f32447c2700 R09: 00007f32447c2700
R10: 00007f32447c2700 R11: 0000000000000202 R12: 0000000000000000
R13: 00007ffe33edec4f R14: 00007f32447c29c0 R15: 0000000000000000
Fixes: ba51b6be38c1 ("net: Fix RCU splat in af_key")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Dmitry Vyukov <dvyukov@google.com>
Cc: David Ahern <dsa@cumulusnetworks.com>
Acked-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/key')
-rw-r--r-- | net/key/af_key.c | 48 |
1 files changed, 26 insertions, 22 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c index ca9d3ae665e7..98f4d8211b9a 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -228,7 +228,7 @@ static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2, | |||
228 | #define BROADCAST_ONE 1 | 228 | #define BROADCAST_ONE 1 |
229 | #define BROADCAST_REGISTERED 2 | 229 | #define BROADCAST_REGISTERED 2 |
230 | #define BROADCAST_PROMISC_ONLY 4 | 230 | #define BROADCAST_PROMISC_ONLY 4 |
231 | static int pfkey_broadcast(struct sk_buff *skb, | 231 | static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, |
232 | int broadcast_flags, struct sock *one_sk, | 232 | int broadcast_flags, struct sock *one_sk, |
233 | struct net *net) | 233 | struct net *net) |
234 | { | 234 | { |
@@ -278,7 +278,7 @@ static int pfkey_broadcast(struct sk_buff *skb, | |||
278 | rcu_read_unlock(); | 278 | rcu_read_unlock(); |
279 | 279 | ||
280 | if (one_sk != NULL) | 280 | if (one_sk != NULL) |
281 | err = pfkey_broadcast_one(skb, &skb2, GFP_KERNEL, one_sk); | 281 | err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk); |
282 | 282 | ||
283 | kfree_skb(skb2); | 283 | kfree_skb(skb2); |
284 | kfree_skb(skb); | 284 | kfree_skb(skb); |
@@ -311,7 +311,7 @@ static int pfkey_do_dump(struct pfkey_sock *pfk) | |||
311 | hdr = (struct sadb_msg *) pfk->dump.skb->data; | 311 | hdr = (struct sadb_msg *) pfk->dump.skb->data; |
312 | hdr->sadb_msg_seq = 0; | 312 | hdr->sadb_msg_seq = 0; |
313 | hdr->sadb_msg_errno = rc; | 313 | hdr->sadb_msg_errno = rc; |
314 | pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE, | 314 | pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, |
315 | &pfk->sk, sock_net(&pfk->sk)); | 315 | &pfk->sk, sock_net(&pfk->sk)); |
316 | pfk->dump.skb = NULL; | 316 | pfk->dump.skb = NULL; |
317 | } | 317 | } |
@@ -355,7 +355,7 @@ static int pfkey_error(const struct sadb_msg *orig, int err, struct sock *sk) | |||
355 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / | 355 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / |
356 | sizeof(uint64_t)); | 356 | sizeof(uint64_t)); |
357 | 357 | ||
358 | pfkey_broadcast(skb, BROADCAST_ONE, sk, sock_net(sk)); | 358 | pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk, sock_net(sk)); |
359 | 359 | ||
360 | return 0; | 360 | return 0; |
361 | } | 361 | } |
@@ -1389,7 +1389,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, const struct sadb_ | |||
1389 | 1389 | ||
1390 | xfrm_state_put(x); | 1390 | xfrm_state_put(x); |
1391 | 1391 | ||
1392 | pfkey_broadcast(resp_skb, BROADCAST_ONE, sk, net); | 1392 | pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk, net); |
1393 | 1393 | ||
1394 | return 0; | 1394 | return 0; |
1395 | } | 1395 | } |
@@ -1476,7 +1476,7 @@ static int key_notify_sa(struct xfrm_state *x, const struct km_event *c) | |||
1476 | hdr->sadb_msg_seq = c->seq; | 1476 | hdr->sadb_msg_seq = c->seq; |
1477 | hdr->sadb_msg_pid = c->portid; | 1477 | hdr->sadb_msg_pid = c->portid; |
1478 | 1478 | ||
1479 | pfkey_broadcast(skb, BROADCAST_ALL, NULL, xs_net(x)); | 1479 | pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xs_net(x)); |
1480 | 1480 | ||
1481 | return 0; | 1481 | return 0; |
1482 | } | 1482 | } |
@@ -1589,7 +1589,7 @@ static int pfkey_get(struct sock *sk, struct sk_buff *skb, const struct sadb_msg | |||
1589 | out_hdr->sadb_msg_reserved = 0; | 1589 | out_hdr->sadb_msg_reserved = 0; |
1590 | out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; | 1590 | out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; |
1591 | out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; | 1591 | out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; |
1592 | pfkey_broadcast(out_skb, BROADCAST_ONE, sk, sock_net(sk)); | 1592 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, sock_net(sk)); |
1593 | 1593 | ||
1594 | return 0; | 1594 | return 0; |
1595 | } | 1595 | } |
@@ -1694,8 +1694,8 @@ static int pfkey_register(struct sock *sk, struct sk_buff *skb, const struct sad | |||
1694 | return -ENOBUFS; | 1694 | return -ENOBUFS; |
1695 | } | 1695 | } |
1696 | 1696 | ||
1697 | pfkey_broadcast(supp_skb, BROADCAST_REGISTERED, sk, sock_net(sk)); | 1697 | pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk, |
1698 | 1698 | sock_net(sk)); | |
1699 | return 0; | 1699 | return 0; |
1700 | } | 1700 | } |
1701 | 1701 | ||
@@ -1712,7 +1712,8 @@ static int unicast_flush_resp(struct sock *sk, const struct sadb_msg *ihdr) | |||
1712 | hdr->sadb_msg_errno = (uint8_t) 0; | 1712 | hdr->sadb_msg_errno = (uint8_t) 0; |
1713 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); | 1713 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); |
1714 | 1714 | ||
1715 | return pfkey_broadcast(skb, BROADCAST_ONE, sk, sock_net(sk)); | 1715 | return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ONE, sk, |
1716 | sock_net(sk)); | ||
1716 | } | 1717 | } |
1717 | 1718 | ||
1718 | static int key_notify_sa_flush(const struct km_event *c) | 1719 | static int key_notify_sa_flush(const struct km_event *c) |
@@ -1733,7 +1734,7 @@ static int key_notify_sa_flush(const struct km_event *c) | |||
1733 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); | 1734 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); |
1734 | hdr->sadb_msg_reserved = 0; | 1735 | hdr->sadb_msg_reserved = 0; |
1735 | 1736 | ||
1736 | pfkey_broadcast(skb, BROADCAST_ALL, NULL, c->net); | 1737 | pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net); |
1737 | 1738 | ||
1738 | return 0; | 1739 | return 0; |
1739 | } | 1740 | } |
@@ -1790,7 +1791,7 @@ static int dump_sa(struct xfrm_state *x, int count, void *ptr) | |||
1790 | out_hdr->sadb_msg_pid = pfk->dump.msg_portid; | 1791 | out_hdr->sadb_msg_pid = pfk->dump.msg_portid; |
1791 | 1792 | ||
1792 | if (pfk->dump.skb) | 1793 | if (pfk->dump.skb) |
1793 | pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE, | 1794 | pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, |
1794 | &pfk->sk, sock_net(&pfk->sk)); | 1795 | &pfk->sk, sock_net(&pfk->sk)); |
1795 | pfk->dump.skb = out_skb; | 1796 | pfk->dump.skb = out_skb; |
1796 | 1797 | ||
@@ -1878,7 +1879,7 @@ static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, const struct sadb | |||
1878 | new_hdr->sadb_msg_errno = 0; | 1879 | new_hdr->sadb_msg_errno = 0; |
1879 | } | 1880 | } |
1880 | 1881 | ||
1881 | pfkey_broadcast(skb, BROADCAST_ALL, NULL, sock_net(sk)); | 1882 | pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ALL, NULL, sock_net(sk)); |
1882 | return 0; | 1883 | return 0; |
1883 | } | 1884 | } |
1884 | 1885 | ||
@@ -2206,7 +2207,7 @@ static int key_notify_policy(struct xfrm_policy *xp, int dir, const struct km_ev | |||
2206 | out_hdr->sadb_msg_errno = 0; | 2207 | out_hdr->sadb_msg_errno = 0; |
2207 | out_hdr->sadb_msg_seq = c->seq; | 2208 | out_hdr->sadb_msg_seq = c->seq; |
2208 | out_hdr->sadb_msg_pid = c->portid; | 2209 | out_hdr->sadb_msg_pid = c->portid; |
2209 | pfkey_broadcast(out_skb, BROADCAST_ALL, NULL, xp_net(xp)); | 2210 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xp_net(xp)); |
2210 | return 0; | 2211 | return 0; |
2211 | 2212 | ||
2212 | } | 2213 | } |
@@ -2426,7 +2427,7 @@ static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struc | |||
2426 | out_hdr->sadb_msg_errno = 0; | 2427 | out_hdr->sadb_msg_errno = 0; |
2427 | out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; | 2428 | out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; |
2428 | out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; | 2429 | out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; |
2429 | pfkey_broadcast(out_skb, BROADCAST_ONE, sk, xp_net(xp)); | 2430 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, xp_net(xp)); |
2430 | err = 0; | 2431 | err = 0; |
2431 | 2432 | ||
2432 | out: | 2433 | out: |
@@ -2682,7 +2683,7 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) | |||
2682 | out_hdr->sadb_msg_pid = pfk->dump.msg_portid; | 2683 | out_hdr->sadb_msg_pid = pfk->dump.msg_portid; |
2683 | 2684 | ||
2684 | if (pfk->dump.skb) | 2685 | if (pfk->dump.skb) |
2685 | pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE, | 2686 | pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, |
2686 | &pfk->sk, sock_net(&pfk->sk)); | 2687 | &pfk->sk, sock_net(&pfk->sk)); |
2687 | pfk->dump.skb = out_skb; | 2688 | pfk->dump.skb = out_skb; |
2688 | 2689 | ||
@@ -2739,7 +2740,7 @@ static int key_notify_policy_flush(const struct km_event *c) | |||
2739 | hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; | 2740 | hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; |
2740 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); | 2741 | hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); |
2741 | hdr->sadb_msg_reserved = 0; | 2742 | hdr->sadb_msg_reserved = 0; |
2742 | pfkey_broadcast(skb_out, BROADCAST_ALL, NULL, c->net); | 2743 | pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net); |
2743 | return 0; | 2744 | return 0; |
2744 | 2745 | ||
2745 | } | 2746 | } |
@@ -2803,7 +2804,7 @@ static int pfkey_process(struct sock *sk, struct sk_buff *skb, const struct sadb | |||
2803 | void *ext_hdrs[SADB_EXT_MAX]; | 2804 | void *ext_hdrs[SADB_EXT_MAX]; |
2804 | int err; | 2805 | int err; |
2805 | 2806 | ||
2806 | pfkey_broadcast(skb_clone(skb, GFP_KERNEL), | 2807 | pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, |
2807 | BROADCAST_PROMISC_ONLY, NULL, sock_net(sk)); | 2808 | BROADCAST_PROMISC_ONLY, NULL, sock_net(sk)); |
2808 | 2809 | ||
2809 | memset(ext_hdrs, 0, sizeof(ext_hdrs)); | 2810 | memset(ext_hdrs, 0, sizeof(ext_hdrs)); |
@@ -3024,7 +3025,8 @@ static int key_notify_sa_expire(struct xfrm_state *x, const struct km_event *c) | |||
3024 | out_hdr->sadb_msg_seq = 0; | 3025 | out_hdr->sadb_msg_seq = 0; |
3025 | out_hdr->sadb_msg_pid = 0; | 3026 | out_hdr->sadb_msg_pid = 0; |
3026 | 3027 | ||
3027 | pfkey_broadcast(out_skb, BROADCAST_REGISTERED, NULL, xs_net(x)); | 3028 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, |
3029 | xs_net(x)); | ||
3028 | return 0; | 3030 | return 0; |
3029 | } | 3031 | } |
3030 | 3032 | ||
@@ -3212,7 +3214,8 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct | |||
3212 | xfrm_ctx->ctx_len); | 3214 | xfrm_ctx->ctx_len); |
3213 | } | 3215 | } |
3214 | 3216 | ||
3215 | return pfkey_broadcast(skb, BROADCAST_REGISTERED, NULL, xs_net(x)); | 3217 | return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, |
3218 | xs_net(x)); | ||
3216 | } | 3219 | } |
3217 | 3220 | ||
3218 | static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, | 3221 | static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, |
@@ -3408,7 +3411,8 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, | |||
3408 | n_port->sadb_x_nat_t_port_port = sport; | 3411 | n_port->sadb_x_nat_t_port_port = sport; |
3409 | n_port->sadb_x_nat_t_port_reserved = 0; | 3412 | n_port->sadb_x_nat_t_port_reserved = 0; |
3410 | 3413 | ||
3411 | return pfkey_broadcast(skb, BROADCAST_REGISTERED, NULL, xs_net(x)); | 3414 | return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, |
3415 | xs_net(x)); | ||
3412 | } | 3416 | } |
3413 | 3417 | ||
3414 | #ifdef CONFIG_NET_KEY_MIGRATE | 3418 | #ifdef CONFIG_NET_KEY_MIGRATE |
@@ -3599,7 +3603,7 @@ static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, | |||
3599 | } | 3603 | } |
3600 | 3604 | ||
3601 | /* broadcast migrate message to sockets */ | 3605 | /* broadcast migrate message to sockets */ |
3602 | pfkey_broadcast(skb, BROADCAST_ALL, NULL, &init_net); | 3606 | pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, &init_net); |
3603 | 3607 | ||
3604 | return 0; | 3608 | return 0; |
3605 | 3609 | ||