From: Greg Kroah-Hartman Date: Mon, 18 Apr 2022 11:56:17 +0000 (+0200) Subject: 5.4-stable patches X-Git-Tag: v4.9.311~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=86d658d5495f1c225469acd5b4ab577870c44d7a;p=thirdparty%2Fkernel%2Fstable-queue.git 5.4-stable patches added patches: ax25-add-refcount-in-ax25_dev-to-avoid-uaf-bugs.patch ax25-fix-npd-bug-in-ax25_disconnect.patch ax25-fix-null-pointer-dereferences-in-ax25-timers.patch ax25-fix-refcount-leaks-caused-by-ax25_cb_del.patch ax25-fix-reference-count-leaks-of-ax25_dev.patch ax25-fix-uaf-bug-in-ax25_send_control.patch ax25-fix-uaf-bugs-in-ax25-timers.patch ax25-fix-uaf-bugs-of-net_device-caused-by-rebinding-operation.patch --- diff --git a/queue-5.4/ax25-add-refcount-in-ax25_dev-to-avoid-uaf-bugs.patch b/queue-5.4/ax25-add-refcount-in-ax25_dev-to-avoid-uaf-bugs.patch new file mode 100644 index 00000000000..9401c8fad5a --- /dev/null +++ b/queue-5.4/ax25-add-refcount-in-ax25_dev-to-avoid-uaf-bugs.patch @@ -0,0 +1,195 @@ +From foo@baz Mon Apr 18 01:55:27 PM CEST 2022 +From: Ovidiu Panait +Date: Mon, 18 Apr 2022 09:33:05 +0300 +Subject: ax25: add refcount in ax25_dev to avoid UAF bugs +To: stable@vger.kernel.org +Message-ID: <20220418063312.1628871-1-ovidiu.panait@windriver.com> + +From: Duoming Zhou + +commit d01ffb9eee4af165d83b08dd73ebdf9fe94a519b upstream. + +If we dereference ax25_dev after we call kfree(ax25_dev) in +ax25_dev_device_down(), it will lead to concurrency UAF bugs. +There are eight syscall functions suffer from UAF bugs, include +ax25_bind(), ax25_release(), ax25_connect(), ax25_ioctl(), +ax25_getname(), ax25_sendmsg(), ax25_getsockopt() and +ax25_info_show(). + +One of the concurrency UAF can be shown as below: + + (USE) | (FREE) + | ax25_device_event + | ax25_dev_device_down +ax25_bind | ... + ... | kfree(ax25_dev) + ax25_fillin_cb() | ... + ax25_fillin_cb_from_dev() | + ... | + +The root cause of UAF bugs is that kfree(ax25_dev) in +ax25_dev_device_down() is not protected by any locks. +When ax25_dev, which there are still pointers point to, +is released, the concurrency UAF bug will happen. + +This patch introduces refcount into ax25_dev in order to +guarantee that there are no pointers point to it when ax25_dev +is released. + +Signed-off-by: Duoming Zhou +Signed-off-by: David S. Miller +[OP: backport to 5.4: adjusted context] +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + include/net/ax25.h | 10 ++++++++++ + net/ax25/af_ax25.c | 2 ++ + net/ax25/ax25_dev.c | 12 ++++++++++-- + net/ax25/ax25_route.c | 3 +++ + 4 files changed, 25 insertions(+), 2 deletions(-) + +--- a/include/net/ax25.h ++++ b/include/net/ax25.h +@@ -236,6 +236,7 @@ typedef struct ax25_dev { + #if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER) + ax25_dama_info dama; + #endif ++ refcount_t refcount; + } ax25_dev; + + typedef struct ax25_cb { +@@ -290,6 +291,15 @@ static __inline__ void ax25_cb_put(ax25_ + } + } + ++#define ax25_dev_hold(__ax25_dev) \ ++ refcount_inc(&((__ax25_dev)->refcount)) ++ ++static __inline__ void ax25_dev_put(ax25_dev *ax25_dev) ++{ ++ if (refcount_dec_and_test(&ax25_dev->refcount)) { ++ kfree(ax25_dev); ++ } ++} + static inline __be16 ax25_type_trans(struct sk_buff *skb, struct net_device *dev) + { + skb->dev = dev; +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -98,6 +98,7 @@ again: + spin_unlock_bh(&ax25_list_lock); + lock_sock(sk); + s->ax25_dev = NULL; ++ ax25_dev_put(ax25_dev); + release_sock(sk); + ax25_disconnect(s, ENETUNREACH); + spin_lock_bh(&ax25_list_lock); +@@ -446,6 +447,7 @@ static int ax25_ctl_ioctl(const unsigned + } + + out_put: ++ ax25_dev_put(ax25_dev); + ax25_cb_put(ax25); + return ret; + +--- a/net/ax25/ax25_dev.c ++++ b/net/ax25/ax25_dev.c +@@ -37,6 +37,7 @@ ax25_dev *ax25_addr_ax25dev(ax25_address + for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) + if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) { + res = ax25_dev; ++ ax25_dev_hold(ax25_dev); + } + spin_unlock_bh(&ax25_dev_lock); + +@@ -56,6 +57,7 @@ void ax25_dev_device_up(struct net_devic + return; + } + ++ refcount_set(&ax25_dev->refcount, 1); + dev->ax25_ptr = ax25_dev; + ax25_dev->dev = dev; + dev_hold(dev); +@@ -83,6 +85,7 @@ void ax25_dev_device_up(struct net_devic + spin_lock_bh(&ax25_dev_lock); + ax25_dev->next = ax25_dev_list; + ax25_dev_list = ax25_dev; ++ ax25_dev_hold(ax25_dev); + spin_unlock_bh(&ax25_dev_lock); + + ax25_register_dev_sysctl(ax25_dev); +@@ -112,20 +115,22 @@ void ax25_dev_device_down(struct net_dev + + if ((s = ax25_dev_list) == ax25_dev) { + ax25_dev_list = s->next; ++ ax25_dev_put(ax25_dev); + spin_unlock_bh(&ax25_dev_lock); + dev->ax25_ptr = NULL; + dev_put(dev); +- kfree(ax25_dev); ++ ax25_dev_put(ax25_dev); + return; + } + + while (s != NULL && s->next != NULL) { + if (s->next == ax25_dev) { + s->next = ax25_dev->next; ++ ax25_dev_put(ax25_dev); + spin_unlock_bh(&ax25_dev_lock); + dev->ax25_ptr = NULL; + dev_put(dev); +- kfree(ax25_dev); ++ ax25_dev_put(ax25_dev); + return; + } + +@@ -133,6 +138,7 @@ void ax25_dev_device_down(struct net_dev + } + spin_unlock_bh(&ax25_dev_lock); + dev->ax25_ptr = NULL; ++ ax25_dev_put(ax25_dev); + } + + int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd) +@@ -149,6 +155,7 @@ int ax25_fwd_ioctl(unsigned int cmd, str + if (ax25_dev->forward != NULL) + return -EINVAL; + ax25_dev->forward = fwd_dev->dev; ++ ax25_dev_put(fwd_dev); + break; + + case SIOCAX25DELFWD: +@@ -161,6 +168,7 @@ int ax25_fwd_ioctl(unsigned int cmd, str + return -EINVAL; + } + ++ ax25_dev_put(ax25_dev); + return 0; + } + +--- a/net/ax25/ax25_route.c ++++ b/net/ax25/ax25_route.c +@@ -116,6 +116,7 @@ static int __must_check ax25_rt_add(stru + ax25_rt->dev = ax25_dev->dev; + ax25_rt->digipeat = NULL; + ax25_rt->ip_mode = ' '; ++ ax25_dev_put(ax25_dev); + if (route->digi_count != 0) { + if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + write_unlock_bh(&ax25_route_lock); +@@ -172,6 +173,7 @@ static int ax25_rt_del(struct ax25_route + } + } + } ++ ax25_dev_put(ax25_dev); + write_unlock_bh(&ax25_route_lock); + + return 0; +@@ -214,6 +216,7 @@ static int ax25_rt_opt(struct ax25_route + } + + out: ++ ax25_dev_put(ax25_dev); + write_unlock_bh(&ax25_route_lock); + return err; + } diff --git a/queue-5.4/ax25-fix-npd-bug-in-ax25_disconnect.patch b/queue-5.4/ax25-fix-npd-bug-in-ax25_disconnect.patch new file mode 100644 index 00000000000..c62062115be --- /dev/null +++ b/queue-5.4/ax25-fix-npd-bug-in-ax25_disconnect.patch @@ -0,0 +1,67 @@ +From foo@baz Mon Apr 18 01:55:27 PM CEST 2022 +From: Ovidiu Panait +Date: Mon, 18 Apr 2022 09:33:10 +0300 +Subject: ax25: fix NPD bug in ax25_disconnect +To: stable@vger.kernel.org +Message-ID: <20220418063312.1628871-6-ovidiu.panait@windriver.com> + +From: Duoming Zhou + +commit 7ec02f5ac8a5be5a3f20611731243dc5e1d9ba10 upstream. + +The ax25_disconnect() in ax25_kill_by_device() is not +protected by any locks, thus there is a race condition +between ax25_disconnect() and ax25_destroy_socket(). +when ax25->sk is assigned as NULL by ax25_destroy_socket(), +a NULL pointer dereference bug will occur if site (1) or (2) +dereferences ax25->sk. + +ax25_kill_by_device() | ax25_release() + ax25_disconnect() | ax25_destroy_socket() + ... | + if(ax25->sk != NULL) | ... + ... | ax25->sk = NULL; + bh_lock_sock(ax25->sk); //(1) | ... + ... | + bh_unlock_sock(ax25->sk); //(2)| + +This patch moves ax25_disconnect() into lock_sock(), which can +synchronize with ax25_destroy_socket() in ax25_release(). + +Fail log: +=============================================================== +BUG: kernel NULL pointer dereference, address: 0000000000000088 +... +RIP: 0010:_raw_spin_lock+0x7e/0xd0 +... +Call Trace: +ax25_disconnect+0xf6/0x220 +ax25_device_event+0x187/0x250 +raw_notifier_call_chain+0x5e/0x70 +dev_close_many+0x17d/0x230 +rollback_registered_many+0x1f1/0x950 +unregister_netdevice_queue+0x133/0x200 +unregister_netdev+0x13/0x20 +... + +Signed-off-by: Duoming Zhou +Signed-off-by: David S. Miller +[OP: backport to 5.4: adjust context] +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + net/ax25/af_ax25.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -102,8 +102,8 @@ again: + dev_put(ax25_dev->dev); + ax25_dev_put(ax25_dev); + } +- release_sock(sk); + ax25_disconnect(s, ENETUNREACH); ++ release_sock(sk); + spin_lock_bh(&ax25_list_lock); + sock_put(sk); + /* The entry could have been deleted from the diff --git a/queue-5.4/ax25-fix-null-pointer-dereferences-in-ax25-timers.patch b/queue-5.4/ax25-fix-null-pointer-dereferences-in-ax25-timers.patch new file mode 100644 index 00000000000..95c3dc2398d --- /dev/null +++ b/queue-5.4/ax25-fix-null-pointer-dereferences-in-ax25-timers.patch @@ -0,0 +1,123 @@ +From foo@baz Mon Apr 18 01:55:27 PM CEST 2022 +From: Ovidiu Panait +Date: Mon, 18 Apr 2022 09:33:11 +0300 +Subject: ax25: Fix NULL pointer dereferences in ax25 timers +To: stable@vger.kernel.org +Message-ID: <20220418063312.1628871-7-ovidiu.panait@windriver.com> + +From: Duoming Zhou + +commit fc6d01ff9ef03b66d4a3a23b46fc3c3d8cf92009 upstream. + +The previous commit 7ec02f5ac8a5 ("ax25: fix NPD bug in ax25_disconnect") +move ax25_disconnect into lock_sock() in order to prevent NPD bugs. But +there are race conditions that may lead to null pointer dereferences in +ax25_heartbeat_expiry(), ax25_t1timer_expiry(), ax25_t2timer_expiry(), +ax25_t3timer_expiry() and ax25_idletimer_expiry(), when we use +ax25_kill_by_device() to detach the ax25 device. + +One of the race conditions that cause null pointer dereferences can be +shown as below: + + (Thread 1) | (Thread 2) +ax25_connect() | + ax25_std_establish_data_link() | + ax25_start_t1timer() | + mod_timer(&ax25->t1timer,..) | + | ax25_kill_by_device() + (wait a time) | ... + | s->ax25_dev = NULL; //(1) + ax25_t1timer_expiry() | + ax25->ax25_dev->values[..] //(2)| ... + ... | + +We set null to ax25_cb->ax25_dev in position (1) and dereference +the null pointer in position (2). + +The corresponding fail log is shown below: +=============================================================== +BUG: kernel NULL pointer dereference, address: 0000000000000050 +CPU: 1 PID: 0 Comm: swapper/1 Not tainted 5.17.0-rc6-00794-g45690b7d0 +RIP: 0010:ax25_t1timer_expiry+0x12/0x40 +... +Call Trace: + call_timer_fn+0x21/0x120 + __run_timers.part.0+0x1ca/0x250 + run_timer_softirq+0x2c/0x60 + __do_softirq+0xef/0x2f3 + irq_exit_rcu+0xb6/0x100 + sysvec_apic_timer_interrupt+0xa2/0xd0 +... + +This patch moves ax25_disconnect() before s->ax25_dev = NULL +and uses del_timer_sync() to delete timers in ax25_disconnect(). +If ax25_disconnect() is called by ax25_kill_by_device() or +ax25->ax25_dev is NULL, the reason in ax25_disconnect() will be +equal to ENETUNREACH, it will wait all timers to stop before we +set null to s->ax25_dev in ax25_kill_by_device(). + +Fixes: 7ec02f5ac8a5 ("ax25: fix NPD bug in ax25_disconnect") +Signed-off-by: Duoming Zhou +Signed-off-by: David S. Miller +[OP: backport to 5.4: adjust context] +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + net/ax25/af_ax25.c | 4 ++-- + net/ax25/ax25_subr.c | 20 ++++++++++++++------ + 2 files changed, 16 insertions(+), 8 deletions(-) + +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -89,20 +89,20 @@ again: + sk = s->sk; + if (!sk) { + spin_unlock_bh(&ax25_list_lock); +- s->ax25_dev = NULL; + ax25_disconnect(s, ENETUNREACH); ++ s->ax25_dev = NULL; + spin_lock_bh(&ax25_list_lock); + goto again; + } + sock_hold(sk); + spin_unlock_bh(&ax25_list_lock); + lock_sock(sk); ++ ax25_disconnect(s, ENETUNREACH); + s->ax25_dev = NULL; + if (sk->sk_socket) { + dev_put(ax25_dev->dev); + ax25_dev_put(ax25_dev); + } +- ax25_disconnect(s, ENETUNREACH); + release_sock(sk); + spin_lock_bh(&ax25_list_lock); + sock_put(sk); +--- a/net/ax25/ax25_subr.c ++++ b/net/ax25/ax25_subr.c +@@ -261,12 +261,20 @@ void ax25_disconnect(ax25_cb *ax25, int + { + ax25_clear_queues(ax25); + +- if (!ax25->sk || !sock_flag(ax25->sk, SOCK_DESTROY)) +- ax25_stop_heartbeat(ax25); +- ax25_stop_t1timer(ax25); +- ax25_stop_t2timer(ax25); +- ax25_stop_t3timer(ax25); +- ax25_stop_idletimer(ax25); ++ if (reason == ENETUNREACH) { ++ del_timer_sync(&ax25->timer); ++ del_timer_sync(&ax25->t1timer); ++ del_timer_sync(&ax25->t2timer); ++ del_timer_sync(&ax25->t3timer); ++ del_timer_sync(&ax25->idletimer); ++ } else { ++ if (!ax25->sk || !sock_flag(ax25->sk, SOCK_DESTROY)) ++ ax25_stop_heartbeat(ax25); ++ ax25_stop_t1timer(ax25); ++ ax25_stop_t2timer(ax25); ++ ax25_stop_t3timer(ax25); ++ ax25_stop_idletimer(ax25); ++ } + + ax25->state = AX25_STATE_0; + diff --git a/queue-5.4/ax25-fix-refcount-leaks-caused-by-ax25_cb_del.patch b/queue-5.4/ax25-fix-refcount-leaks-caused-by-ax25_cb_del.patch new file mode 100644 index 00000000000..ae54f499b69 --- /dev/null +++ b/queue-5.4/ax25-fix-refcount-leaks-caused-by-ax25_cb_del.patch @@ -0,0 +1,102 @@ +From foo@baz Mon Apr 18 01:55:27 PM CEST 2022 +From: Ovidiu Panait +Date: Mon, 18 Apr 2022 09:33:08 +0300 +Subject: ax25: Fix refcount leaks caused by ax25_cb_del() +To: stable@vger.kernel.org +Message-ID: <20220418063312.1628871-4-ovidiu.panait@windriver.com> + +From: Duoming Zhou + +commit 9fd75b66b8f68498454d685dc4ba13192ae069b0 upstream. + +The previous commit d01ffb9eee4a ("ax25: add refcount in ax25_dev to +avoid UAF bugs") and commit feef318c855a ("ax25: fix UAF bugs of +net_device caused by rebinding operation") increase the refcounts of +ax25_dev and net_device in ax25_bind() and decrease the matching refcounts +in ax25_kill_by_device() in order to prevent UAF bugs, but there are +reference count leaks. + +The root cause of refcount leaks is shown below: + + (Thread 1) | (Thread 2) +ax25_bind() | + ... | + ax25_addr_ax25dev() | + ax25_dev_hold() //(1) | + ... | + dev_hold_track() //(2) | + ... | ax25_destroy_socket() + | ax25_cb_del() + | ... + | hlist_del_init() //(3) + | + | + (Thread 3) | +ax25_kill_by_device() | + ... | + ax25_for_each(s, &ax25_list) { | + if (s->ax25_dev == ax25_dev) //(4) | + ... | + +Firstly, we use ax25_bind() to increase the refcount of ax25_dev in +position (1) and increase the refcount of net_device in position (2). +Then, we use ax25_cb_del() invoked by ax25_destroy_socket() to delete +ax25_cb in hlist in position (3) before calling ax25_kill_by_device(). +Finally, the decrements of refcounts in ax25_kill_by_device() will not +be executed, because no s->ax25_dev equals to ax25_dev in position (4). + +This patch adds decrements of refcounts in ax25_release() and use +lock_sock() to do synchronization. If refcounts decrease in ax25_release(), +the decrements of refcounts in ax25_kill_by_device() will not be +executed and vice versa. + +Fixes: d01ffb9eee4a ("ax25: add refcount in ax25_dev to avoid UAF bugs") +Fixes: 87563a043cef ("ax25: fix reference count leaks of ax25_dev") +Fixes: feef318c855a ("ax25: fix UAF bugs of net_device caused by rebinding operation") +Reported-by: Thomas Osterried +Signed-off-by: Duoming Zhou +Signed-off-by: David S. Miller +[OP: backport to 5.4: adjust dev_put_track()->dev_put()] +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + net/ax25/af_ax25.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -98,8 +98,10 @@ again: + spin_unlock_bh(&ax25_list_lock); + lock_sock(sk); + s->ax25_dev = NULL; +- dev_put(ax25_dev->dev); +- ax25_dev_put(ax25_dev); ++ if (sk->sk_socket) { ++ dev_put(ax25_dev->dev); ++ ax25_dev_put(ax25_dev); ++ } + release_sock(sk); + ax25_disconnect(s, ENETUNREACH); + spin_lock_bh(&ax25_list_lock); +@@ -978,14 +980,20 @@ static int ax25_release(struct socket *s + { + struct sock *sk = sock->sk; + ax25_cb *ax25; ++ ax25_dev *ax25_dev; + + if (sk == NULL) + return 0; + + sock_hold(sk); +- sock_orphan(sk); + lock_sock(sk); ++ sock_orphan(sk); + ax25 = sk_to_ax25(sk); ++ ax25_dev = ax25->ax25_dev; ++ if (ax25_dev) { ++ dev_put(ax25_dev->dev); ++ ax25_dev_put(ax25_dev); ++ } + + if (sk->sk_type == SOCK_SEQPACKET) { + switch (ax25->state) { diff --git a/queue-5.4/ax25-fix-reference-count-leaks-of-ax25_dev.patch b/queue-5.4/ax25-fix-reference-count-leaks-of-ax25_dev.patch new file mode 100644 index 00000000000..ff119ecb92d --- /dev/null +++ b/queue-5.4/ax25-fix-reference-count-leaks-of-ax25_dev.patch @@ -0,0 +1,239 @@ +From foo@baz Mon Apr 18 01:55:27 PM CEST 2022 +From: Ovidiu Panait +Date: Mon, 18 Apr 2022 09:33:06 +0300 +Subject: ax25: fix reference count leaks of ax25_dev +To: stable@vger.kernel.org +Message-ID: <20220418063312.1628871-2-ovidiu.panait@windriver.com> + +From: Duoming Zhou + +commit 87563a043cef044fed5db7967a75741cc16ad2b1 upstream. + +The previous commit d01ffb9eee4a ("ax25: add refcount in ax25_dev +to avoid UAF bugs") introduces refcount into ax25_dev, but there +are reference leak paths in ax25_ctl_ioctl(), ax25_fwd_ioctl(), +ax25_rt_add(), ax25_rt_del() and ax25_rt_opt(). + +This patch uses ax25_dev_put() and adjusts the position of +ax25_addr_ax25dev() to fix reference cout leaks of ax25_dev. + +Fixes: d01ffb9eee4a ("ax25: add refcount in ax25_dev to avoid UAF bugs") +Signed-off-by: Duoming Zhou +Reviewed-by: Dan Carpenter +Link: https://lore.kernel.org/r/20220203150811.42256-1-duoming@zju.edu.cn +Signed-off-by: Jakub Kicinski +[OP: backport to 5.4: adjust context] +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + include/net/ax25.h | 8 +++++--- + net/ax25/af_ax25.c | 12 ++++++++---- + net/ax25/ax25_dev.c | 24 +++++++++++++++++------- + net/ax25/ax25_route.c | 16 +++++++++++----- + 4 files changed, 41 insertions(+), 19 deletions(-) + +--- a/include/net/ax25.h ++++ b/include/net/ax25.h +@@ -291,10 +291,12 @@ static __inline__ void ax25_cb_put(ax25_ + } + } + +-#define ax25_dev_hold(__ax25_dev) \ +- refcount_inc(&((__ax25_dev)->refcount)) ++static inline void ax25_dev_hold(ax25_dev *ax25_dev) ++{ ++ refcount_inc(&ax25_dev->refcount); ++} + +-static __inline__ void ax25_dev_put(ax25_dev *ax25_dev) ++static inline void ax25_dev_put(ax25_dev *ax25_dev) + { + if (refcount_dec_and_test(&ax25_dev->refcount)) { + kfree(ax25_dev); +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -366,21 +366,25 @@ static int ax25_ctl_ioctl(const unsigned + if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl))) + return -EFAULT; + +- if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL) +- return -ENODEV; +- + if (ax25_ctl.digi_count > AX25_MAX_DIGIS) + return -EINVAL; + + if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL) + return -EINVAL; + ++ ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr); ++ if (!ax25_dev) ++ return -ENODEV; ++ + digi.ndigi = ax25_ctl.digi_count; + for (k = 0; k < digi.ndigi; k++) + digi.calls[k] = ax25_ctl.digi_addr[k]; + +- if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev)) == NULL) ++ ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev); ++ if (!ax25) { ++ ax25_dev_put(ax25_dev); + return -ENOTCONN; ++ } + + switch (ax25_ctl.cmd) { + case AX25_KILL: +--- a/net/ax25/ax25_dev.c ++++ b/net/ax25/ax25_dev.c +@@ -85,8 +85,8 @@ void ax25_dev_device_up(struct net_devic + spin_lock_bh(&ax25_dev_lock); + ax25_dev->next = ax25_dev_list; + ax25_dev_list = ax25_dev; +- ax25_dev_hold(ax25_dev); + spin_unlock_bh(&ax25_dev_lock); ++ ax25_dev_hold(ax25_dev); + + ax25_register_dev_sysctl(ax25_dev); + } +@@ -115,8 +115,8 @@ void ax25_dev_device_down(struct net_dev + + if ((s = ax25_dev_list) == ax25_dev) { + ax25_dev_list = s->next; +- ax25_dev_put(ax25_dev); + spin_unlock_bh(&ax25_dev_lock); ++ ax25_dev_put(ax25_dev); + dev->ax25_ptr = NULL; + dev_put(dev); + ax25_dev_put(ax25_dev); +@@ -126,8 +126,8 @@ void ax25_dev_device_down(struct net_dev + while (s != NULL && s->next != NULL) { + if (s->next == ax25_dev) { + s->next = ax25_dev->next; +- ax25_dev_put(ax25_dev); + spin_unlock_bh(&ax25_dev_lock); ++ ax25_dev_put(ax25_dev); + dev->ax25_ptr = NULL; + dev_put(dev); + ax25_dev_put(ax25_dev); +@@ -150,25 +150,35 @@ int ax25_fwd_ioctl(unsigned int cmd, str + + switch (cmd) { + case SIOCAX25ADDFWD: +- if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL) ++ fwd_dev = ax25_addr_ax25dev(&fwd->port_to); ++ if (!fwd_dev) { ++ ax25_dev_put(ax25_dev); + return -EINVAL; +- if (ax25_dev->forward != NULL) ++ } ++ if (ax25_dev->forward) { ++ ax25_dev_put(fwd_dev); ++ ax25_dev_put(ax25_dev); + return -EINVAL; ++ } + ax25_dev->forward = fwd_dev->dev; + ax25_dev_put(fwd_dev); ++ ax25_dev_put(ax25_dev); + break; + + case SIOCAX25DELFWD: +- if (ax25_dev->forward == NULL) ++ if (!ax25_dev->forward) { ++ ax25_dev_put(ax25_dev); + return -EINVAL; ++ } + ax25_dev->forward = NULL; ++ ax25_dev_put(ax25_dev); + break; + + default: ++ ax25_dev_put(ax25_dev); + return -EINVAL; + } + +- ax25_dev_put(ax25_dev); + return 0; + } + +--- a/net/ax25/ax25_route.c ++++ b/net/ax25/ax25_route.c +@@ -75,11 +75,13 @@ static int __must_check ax25_rt_add(stru + ax25_dev *ax25_dev; + int i; + +- if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL) +- return -EINVAL; + if (route->digi_count > AX25_MAX_DIGIS) + return -EINVAL; + ++ ax25_dev = ax25_addr_ax25dev(&route->port_addr); ++ if (!ax25_dev) ++ return -EINVAL; ++ + write_lock_bh(&ax25_route_lock); + + ax25_rt = ax25_route_list; +@@ -91,6 +93,7 @@ static int __must_check ax25_rt_add(stru + if (route->digi_count != 0) { + if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + write_unlock_bh(&ax25_route_lock); ++ ax25_dev_put(ax25_dev); + return -ENOMEM; + } + ax25_rt->digipeat->lastrepeat = -1; +@@ -101,6 +104,7 @@ static int __must_check ax25_rt_add(stru + } + } + write_unlock_bh(&ax25_route_lock); ++ ax25_dev_put(ax25_dev); + return 0; + } + ax25_rt = ax25_rt->next; +@@ -108,6 +112,7 @@ static int __must_check ax25_rt_add(stru + + if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) { + write_unlock_bh(&ax25_route_lock); ++ ax25_dev_put(ax25_dev); + return -ENOMEM; + } + +@@ -116,11 +121,11 @@ static int __must_check ax25_rt_add(stru + ax25_rt->dev = ax25_dev->dev; + ax25_rt->digipeat = NULL; + ax25_rt->ip_mode = ' '; +- ax25_dev_put(ax25_dev); + if (route->digi_count != 0) { + if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + write_unlock_bh(&ax25_route_lock); + kfree(ax25_rt); ++ ax25_dev_put(ax25_dev); + return -ENOMEM; + } + ax25_rt->digipeat->lastrepeat = -1; +@@ -133,6 +138,7 @@ static int __must_check ax25_rt_add(stru + ax25_rt->next = ax25_route_list; + ax25_route_list = ax25_rt; + write_unlock_bh(&ax25_route_lock); ++ ax25_dev_put(ax25_dev); + + return 0; + } +@@ -173,8 +179,8 @@ static int ax25_rt_del(struct ax25_route + } + } + } +- ax25_dev_put(ax25_dev); + write_unlock_bh(&ax25_route_lock); ++ ax25_dev_put(ax25_dev); + + return 0; + } +@@ -216,8 +222,8 @@ static int ax25_rt_opt(struct ax25_route + } + + out: +- ax25_dev_put(ax25_dev); + write_unlock_bh(&ax25_route_lock); ++ ax25_dev_put(ax25_dev); + return err; + } + diff --git a/queue-5.4/ax25-fix-uaf-bug-in-ax25_send_control.patch b/queue-5.4/ax25-fix-uaf-bug-in-ax25_send_control.patch new file mode 100644 index 00000000000..b14f001049d --- /dev/null +++ b/queue-5.4/ax25-fix-uaf-bug-in-ax25_send_control.patch @@ -0,0 +1,89 @@ +From foo@baz Mon Apr 18 01:55:27 PM CEST 2022 +From: Ovidiu Panait +Date: Mon, 18 Apr 2022 09:33:09 +0300 +Subject: ax25: fix UAF bug in ax25_send_control() +To: stable@vger.kernel.org +Message-ID: <20220418063312.1628871-5-ovidiu.panait@windriver.com> + +From: Duoming Zhou + +commit 5352a761308397a0e6250fdc629bb3f615b94747 upstream. + +There are UAF bugs in ax25_send_control(), when we call ax25_release() +to deallocate ax25_dev. The possible race condition is shown below: + + (Thread 1) | (Thread 2) +ax25_dev_device_up() //(1) | + | ax25_kill_by_device() +ax25_bind() //(2) | +ax25_connect() | ... + ax25->state = AX25_STATE_1 | + ... | ax25_dev_device_down() //(3) + + (Thread 3) +ax25_release() | + ax25_dev_put() //(4) FREE | + case AX25_STATE_1: | + ax25_send_control() | + alloc_skb() //USE | + +The refcount of ax25_dev increases in position (1) and (2), and +decreases in position (3) and (4). The ax25_dev will be freed +before dereference sites in ax25_send_control(). + +The following is part of the report: + +[ 102.297448] BUG: KASAN: use-after-free in ax25_send_control+0x33/0x210 +[ 102.297448] Read of size 8 at addr ffff888009e6e408 by task ax25_close/602 +[ 102.297448] Call Trace: +[ 102.303751] ax25_send_control+0x33/0x210 +[ 102.303751] ax25_release+0x356/0x450 +[ 102.305431] __sock_release+0x6d/0x120 +[ 102.305431] sock_close+0xf/0x20 +[ 102.305431] __fput+0x11f/0x420 +[ 102.305431] task_work_run+0x86/0xd0 +[ 102.307130] get_signal+0x1075/0x1220 +[ 102.308253] arch_do_signal_or_restart+0x1df/0xc00 +[ 102.308253] exit_to_user_mode_prepare+0x150/0x1e0 +[ 102.308253] syscall_exit_to_user_mode+0x19/0x50 +[ 102.308253] do_syscall_64+0x48/0x90 +[ 102.308253] entry_SYSCALL_64_after_hwframe+0x44/0xae +[ 102.308253] RIP: 0033:0x405ae7 + +This patch defers the free operation of ax25_dev and net_device after +all corresponding dereference sites in ax25_release() to avoid UAF. + +Fixes: 9fd75b66b8f6 ("ax25: Fix refcount leaks caused by ax25_cb_del()") +Signed-off-by: Duoming Zhou +Signed-off-by: Paolo Abeni +[OP: backport to 5.4: adjust dev_put_track()->dev_put()] +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + net/ax25/af_ax25.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -990,10 +990,6 @@ static int ax25_release(struct socket *s + sock_orphan(sk); + ax25 = sk_to_ax25(sk); + ax25_dev = ax25->ax25_dev; +- if (ax25_dev) { +- dev_put(ax25_dev->dev); +- ax25_dev_put(ax25_dev); +- } + + if (sk->sk_type == SOCK_SEQPACKET) { + switch (ax25->state) { +@@ -1055,6 +1051,10 @@ static int ax25_release(struct socket *s + sk->sk_state_change(sk); + ax25_destroy_socket(ax25); + } ++ if (ax25_dev) { ++ dev_put(ax25_dev->dev); ++ ax25_dev_put(ax25_dev); ++ } + + sock->sk = NULL; + release_sock(sk); diff --git a/queue-5.4/ax25-fix-uaf-bugs-in-ax25-timers.patch b/queue-5.4/ax25-fix-uaf-bugs-in-ax25-timers.patch new file mode 100644 index 00000000000..87ef4b951c1 --- /dev/null +++ b/queue-5.4/ax25-fix-uaf-bugs-in-ax25-timers.patch @@ -0,0 +1,80 @@ +From foo@baz Mon Apr 18 01:55:27 PM CEST 2022 +From: Ovidiu Panait +Date: Mon, 18 Apr 2022 09:33:12 +0300 +Subject: ax25: Fix UAF bugs in ax25 timers +To: stable@vger.kernel.org +Message-ID: <20220418063312.1628871-8-ovidiu.panait@windriver.com> + +From: Duoming Zhou + +commit 82e31755e55fbcea6a9dfaae5fe4860ade17cbc0 upstream. + +There are race conditions that may lead to UAF bugs in +ax25_heartbeat_expiry(), ax25_t1timer_expiry(), ax25_t2timer_expiry(), +ax25_t3timer_expiry() and ax25_idletimer_expiry(), when we call +ax25_release() to deallocate ax25_dev. + +One of the UAF bugs caused by ax25_release() is shown below: + + (Thread 1) | (Thread 2) +ax25_dev_device_up() //(1) | +... | ax25_kill_by_device() +ax25_bind() //(2) | +ax25_connect() | ... + ax25_std_establish_data_link() | + ax25_start_t1timer() | ax25_dev_device_down() //(3) + mod_timer(&ax25->t1timer,..) | + | ax25_release() + (wait a time) | ... + | ax25_dev_put(ax25_dev) //(4)FREE + ax25_t1timer_expiry() | + ax25->ax25_dev->values[..] //USE| ... + ... | + +We increase the refcount of ax25_dev in position (1) and (2), and +decrease the refcount of ax25_dev in position (3) and (4). +The ax25_dev will be freed in position (4) and be used in +ax25_t1timer_expiry(). + +The fail log is shown below: +============================================================== + +[ 106.116942] BUG: KASAN: use-after-free in ax25_t1timer_expiry+0x1c/0x60 +[ 106.116942] Read of size 8 at addr ffff88800bda9028 by task swapper/0/0 +[ 106.116942] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.17.0-06123-g0905eec574 +[ 106.116942] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-14 +[ 106.116942] Call Trace: +... +[ 106.116942] ax25_t1timer_expiry+0x1c/0x60 +[ 106.116942] call_timer_fn+0x122/0x3d0 +[ 106.116942] __run_timers.part.0+0x3f6/0x520 +[ 106.116942] run_timer_softirq+0x4f/0xb0 +[ 106.116942] __do_softirq+0x1c2/0x651 +... + +This patch adds del_timer_sync() in ax25_release(), which could ensure +that all timers stop before we deallocate ax25_dev. + +Signed-off-by: Duoming Zhou +Signed-off-by: Paolo Abeni +[OP: backport to 5.4: adjust context] +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + net/ax25/af_ax25.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -1052,6 +1052,11 @@ static int ax25_release(struct socket *s + ax25_destroy_socket(ax25); + } + if (ax25_dev) { ++ del_timer_sync(&ax25->timer); ++ del_timer_sync(&ax25->t1timer); ++ del_timer_sync(&ax25->t2timer); ++ del_timer_sync(&ax25->t3timer); ++ del_timer_sync(&ax25->idletimer); + dev_put(ax25_dev->dev); + ax25_dev_put(ax25_dev); + } diff --git a/queue-5.4/ax25-fix-uaf-bugs-of-net_device-caused-by-rebinding-operation.patch b/queue-5.4/ax25-fix-uaf-bugs-of-net_device-caused-by-rebinding-operation.patch new file mode 100644 index 00000000000..894c38305cd --- /dev/null +++ b/queue-5.4/ax25-fix-uaf-bugs-of-net_device-caused-by-rebinding-operation.patch @@ -0,0 +1,101 @@ +From foo@baz Mon Apr 18 01:55:27 PM CEST 2022 +From: Ovidiu Panait +Date: Mon, 18 Apr 2022 09:33:07 +0300 +Subject: ax25: fix UAF bugs of net_device caused by rebinding operation +To: stable@vger.kernel.org +Message-ID: <20220418063312.1628871-3-ovidiu.panait@windriver.com> + +From: Duoming Zhou + +commit feef318c855a361a1eccd880f33e88c460eb63b4 upstream. + +The ax25_kill_by_device() will set s->ax25_dev = NULL and +call ax25_disconnect() to change states of ax25_cb and +sock, if we call ax25_bind() before ax25_kill_by_device(). + +However, if we call ax25_bind() again between the window of +ax25_kill_by_device() and ax25_dev_device_down(), the values +and states changed by ax25_kill_by_device() will be reassigned. + +Finally, ax25_dev_device_down() will deallocate net_device. +If we dereference net_device in syscall functions such as +ax25_release(), ax25_sendmsg(), ax25_getsockopt(), ax25_getname() +and ax25_info_show(), a UAF bug will occur. + +One of the possible race conditions is shown below: + + (USE) | (FREE) +ax25_bind() | + | ax25_kill_by_device() +ax25_bind() | +ax25_connect() | ... + | ax25_dev_device_down() + | ... + | dev_put_track(dev, ...) //FREE +ax25_release() | ... + ax25_send_control() | + alloc_skb() //USE | + +the corresponding fail log is shown below: +=============================================================== +BUG: KASAN: use-after-free in ax25_send_control+0x43/0x210 +... +Call Trace: + ... + ax25_send_control+0x43/0x210 + ax25_release+0x2db/0x3b0 + __sock_release+0x6d/0x120 + sock_close+0xf/0x20 + __fput+0x11f/0x420 + ... +Allocated by task 1283: + ... + __kasan_kmalloc+0x81/0xa0 + alloc_netdev_mqs+0x5a/0x680 + mkiss_open+0x6c/0x380 + tty_ldisc_open+0x55/0x90 + ... +Freed by task 1969: + ... + kfree+0xa3/0x2c0 + device_release+0x54/0xe0 + kobject_put+0xa5/0x120 + tty_ldisc_kill+0x3e/0x80 + ... + +In order to fix these UAF bugs caused by rebinding operation, +this patch adds dev_hold_track() into ax25_bind() and +corresponding dev_put_track() into ax25_kill_by_device(). + +Signed-off-by: Duoming Zhou +Signed-off-by: David S. Miller +[OP: backport to 5.4: adjust dev_put_track()->dev_put() and +dev_hold_track()->dev_hold()] +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + net/ax25/af_ax25.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -98,6 +98,7 @@ again: + spin_unlock_bh(&ax25_list_lock); + lock_sock(sk); + s->ax25_dev = NULL; ++ dev_put(ax25_dev->dev); + ax25_dev_put(ax25_dev); + release_sock(sk); + ax25_disconnect(s, ENETUNREACH); +@@ -1122,8 +1123,10 @@ static int ax25_bind(struct socket *sock + } + } + +- if (ax25_dev != NULL) ++ if (ax25_dev) { + ax25_fillin_cb(ax25, ax25_dev); ++ dev_hold(ax25_dev->dev); ++ } + + done: + ax25_cb_add(ax25); diff --git a/queue-5.4/series b/queue-5.4/series index 6c48c934815..3f09c7469e4 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -53,3 +53,11 @@ dm-integrity-fix-memory-corruption-when-tag_size-is-less-than-digest-size.patch smp-fix-offline-cpu-check-in-flush_smp_call_function_queue.patch i2c-pasemi-wait-for-write-xfers-to-finish.patch dma-direct-avoid-redundant-memory-sync-for-swiotlb.patch +ax25-add-refcount-in-ax25_dev-to-avoid-uaf-bugs.patch +ax25-fix-reference-count-leaks-of-ax25_dev.patch +ax25-fix-uaf-bugs-of-net_device-caused-by-rebinding-operation.patch +ax25-fix-refcount-leaks-caused-by-ax25_cb_del.patch +ax25-fix-uaf-bug-in-ax25_send_control.patch +ax25-fix-npd-bug-in-ax25_disconnect.patch +ax25-fix-null-pointer-dereferences-in-ax25-timers.patch +ax25-fix-uaf-bugs-in-ax25-timers.patch