diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-09-16 13:31:58 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-09-16 13:31:58 +0200 |
commit | 2f2387e5223e1aa80876261d423f8ce7242ebe89 (patch) | |
tree | 56402f0615fe99ddc3d6305fbe232761d82c2029 | |
parent | 41a221a7913ed754f56e4c3d6abed0f8979ba69f (diff) | |
download | queue-3.18-2f2387e5223e1aa80876261d423f8ce7242ebe89.tar.gz |
more patches
9 files changed, 537 insertions, 0 deletions
diff --git a/ipv6-fix-the-link-time-qualifier-of-ping_v6_proc_exit_net.patch b/ipv6-fix-the-link-time-qualifier-of-ping_v6_proc_exit_net.patch new file mode 100644 index 0000000..1198a03 --- /dev/null +++ b/ipv6-fix-the-link-time-qualifier-of-ping_v6_proc_exit_net.patch @@ -0,0 +1,31 @@ +From foo@baz Mon 16 Sep 2019 01:29:13 PM CEST +From: Christophe JAILLET <christophe.jaillet@wanadoo.fr> +Date: Tue, 10 Sep 2019 13:29:59 +0200 +Subject: ipv6: Fix the link time qualifier of 'ping_v6_proc_exit_net()' + +From: Christophe JAILLET <christophe.jaillet@wanadoo.fr> + +[ Upstream commit d23dbc479a8e813db4161a695d67da0e36557846 ] + +The '.exit' functions from 'pernet_operations' structure should be marked +as __net_exit, not __net_init. + +Fixes: d862e5461423 ("net: ipv6: Implement /proc/net/icmp6.") +Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + net/ipv6/ping.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ipv6/ping.c ++++ b/net/ipv6/ping.c +@@ -227,7 +227,7 @@ static int __net_init ping_v6_proc_init_ + return ping_proc_register(net, &ping_v6_seq_afinfo); + } + +-static void __net_init ping_v6_proc_exit_net(struct net *net) ++static void __net_exit ping_v6_proc_exit_net(struct net *net) + { + return ping_proc_unregister(net, &ping_v6_seq_afinfo); + } diff --git a/isdn-capi-check-message-length-in-capi_write.patch b/isdn-capi-check-message-length-in-capi_write.patch new file mode 100644 index 0000000..d3be6f6 --- /dev/null +++ b/isdn-capi-check-message-length-in-capi_write.patch @@ -0,0 +1,86 @@ +From foo@baz Mon 16 Sep 2019 01:29:13 PM CEST +From: Eric Biggers <ebiggers@google.com> +Date: Thu, 5 Sep 2019 19:36:37 -0700 +Subject: isdn/capi: check message length in capi_write() + +From: Eric Biggers <ebiggers@google.com> + +[ Upstream commit fe163e534e5eecdfd7b5920b0dfd24c458ee85d6 ] + +syzbot reported: + + BUG: KMSAN: uninit-value in capi_write+0x791/0xa90 drivers/isdn/capi/capi.c:700 + CPU: 0 PID: 10025 Comm: syz-executor379 Not tainted 4.20.0-rc7+ #2 + Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 + Call Trace: + __dump_stack lib/dump_stack.c:77 [inline] + dump_stack+0x173/0x1d0 lib/dump_stack.c:113 + kmsan_report+0x12e/0x2a0 mm/kmsan/kmsan.c:613 + __msan_warning+0x82/0xf0 mm/kmsan/kmsan_instr.c:313 + capi_write+0x791/0xa90 drivers/isdn/capi/capi.c:700 + do_loop_readv_writev fs/read_write.c:703 [inline] + do_iter_write+0x83e/0xd80 fs/read_write.c:961 + vfs_writev fs/read_write.c:1004 [inline] + do_writev+0x397/0x840 fs/read_write.c:1039 + __do_sys_writev fs/read_write.c:1112 [inline] + __se_sys_writev+0x9b/0xb0 fs/read_write.c:1109 + __x64_sys_writev+0x4a/0x70 fs/read_write.c:1109 + do_syscall_64+0xbc/0xf0 arch/x86/entry/common.c:291 + entry_SYSCALL_64_after_hwframe+0x63/0xe7 + [...] + +The problem is that capi_write() is reading past the end of the message. +Fix it by checking the message's length in the needed places. + +Reported-and-tested-by: syzbot+0849c524d9c634f5ae66@syzkaller.appspotmail.com +Signed-off-by: Eric Biggers <ebiggers@google.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/isdn/capi/capi.c | 10 +++++++++- + include/uapi/linux/isdn/capicmd.h | 1 + + 2 files changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/isdn/capi/capi.c ++++ b/drivers/isdn/capi/capi.c +@@ -687,6 +687,9 @@ capi_write(struct file *file, const char + if (!cdev->ap.applid) + return -ENODEV; + ++ if (count < CAPIMSG_BASELEN) ++ return -EINVAL; ++ + skb = alloc_skb(count, GFP_USER); + if (!skb) + return -ENOMEM; +@@ -697,7 +700,8 @@ capi_write(struct file *file, const char + } + mlen = CAPIMSG_LEN(skb->data); + if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { +- if ((size_t)(mlen + CAPIMSG_DATALEN(skb->data)) != count) { ++ if (count < CAPI_DATA_B3_REQ_LEN || ++ (size_t)(mlen + CAPIMSG_DATALEN(skb->data)) != count) { + kfree_skb(skb); + return -EINVAL; + } +@@ -710,6 +714,10 @@ capi_write(struct file *file, const char + CAPIMSG_SETAPPID(skb->data, cdev->ap.applid); + + if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) { ++ if (count < CAPI_DISCONNECT_B3_RESP_LEN) { ++ kfree_skb(skb); ++ return -EINVAL; ++ } + mutex_lock(&cdev->lock); + capincci_free(cdev, CAPIMSG_NCCI(skb->data)); + mutex_unlock(&cdev->lock); +--- a/include/uapi/linux/isdn/capicmd.h ++++ b/include/uapi/linux/isdn/capicmd.h +@@ -15,6 +15,7 @@ + #define CAPI_MSG_BASELEN 8 + #define CAPI_DATA_B3_REQ_LEN (CAPI_MSG_BASELEN+4+4+2+2+2) + #define CAPI_DATA_B3_RESP_LEN (CAPI_MSG_BASELEN+4+2) ++#define CAPI_DISCONNECT_B3_RESP_LEN (CAPI_MSG_BASELEN+4) + + /*----- CAPI commands -----*/ + #define CAPI_ALERT 0x01 diff --git a/net-fix-null-de-reference-of-device-refcount.patch b/net-fix-null-de-reference-of-device-refcount.patch new file mode 100644 index 0000000..41f919a --- /dev/null +++ b/net-fix-null-de-reference-of-device-refcount.patch @@ -0,0 +1,54 @@ +From foo@baz Mon 16 Sep 2019 01:29:13 PM CEST +From: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org> +Date: Tue, 10 Sep 2019 14:02:57 -0600 +Subject: net: Fix null de-reference of device refcount + +From: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org> + +[ Upstream commit 10cc514f451a0f239aa34f91bc9dc954a9397840 ] + +In event of failure during register_netdevice, free_netdev is +invoked immediately. free_netdev assumes that all the netdevice +refcounts have been dropped prior to it being called and as a +result frees and clears out the refcount pointer. + +However, this is not necessarily true as some of the operations +in the NETDEV_UNREGISTER notifier handlers queue RCU callbacks for +invocation after a grace period. The IPv4 callback in_dev_rcu_put +tries to access the refcount after free_netdev is called which +leads to a null de-reference- + +44837.761523: <6> Unable to handle kernel paging request at + virtual address 0000004a88287000 +44837.761651: <2> pc : in_dev_finish_destroy+0x4c/0xc8 +44837.761654: <2> lr : in_dev_finish_destroy+0x2c/0xc8 +44837.762393: <2> Call trace: +44837.762398: <2> in_dev_finish_destroy+0x4c/0xc8 +44837.762404: <2> in_dev_rcu_put+0x24/0x30 +44837.762412: <2> rcu_nocb_kthread+0x43c/0x468 +44837.762418: <2> kthread+0x118/0x128 +44837.762424: <2> ret_from_fork+0x10/0x1c + +Fix this by waiting for the completion of the call_rcu() in +case of register_netdevice errors. + +Fixes: 93ee31f14f6f ("[NET]: Fix free_netdev on register_netdev failure.") +Cc: Sean Tranchetti <stranche@codeaurora.org> +Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + net/core/dev.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -6314,6 +6314,8 @@ int register_netdevice(struct net_device + ret = notifier_to_errno(ret); + if (ret) { + rollback_registered(dev); ++ rcu_barrier(); ++ + dev->reg_state = NETREG_UNREGISTERED; + } + /* diff --git a/sch_hhf-ensure-quantum-and-hhf_non_hh_weight-are-non-zero.patch b/sch_hhf-ensure-quantum-and-hhf_non_hh_weight-are-non-zero.patch new file mode 100644 index 0000000..531e383 --- /dev/null +++ b/sch_hhf-ensure-quantum-and-hhf_non_hh_weight-are-non-zero.patch @@ -0,0 +1,40 @@ +From foo@baz Mon 16 Sep 2019 01:29:13 PM CEST +From: Cong Wang <xiyou.wangcong@gmail.com> +Date: Sun, 8 Sep 2019 13:40:51 -0700 +Subject: sch_hhf: ensure quantum and hhf_non_hh_weight are non-zero + +From: Cong Wang <xiyou.wangcong@gmail.com> + +[ Upstream commit d4d6ec6dac07f263f06d847d6f732d6855522845 ] + +In case of TCA_HHF_NON_HH_WEIGHT or TCA_HHF_QUANTUM is zero, +it would make no progress inside the loop in hhf_dequeue() thus +kernel would get stuck. + +Fix this by checking this corner case in hhf_change(). + +Fixes: 10239edf86f1 ("net-qdisc-hhf: Heavy-Hitter Filter (HHF) qdisc") +Reported-by: syzbot+bc6297c11f19ee807dc2@syzkaller.appspotmail.com +Reported-by: syzbot+041483004a7f45f1f20a@syzkaller.appspotmail.com +Reported-by: syzbot+55be5f513bed37fc4367@syzkaller.appspotmail.com +Cc: Jamal Hadi Salim <jhs@mojatatu.com> +Cc: Jiri Pirko <jiri@resnulli.us> +Cc: Terry Lam <vtlam@google.com> +Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + net/sched/sch_hhf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/sched/sch_hhf.c ++++ b/net/sched/sch_hhf.c +@@ -557,7 +557,7 @@ static int hhf_change(struct Qdisc *sch, + new_hhf_non_hh_weight = nla_get_u32(tb[TCA_HHF_NON_HH_WEIGHT]); + + non_hh_quantum = (u64)new_quantum * new_hhf_non_hh_weight; +- if (non_hh_quantum > INT_MAX) ++ if (non_hh_quantum == 0 || non_hh_quantum > INT_MAX) + return -EINVAL; + + sch_tree_lock(sch); diff --git a/sctp-fix-the-link-time-qualifier-of-sctp_ctrlsock_exit.patch b/sctp-fix-the-link-time-qualifier-of-sctp_ctrlsock_exit.patch new file mode 100644 index 0000000..9e134a3 --- /dev/null +++ b/sctp-fix-the-link-time-qualifier-of-sctp_ctrlsock_exit.patch @@ -0,0 +1,32 @@ +From foo@baz Mon 16 Sep 2019 01:29:13 PM CEST +From: Christophe JAILLET <christophe.jaillet@wanadoo.fr> +Date: Wed, 11 Sep 2019 18:02:39 +0200 +Subject: sctp: Fix the link time qualifier of 'sctp_ctrlsock_exit()' + +From: Christophe JAILLET <christophe.jaillet@wanadoo.fr> + +[ Upstream commit b456d72412ca8797234449c25815e82f4e1426c0 ] + +The '.exit' functions from 'pernet_operations' structure should be marked +as __net_exit, not __net_init. + +Fixes: 8e2d61e0aed2 ("sctp: fix race on protocol/netns initialization") +Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr> +Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + net/sctp/protocol.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/sctp/protocol.c ++++ b/net/sctp/protocol.c +@@ -1311,7 +1311,7 @@ static int __net_init sctp_ctrlsock_init + return status; + } + +-static void __net_init sctp_ctrlsock_exit(struct net *net) ++static void __net_exit sctp_ctrlsock_exit(struct net *net) + { + /* Free the control endpoint. */ + inet_ctl_sock_destroy(net->sctp.ctl_sock); diff --git a/sctp-use-transport-pf_retrans-in-sctp_do_8_2_transport_strike.patch b/sctp-use-transport-pf_retrans-in-sctp_do_8_2_transport_strike.patch new file mode 100644 index 0000000..4cab90e --- /dev/null +++ b/sctp-use-transport-pf_retrans-in-sctp_do_8_2_transport_strike.patch @@ -0,0 +1,34 @@ +From foo@baz Mon 16 Sep 2019 01:29:13 PM CEST +From: Xin Long <lucien.xin@gmail.com> +Date: Mon, 2 Sep 2019 23:24:21 +0800 +Subject: sctp: use transport pf_retrans in sctp_do_8_2_transport_strike + +From: Xin Long <lucien.xin@gmail.com> + +[ Upstream commit 10eb56c582c557c629271f1ee31e15e7a9b2558b ] + +Transport should use its own pf_retrans to do the error_count +check, instead of asoc's. Otherwise, it's meaningless to make +pf_retrans per transport. + +Fixes: 5aa93bcf66f4 ("sctp: Implement quick failover draft from tsvwg") +Signed-off-by: Xin Long <lucien.xin@gmail.com> +Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> +Acked-by: Neil Horman <nhorman@tuxdriver.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + net/sctp/sm_sideeffect.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/sctp/sm_sideeffect.c ++++ b/net/sctp/sm_sideeffect.c +@@ -501,7 +501,7 @@ static void sctp_do_8_2_transport_strike + */ + if ((transport->state == SCTP_ACTIVE) && + (transport->error_count < transport->pathmaxrxt) && +- (transport->error_count > asoc->pf_retrans)) { ++ (transport->error_count > transport->pf_retrans)) { + + sctp_assoc_control_transport(asoc, transport, + SCTP_TRANSPORT_PF, @@ -0,0 +1,8 @@ +ipv6-fix-the-link-time-qualifier-of-ping_v6_proc_exit_net.patch +isdn-capi-check-message-length-in-capi_write.patch +net-fix-null-de-reference-of-device-refcount.patch +sch_hhf-ensure-quantum-and-hhf_non_hh_weight-are-non-zero.patch +sctp-fix-the-link-time-qualifier-of-sctp_ctrlsock_exit.patch +sctp-use-transport-pf_retrans-in-sctp_do_8_2_transport_strike.patch +tcp-fix-tcp_ecn_withdraw_cwr-to-clear-tcp_ecn_queue_cwr.patch +tun-fix-use-after-free-when-register-netdev-failed.patch diff --git a/tcp-fix-tcp_ecn_withdraw_cwr-to-clear-tcp_ecn_queue_cwr.patch b/tcp-fix-tcp_ecn_withdraw_cwr-to-clear-tcp_ecn_queue_cwr.patch new file mode 100644 index 0000000..41519f2 --- /dev/null +++ b/tcp-fix-tcp_ecn_withdraw_cwr-to-clear-tcp_ecn_queue_cwr.patch @@ -0,0 +1,59 @@ +From foo@baz Mon 16 Sep 2019 01:29:13 PM CEST +From: Neal Cardwell <ncardwell@google.com> +Date: Mon, 9 Sep 2019 16:56:02 -0400 +Subject: tcp: fix tcp_ecn_withdraw_cwr() to clear TCP_ECN_QUEUE_CWR + +From: Neal Cardwell <ncardwell@google.com> + +[ Upstream commit af38d07ed391b21f7405fa1f936ca9686787d6d2 ] + +Fix tcp_ecn_withdraw_cwr() to clear the correct bit: +TCP_ECN_QUEUE_CWR. + +Rationale: basically, TCP_ECN_DEMAND_CWR is a bit that is purely about +the behavior of data receivers, and deciding whether to reflect +incoming IP ECN CE marks as outgoing TCP th->ece marks. The +TCP_ECN_QUEUE_CWR bit is purely about the behavior of data senders, +and deciding whether to send CWR. The tcp_ecn_withdraw_cwr() function +is only called from tcp_undo_cwnd_reduction() by data senders during +an undo, so it should zero the sender-side state, +TCP_ECN_QUEUE_CWR. It does not make sense to stop the reflection of +incoming CE bits on incoming data packets just because outgoing +packets were spuriously retransmitted. + +The bug has been reproduced with packetdrill to manifest in a scenario +with RFC3168 ECN, with an incoming data packet with CE bit set and +carrying a TCP timestamp value that causes cwnd undo. Before this fix, +the IP CE bit was ignored and not reflected in the TCP ECE header bit, +and sender sent a TCP CWR ('W') bit on the next outgoing data packet, +even though the cwnd reduction had been undone. After this fix, the +sender properly reflects the CE bit and does not set the W bit. + +Note: the bug actually predates 2005 git history; this Fixes footer is +chosen to be the oldest SHA1 I have tested (from Sep 2007) for which +the patch applies cleanly (since before this commit the code was in a +.h file). + +Fixes: bdf1ee5d3bd3 ("[TCP]: Move code from tcp_ecn.h to tcp*.c and tcp.h & remove it") +Signed-off-by: Neal Cardwell <ncardwell@google.com> +Acked-by: Yuchung Cheng <ycheng@google.com> +Acked-by: Soheil Hassas Yeganeh <soheil@google.com> +Cc: Eric Dumazet <edumazet@google.com> +Signed-off-by: Eric Dumazet <edumazet@google.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + net/ipv4/tcp_input.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -219,7 +219,7 @@ static void tcp_ecn_accept_cwr(struct tc + + static void tcp_ecn_withdraw_cwr(struct tcp_sock *tp) + { +- tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; ++ tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR; + } + + static void __tcp_ecn_check_ce(struct sock *sk, const struct sk_buff *skb) diff --git a/tun-fix-use-after-free-when-register-netdev-failed.patch b/tun-fix-use-after-free-when-register-netdev-failed.patch new file mode 100644 index 0000000..3b84704 --- /dev/null +++ b/tun-fix-use-after-free-when-register-netdev-failed.patch @@ -0,0 +1,193 @@ +From foo@baz Mon 16 Sep 2019 01:07:00 PM CEST +From: Yang Yingliang <yangyingliang@huawei.com> +Date: Tue, 10 Sep 2019 18:56:57 +0800 +Subject: tun: fix use-after-free when register netdev failed + +From: Yang Yingliang <yangyingliang@huawei.com> + +[ Upstream commit 77f22f92dff8e7b45c7786a430626d38071d4670 ] + +I got a UAF repport in tun driver when doing fuzzy test: + +[ 466.269490] ================================================================== +[ 466.271792] BUG: KASAN: use-after-free in tun_chr_read_iter+0x2ca/0x2d0 +[ 466.271806] Read of size 8 at addr ffff888372139250 by task tun-test/2699 +[ 466.271810] +[ 466.271824] CPU: 1 PID: 2699 Comm: tun-test Not tainted 5.3.0-rc1-00001-g5a9433db2614-dirty #427 +[ 466.271833] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014 +[ 466.271838] Call Trace: +[ 466.271858] dump_stack+0xca/0x13e +[ 466.271871] ? tun_chr_read_iter+0x2ca/0x2d0 +[ 466.271890] print_address_description+0x79/0x440 +[ 466.271906] ? vprintk_func+0x5e/0xf0 +[ 466.271920] ? tun_chr_read_iter+0x2ca/0x2d0 +[ 466.271935] __kasan_report+0x15c/0x1df +[ 466.271958] ? tun_chr_read_iter+0x2ca/0x2d0 +[ 466.271976] kasan_report+0xe/0x20 +[ 466.271987] tun_chr_read_iter+0x2ca/0x2d0 +[ 466.272013] do_iter_readv_writev+0x4b7/0x740 +[ 466.272032] ? default_llseek+0x2d0/0x2d0 +[ 466.272072] do_iter_read+0x1c5/0x5e0 +[ 466.272110] vfs_readv+0x108/0x180 +[ 466.299007] ? compat_rw_copy_check_uvector+0x440/0x440 +[ 466.299020] ? fsnotify+0x888/0xd50 +[ 466.299040] ? __fsnotify_parent+0xd0/0x350 +[ 466.299064] ? fsnotify_first_mark+0x1e0/0x1e0 +[ 466.304548] ? vfs_write+0x264/0x510 +[ 466.304569] ? ksys_write+0x101/0x210 +[ 466.304591] ? do_preadv+0x116/0x1a0 +[ 466.304609] do_preadv+0x116/0x1a0 +[ 466.309829] do_syscall_64+0xc8/0x600 +[ 466.309849] entry_SYSCALL_64_after_hwframe+0x49/0xbe +[ 466.309861] RIP: 0033:0x4560f9 +[ 466.309875] Code: 00 00 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b8 ff ff ff f7 d8 64 89 01 48 +[ 466.309889] RSP: 002b:00007ffffa5166e8 EFLAGS: 00000206 ORIG_RAX: 0000000000000127 +[ 466.322992] RAX: ffffffffffffffda RBX: 0000000000400460 RCX: 00000000004560f9 +[ 466.322999] RDX: 0000000000000003 RSI: 00000000200008c0 RDI: 0000000000000003 +[ 466.323007] RBP: 00007ffffa516700 R08: 0000000000000004 R09: 0000000000000000 +[ 466.323014] R10: 0000000000000000 R11: 0000000000000206 R12: 000000000040cb10 +[ 466.323021] R13: 0000000000000000 R14: 00000000006d7018 R15: 0000000000000000 +[ 466.323057] +[ 466.323064] Allocated by task 2605: +[ 466.335165] save_stack+0x19/0x80 +[ 466.336240] __kasan_kmalloc.constprop.8+0xa0/0xd0 +[ 466.337755] kmem_cache_alloc+0xe8/0x320 +[ 466.339050] getname_flags+0xca/0x560 +[ 466.340229] user_path_at_empty+0x2c/0x50 +[ 466.341508] vfs_statx+0xe6/0x190 +[ 466.342619] __do_sys_newstat+0x81/0x100 +[ 466.343908] do_syscall_64+0xc8/0x600 +[ 466.345303] entry_SYSCALL_64_after_hwframe+0x49/0xbe +[ 466.347034] +[ 466.347517] Freed by task 2605: +[ 466.348471] save_stack+0x19/0x80 +[ 466.349476] __kasan_slab_free+0x12e/0x180 +[ 466.350726] kmem_cache_free+0xc8/0x430 +[ 466.351874] putname+0xe2/0x120 +[ 466.352921] filename_lookup+0x257/0x3e0 +[ 466.354319] vfs_statx+0xe6/0x190 +[ 466.355498] __do_sys_newstat+0x81/0x100 +[ 466.356889] do_syscall_64+0xc8/0x600 +[ 466.358037] entry_SYSCALL_64_after_hwframe+0x49/0xbe +[ 466.359567] +[ 466.360050] The buggy address belongs to the object at ffff888372139100 +[ 466.360050] which belongs to the cache names_cache of size 4096 +[ 466.363735] The buggy address is located 336 bytes inside of +[ 466.363735] 4096-byte region [ffff888372139100, ffff88837213a100) +[ 466.367179] The buggy address belongs to the page: +[ 466.368604] page:ffffea000dc84e00 refcount:1 mapcount:0 mapping:ffff8883df1b4f00 index:0x0 compound_mapcount: 0 +[ 466.371582] flags: 0x2fffff80010200(slab|head) +[ 466.372910] raw: 002fffff80010200 dead000000000100 dead000000000122 ffff8883df1b4f00 +[ 466.375209] raw: 0000000000000000 0000000000070007 00000001ffffffff 0000000000000000 +[ 466.377778] page dumped because: kasan: bad access detected +[ 466.379730] +[ 466.380288] Memory state around the buggy address: +[ 466.381844] ffff888372139100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 466.384009] ffff888372139180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 466.386131] >ffff888372139200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 466.388257] ^ +[ 466.390234] ffff888372139280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 466.392512] ffff888372139300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 466.394667] ================================================================== + +tun_chr_read_iter() accessed the memory which freed by free_netdev() +called by tun_set_iff(): + + CPUA CPUB + tun_set_iff() + alloc_netdev_mqs() + tun_attach() + tun_chr_read_iter() + tun_get() + tun_do_read() + tun_ring_recv() + register_netdevice() <-- inject error + goto err_detach + tun_detach_all() <-- set RCV_SHUTDOWN + free_netdev() <-- called from + err_free_dev path + netdev_freemem() <-- free the memory + without check refcount + (In this path, the refcount cannot prevent + freeing the memory of dev, and the memory + will be used by dev_put() called by + tun_chr_read_iter() on CPUB.) + (Break from tun_ring_recv(), + because RCV_SHUTDOWN is set) + tun_put() + dev_put() <-- use the memory + freed by netdev_freemem() + +Put the publishing of tfile->tun after register_netdevice(), +so tun_get() won't get the tun pointer that freed by +err_detach path if register_netdevice() failed. + +Fixes: eb0fb363f920 ("tuntap: attach queue 0 before registering netdevice") +Reported-by: Hulk Robot <hulkci@huawei.com> +Suggested-by: Jason Wang <jasowang@redhat.com> +Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/net/tun.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -529,7 +529,8 @@ static void tun_detach_all(struct net_de + module_put(THIS_MODULE); + } + +-static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filter) ++static int tun_attach(struct tun_struct *tun, struct file *file, ++ bool skip_filter, bool publish_tun) + { + struct tun_file *tfile = file->private_data; + int err; +@@ -561,7 +562,8 @@ static int tun_attach(struct tun_struct + } + tfile->queue_index = tun->numqueues; + tfile->socket.sk->sk_shutdown &= ~RCV_SHUTDOWN; +- rcu_assign_pointer(tfile->tun, tun); ++ if (publish_tun) ++ rcu_assign_pointer(tfile->tun, tun); + rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile); + tun->numqueues++; + +@@ -1613,7 +1615,7 @@ static int tun_set_iff(struct net *net, + if (err < 0) + return err; + +- err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER); ++ err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER, true); + if (err < 0) + return err; + +@@ -1693,13 +1695,17 @@ static int tun_set_iff(struct net *net, + NETIF_F_HW_VLAN_STAG_TX); + + INIT_LIST_HEAD(&tun->disabled); +- err = tun_attach(tun, file, false); ++ err = tun_attach(tun, file, false, false); + if (err < 0) + goto err_free_flow; + + err = register_netdevice(tun->dev); + if (err < 0) + goto err_detach; ++ /* free_netdev() won't check refcnt, to aovid race ++ * with dev_put() we need publish tun after registration. ++ */ ++ rcu_assign_pointer(tfile->tun, tun); + + if (device_create_file(&tun->dev->dev, &dev_attr_tun_flags) || + device_create_file(&tun->dev->dev, &dev_attr_owner) || +@@ -1857,7 +1863,7 @@ static int tun_set_queue(struct file *fi + ret = security_tun_dev_attach_queue(tun->security); + if (ret < 0) + goto unlock; +- ret = tun_attach(tun, file, false); ++ ret = tun_attach(tun, file, false, true); + } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { + tun = rtnl_dereference(tfile->tun); + if (!tun || !(tun->flags & TUN_TAP_MQ) || tfile->detached) |