From: Greg Kroah-Hartman Date: Mon, 12 Jan 2026 11:14:55 +0000 (+0100) Subject: 5.10-stable patches X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7db21d3e2b4b854c14c15ee29cb4ab09d3abc7f1;p=thirdparty%2Fkernel%2Fstable-queue.git 5.10-stable patches added patches: bpf-sockmap-don-t-let-sock_map_-close-destroy-unhash-call-itself.patch ext4-fix-out-of-bound-read-in-ext4_xattr_inode_dec_ref_all.patch ext4-introduce-itail-helper.patch net-add-locking-to-protect-skb-dev-access-in-ip_output.patch net-netdevice-add-operation-ndo_sk_get_lower_dev.patch tls-use-__sk_dst_get-and-dst_dev_rcu-in-get_netdev_for_sock.patch --- diff --git a/queue-5.10/bpf-sockmap-don-t-let-sock_map_-close-destroy-unhash-call-itself.patch b/queue-5.10/bpf-sockmap-don-t-let-sock_map_-close-destroy-unhash-call-itself.patch new file mode 100644 index 0000000000..8a72d620d4 --- /dev/null +++ b/queue-5.10/bpf-sockmap-don-t-let-sock_map_-close-destroy-unhash-call-itself.patch @@ -0,0 +1,106 @@ +From 5b4a79ba65a1ab479903fff2e604865d229b70a9 Mon Sep 17 00:00:00 2001 +From: Jakub Sitnicki +Date: Sat, 21 Jan 2023 13:41:43 +0100 +Subject: bpf, sockmap: Don't let sock_map_{close,destroy,unhash} call itself + +From: Jakub Sitnicki + +commit 5b4a79ba65a1ab479903fff2e604865d229b70a9 upstream. + +sock_map proto callbacks should never call themselves by design. Protect +against bugs like [1] and break out of the recursive loop to avoid a stack +overflow in favor of a resource leak. + +[1] https://lore.kernel.org/all/00000000000073b14905ef2e7401@google.com/ + +Suggested-by: Eric Dumazet +Signed-off-by: Jakub Sitnicki +Acked-by: John Fastabend +Link: https://lore.kernel.org/r/20230113-sockmap-fix-v2-1-1e0ee7ac2f90@cloudflare.com +Signed-off-by: Alexei Starovoitov +[Harinadh: Modified to apply on v5.10.y ] +Signed-off-by: Harinadh Dommaraju +Signed-off-by: Greg Kroah-Hartman +--- + net/core/sock_map.c | 53 +++++++++++++++++++++++++++++----------------------- + 1 file changed, 30 insertions(+), 23 deletions(-) + +--- a/net/core/sock_map.c ++++ b/net/core/sock_map.c +@@ -1558,15 +1558,16 @@ void sock_map_unhash(struct sock *sk) + psock = sk_psock(sk); + if (unlikely(!psock)) { + rcu_read_unlock(); +- if (sk->sk_prot->unhash) +- sk->sk_prot->unhash(sk); +- return; ++ saved_unhash = READ_ONCE(sk->sk_prot)->unhash; ++ } else { ++ saved_unhash = psock->saved_unhash; ++ sock_map_remove_links(sk, psock); ++ rcu_read_unlock(); + } +- +- saved_unhash = psock->saved_unhash; +- sock_map_remove_links(sk, psock); +- rcu_read_unlock(); +- saved_unhash(sk); ++ if (WARN_ON_ONCE(saved_unhash == sock_map_unhash)) ++ return; ++ if (saved_unhash) ++ saved_unhash(sk); + } + + void sock_map_destroy(struct sock *sk) +@@ -1578,16 +1579,17 @@ void sock_map_destroy(struct sock *sk) + psock = sk_psock_get(sk); + if (unlikely(!psock)) { + rcu_read_unlock(); +- if (sk->sk_prot->destroy) +- sk->sk_prot->destroy(sk); +- return; ++ saved_destroy = READ_ONCE(sk->sk_prot)->destroy; ++ } else { ++ saved_destroy = psock->saved_destroy; ++ sock_map_remove_links(sk, psock); ++ rcu_read_unlock(); ++ sk_psock_put(sk, psock); + } +- +- saved_destroy = psock->saved_destroy; +- sock_map_remove_links(sk, psock); +- rcu_read_unlock(); +- sk_psock_put(sk, psock); +- saved_destroy(sk); ++ if (WARN_ON_ONCE(saved_destroy == sock_map_destroy)) ++ return; ++ if (saved_destroy) ++ saved_destroy(sk); + } + EXPORT_SYMBOL_GPL(sock_map_destroy); + +@@ -1602,13 +1604,18 @@ void sock_map_close(struct sock *sk, lon + if (unlikely(!psock)) { + rcu_read_unlock(); + release_sock(sk); +- return sk->sk_prot->close(sk, timeout); ++ saved_close = READ_ONCE(sk->sk_prot)->close; ++ } else { ++ saved_close = psock->saved_close; ++ sock_map_remove_links(sk, psock); ++ rcu_read_unlock(); ++ release_sock(sk); + } +- +- saved_close = psock->saved_close; +- sock_map_remove_links(sk, psock); +- rcu_read_unlock(); +- release_sock(sk); ++ /* Make sure we do not recurse. This is a bug. ++ * Leak the socket instead of crashing on a stack overflow. ++ */ ++ if (WARN_ON_ONCE(saved_close == sock_map_close)) ++ return; + saved_close(sk, timeout); + } + diff --git a/queue-5.10/ext4-fix-out-of-bound-read-in-ext4_xattr_inode_dec_ref_all.patch b/queue-5.10/ext4-fix-out-of-bound-read-in-ext4_xattr_inode_dec_ref_all.patch new file mode 100644 index 0000000000..50d868be52 --- /dev/null +++ b/queue-5.10/ext4-fix-out-of-bound-read-in-ext4_xattr_inode_dec_ref_all.patch @@ -0,0 +1,194 @@ +From stable+bounces-207877-greg=kroah.com@vger.kernel.org Fri Jan 9 16:24:10 2026 +From: "David Nyström" +Date: Fri, 09 Jan 2026 16:23:14 +0100 +Subject: ext4: fix out-of-bound read in ext4_xattr_inode_dec_ref_all() +To: stable@vger.kernel.org +Cc: "Theodore Ts'o" , "Ye Bin" , "Sasha Levin" , "David Nyström" , "Jan Kara" +Message-ID: <20260109-ext4_splat-v3-2-bb8dfefb8f38@est.tech> + +From: Ye Bin + +[ Upstream commit 5701875f9609b000d91351eaa6bfd97fe2f157f4 ] + +There's issue as follows: +BUG: KASAN: use-after-free in ext4_xattr_inode_dec_ref_all+0x6ff/0x790 +Read of size 4 at addr ffff88807b003000 by task syz-executor.0/15172 + +CPU: 3 PID: 15172 Comm: syz-executor.0 +Call Trace: + __dump_stack lib/dump_stack.c:82 [inline] + dump_stack+0xbe/0xfd lib/dump_stack.c:123 + print_address_description.constprop.0+0x1e/0x280 mm/kasan/report.c:400 + __kasan_report.cold+0x6c/0x84 mm/kasan/report.c:560 + kasan_report+0x3a/0x50 mm/kasan/report.c:585 + ext4_xattr_inode_dec_ref_all+0x6ff/0x790 fs/ext4/xattr.c:1137 + ext4_xattr_delete_inode+0x4c7/0xda0 fs/ext4/xattr.c:2896 + ext4_evict_inode+0xb3b/0x1670 fs/ext4/inode.c:323 + evict+0x39f/0x880 fs/inode.c:622 + iput_final fs/inode.c:1746 [inline] + iput fs/inode.c:1772 [inline] + iput+0x525/0x6c0 fs/inode.c:1758 + ext4_orphan_cleanup fs/ext4/super.c:3298 [inline] + ext4_fill_super+0x8c57/0xba40 fs/ext4/super.c:5300 + mount_bdev+0x355/0x410 fs/super.c:1446 + legacy_get_tree+0xfe/0x220 fs/fs_context.c:611 + vfs_get_tree+0x8d/0x2f0 fs/super.c:1576 + do_new_mount fs/namespace.c:2983 [inline] + path_mount+0x119a/0x1ad0 fs/namespace.c:3316 + do_mount+0xfc/0x110 fs/namespace.c:3329 + __do_sys_mount fs/namespace.c:3540 [inline] + __se_sys_mount+0x219/0x2e0 fs/namespace.c:3514 + do_syscall_64+0x33/0x40 arch/x86/entry/common.c:46 + entry_SYSCALL_64_after_hwframe+0x67/0xd1 + +Memory state around the buggy address: + ffff88807b002f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + ffff88807b002f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +>ffff88807b003000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ^ + ffff88807b003080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ffff88807b003100: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + +Above issue happens as ext4_xattr_delete_inode() isn't check xattr +is valid if xattr is in inode. +To solve above issue call xattr_check_inode() check if xattr if valid +in inode. In fact, we can directly verify in ext4_iget_extra_inode(), +so that there is no divergent verification. + +Fixes: e50e5129f384 ("ext4: xattr-in-inode support") +Signed-off-by: Ye Bin +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20250208063141.1539283-3-yebin@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: David Nyström +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/inode.c | 5 +++++ + fs/ext4/xattr.c | 26 +------------------------- + fs/ext4/xattr.h | 7 +++++++ + 3 files changed, 13 insertions(+), 25 deletions(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4650,6 +4650,11 @@ static inline int ext4_iget_extra_inode( + *magic == cpu_to_le32(EXT4_XATTR_MAGIC)) { + int err; + ++ err = xattr_check_inode(inode, IHDR(inode, raw_inode), ++ ITAIL(inode, raw_inode)); ++ if (err) ++ return err; ++ + ext4_set_inode_state(inode, EXT4_STATE_XATTR); + err = ext4_find_inline_data_nolock(inode); + if (!err && ext4_has_inline_data(inode)) +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -263,7 +263,7 @@ errout: + __ext4_xattr_check_block((inode), (bh), __func__, __LINE__) + + +-static int ++int + __xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header, + void *end, const char *function, unsigned int line) + { +@@ -280,9 +280,6 @@ errout: + return error; + } + +-#define xattr_check_inode(inode, header, end) \ +- __xattr_check_inode((inode), (header), (end), __func__, __LINE__) +- + static int + xattr_find_entry(struct inode *inode, struct ext4_xattr_entry **pentry, + void *end, int name_index, const char *name, int sorted) +@@ -600,9 +597,6 @@ ext4_xattr_ibody_get(struct inode *inode + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); + end = ITAIL(inode, raw_inode); +- error = xattr_check_inode(inode, header, end); +- if (error) +- goto cleanup; + entry = IFIRST(header); + error = xattr_find_entry(inode, &entry, end, name_index, name, 0); + if (error) +@@ -734,7 +728,6 @@ ext4_xattr_ibody_list(struct dentry *den + struct ext4_xattr_ibody_header *header; + struct ext4_inode *raw_inode; + struct ext4_iloc iloc; +- void *end; + int error; + + if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) +@@ -744,14 +737,9 @@ ext4_xattr_ibody_list(struct dentry *den + return error; + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); +- end = ITAIL(inode, raw_inode); +- error = xattr_check_inode(inode, header, end); +- if (error) +- goto cleanup; + error = ext4_xattr_list_entries(dentry, IFIRST(header), + buffer, buffer_size); + +-cleanup: + brelse(iloc.bh); + return error; + } +@@ -815,7 +803,6 @@ int ext4_get_inode_usage(struct inode *i + struct ext4_xattr_ibody_header *header; + struct ext4_xattr_entry *entry; + qsize_t ea_inode_refs = 0; +- void *end; + int ret; + + lockdep_assert_held_read(&EXT4_I(inode)->xattr_sem); +@@ -826,10 +813,6 @@ int ext4_get_inode_usage(struct inode *i + goto out; + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); +- end = ITAIL(inode, raw_inode); +- ret = xattr_check_inode(inode, header, end); +- if (ret) +- goto out; + + for (entry = IFIRST(header); !IS_LAST_ENTRY(entry); + entry = EXT4_XATTR_NEXT(entry)) +@@ -2221,9 +2204,6 @@ int ext4_xattr_ibody_find(struct inode * + is->s.here = is->s.first; + is->s.end = ITAIL(inode, raw_inode); + if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { +- error = xattr_check_inode(inode, header, is->s.end); +- if (error) +- return error; + /* Find the named attribute. */ + error = xattr_find_entry(inode, &is->s.here, is->s.end, + i->name_index, i->name, 0); +@@ -2747,10 +2727,6 @@ retry: + min_offs = end - base; + total_ino = sizeof(struct ext4_xattr_ibody_header) + sizeof(u32); + +- error = xattr_check_inode(inode, header, end); +- if (error) +- goto cleanup; +- + ifree = ext4_xattr_free_space(base, &min_offs, base, &total_ino); + if (ifree >= isize_diff) + goto shift; +--- a/fs/ext4/xattr.h ++++ b/fs/ext4/xattr.h +@@ -210,6 +210,13 @@ extern int ext4_xattr_ibody_set(handle_t + extern struct mb_cache *ext4_xattr_create_cache(void); + extern void ext4_xattr_destroy_cache(struct mb_cache *); + ++extern int ++__xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header, ++ void *end, const char *function, unsigned int line); ++ ++#define xattr_check_inode(inode, header, end) \ ++ __xattr_check_inode((inode), (header), (end), __func__, __LINE__) ++ + #ifdef CONFIG_EXT4_FS_SECURITY + extern int ext4_init_security(handle_t *handle, struct inode *inode, + struct inode *dir, const struct qstr *qstr); diff --git a/queue-5.10/ext4-introduce-itail-helper.patch b/queue-5.10/ext4-introduce-itail-helper.patch new file mode 100644 index 0000000000..033bf11da1 --- /dev/null +++ b/queue-5.10/ext4-introduce-itail-helper.patch @@ -0,0 +1,84 @@ +From stable+bounces-207876-greg=kroah.com@vger.kernel.org Fri Jan 9 16:24:07 2026 +From: "David Nyström" +Date: Fri, 09 Jan 2026 16:23:13 +0100 +Subject: ext4: introduce ITAIL helper +To: stable@vger.kernel.org +Cc: "Theodore Ts'o" , "Ye Bin" , "Sasha Levin" , "David Nyström" , "Jan Kara" +Message-ID: <20260109-ext4_splat-v3-1-bb8dfefb8f38@est.tech> + +From: Ye Bin + +[ Upstream commit 69f3a3039b0d0003de008659cafd5a1eaaa0a7a4 ] + +Introduce ITAIL helper to get the bound of xattr in inode. + +Signed-off-by: Ye Bin +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20250208063141.1539283-2-yebin@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: David Nyström +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/xattr.c | 10 +++++----- + fs/ext4/xattr.h | 3 +++ + 2 files changed, 8 insertions(+), 5 deletions(-) + +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -599,7 +599,7 @@ ext4_xattr_ibody_get(struct inode *inode + return error; + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); +- end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; ++ end = ITAIL(inode, raw_inode); + error = xattr_check_inode(inode, header, end); + if (error) + goto cleanup; +@@ -744,7 +744,7 @@ ext4_xattr_ibody_list(struct dentry *den + return error; + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); +- end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; ++ end = ITAIL(inode, raw_inode); + error = xattr_check_inode(inode, header, end); + if (error) + goto cleanup; +@@ -826,7 +826,7 @@ int ext4_get_inode_usage(struct inode *i + goto out; + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); +- end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; ++ end = ITAIL(inode, raw_inode); + ret = xattr_check_inode(inode, header, end); + if (ret) + goto out; +@@ -2219,7 +2219,7 @@ int ext4_xattr_ibody_find(struct inode * + header = IHDR(inode, raw_inode); + is->s.base = is->s.first = IFIRST(header); + is->s.here = is->s.first; +- is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; ++ is->s.end = ITAIL(inode, raw_inode); + if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { + error = xattr_check_inode(inode, header, is->s.end); + if (error) +@@ -2743,7 +2743,7 @@ retry: + */ + + base = IFIRST(header); +- end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; ++ end = ITAIL(inode, raw_inode); + min_offs = end - base; + total_ino = sizeof(struct ext4_xattr_ibody_header) + sizeof(u32); + +--- a/fs/ext4/xattr.h ++++ b/fs/ext4/xattr.h +@@ -68,6 +68,9 @@ struct ext4_xattr_entry { + ((void *)raw_inode + \ + EXT4_GOOD_OLD_INODE_SIZE + \ + EXT4_I(inode)->i_extra_isize)) ++#define ITAIL(inode, raw_inode) \ ++ ((void *)(raw_inode) + \ ++ EXT4_SB((inode)->i_sb)->s_inode_size) + #define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1)) + + /* diff --git a/queue-5.10/net-add-locking-to-protect-skb-dev-access-in-ip_output.patch b/queue-5.10/net-add-locking-to-protect-skb-dev-access-in-ip_output.patch new file mode 100644 index 0000000000..05c0925c9d --- /dev/null +++ b/queue-5.10/net-add-locking-to-protect-skb-dev-access-in-ip_output.patch @@ -0,0 +1,119 @@ +From stable+bounces-208038-greg=kroah.com@vger.kernel.org Mon Jan 12 07:34:47 2026 +From: Keerthana K +Date: Mon, 12 Jan 2026 06:30:37 +0000 +Subject: net: Add locking to protect skb->dev access in ip_output +To: stable@vger.kernel.org, gregkh@linuxfoundation.org +Cc: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, yoshfuji@linux-ipv6.org, dsahern@kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bpf@vger.kernel.org, borisp@nvidia.com, john.fastabend@gmail.com, sashal@kernel.org, leitao@debian.org, kuniyu@amazon.com, willemb@google.com, jramaseu@redhat.com, aviadye@mellanox.com, ilyal@mellanox.com, ajay.kaher@broadcom.com, alexey.makhalov@broadcom.com, vamsi-krishna.brahmajosyula@broadcom.com, yin.ding@broadcom.com, tapas.kundu@broadcom.com, Sharath Chandra Vurukala , Keerthana K +Message-ID: <20260112063039.2968980-2-keerthana.kalyanasundaram@broadcom.com> + +From: Sharath Chandra Vurukala + +[ Upstream commit 1dbf1d590d10a6d1978e8184f8dfe20af22d680a] + +In ip_output() skb->dev is updated from the skb_dst(skb)->dev +this can become invalid when the interface is unregistered and freed, + +Introduced new skb_dst_dev_rcu() function to be used instead of +skb_dst_dev() within rcu_locks in ip_output.This will ensure that +all the skb's associated with the dev being deregistered will +be transnmitted out first, before freeing the dev. + +Given that ip_output() is called within an rcu_read_lock() +critical section or from a bottom-half context, it is safe to introduce +an RCU read-side critical section within it. + +Multiple panic call stacks were observed when UL traffic was run +in concurrency with device deregistration from different functions, +pasting one sample for reference. + +[496733.627565][T13385] Call trace: +[496733.627570][T13385] bpf_prog_ce7c9180c3b128ea_cgroupskb_egres+0x24c/0x7f0 +[496733.627581][T13385] __cgroup_bpf_run_filter_skb+0x128/0x498 +[496733.627595][T13385] ip_finish_output+0xa4/0xf4 +[496733.627605][T13385] ip_output+0x100/0x1a0 +[496733.627613][T13385] ip_send_skb+0x68/0x100 +[496733.627618][T13385] udp_send_skb+0x1c4/0x384 +[496733.627625][T13385] udp_sendmsg+0x7b0/0x898 +[496733.627631][T13385] inet_sendmsg+0x5c/0x7c +[496733.627639][T13385] __sys_sendto+0x174/0x1e4 +[496733.627647][T13385] __arm64_sys_sendto+0x28/0x3c +[496733.627653][T13385] invoke_syscall+0x58/0x11c +[496733.627662][T13385] el0_svc_common+0x88/0xf4 +[496733.627669][T13385] do_el0_svc+0x2c/0xb0 +[496733.627676][T13385] el0_svc+0x2c/0xa4 +[496733.627683][T13385] el0t_64_sync_handler+0x68/0xb4 +[496733.627689][T13385] el0t_64_sync+0x1a4/0x1a8 + +Changes in v3: +- Replaced WARN_ON() with WARN_ON_ONCE(), as suggested by Willem de Bruijn. +- Dropped legacy lines mistakenly pulled in from an outdated branch. + +Changes in v2: +- Addressed review comments from Eric Dumazet +- Used READ_ONCE() to prevent potential load/store tearing +- Added skb_dst_dev_rcu() and used along with rcu_read_lock() in ip_output + +Signed-off-by: Sharath Chandra Vurukala +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20250730105118.GA26100@hu-sharathv-hyd.qualcomm.com +Signed-off-by: Jakub Kicinski +[ Keerthana: Backported the patch to v5.10.y ] +Signed-off-by: Keerthana K +Signed-off-by: Greg Kroah-Hartman +--- + include/net/dst.h | 12 ++++++++++++ + net/ipv4/ip_output.c | 16 +++++++++++----- + 2 files changed, 23 insertions(+), 5 deletions(-) + +--- a/include/net/dst.h ++++ b/include/net/dst.h +@@ -547,6 +547,18 @@ static inline void skb_dst_update_pmtu_n + dst->ops->update_pmtu(dst, NULL, skb, mtu, false); + } + ++static inline struct net_device *dst_dev_rcu(const struct dst_entry *dst) ++{ ++ /* In the future, use rcu_dereference(dst->dev) */ ++ WARN_ON_ONCE(!rcu_read_lock_held()); ++ return READ_ONCE(dst->dev); ++} ++ ++static inline struct net_device *skb_dst_dev_rcu(const struct sk_buff *skb) ++{ ++ return dst_dev_rcu(skb_dst(skb)); ++} ++ + struct dst_entry *dst_blackhole_check(struct dst_entry *dst, u32 cookie); + void dst_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk, + struct sk_buff *skb, u32 mtu, bool confirm_neigh); +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -429,17 +429,23 @@ int ip_mc_output(struct net *net, struct + + int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb) + { +- struct net_device *dev = skb_dst(skb)->dev, *indev = skb->dev; ++ struct net_device *dev, *indev = skb->dev; ++ int ret_val; ++ ++ rcu_read_lock(); ++ dev = skb_dst_dev_rcu(skb); + + IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len); + + skb->dev = dev; + skb->protocol = htons(ETH_P_IP); + +- return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, +- net, sk, skb, indev, dev, +- ip_finish_output, +- !(IPCB(skb)->flags & IPSKB_REROUTED)); ++ ret_val = NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, ++ net, sk, skb, indev, dev, ++ ip_finish_output, ++ !(IPCB(skb)->flags & IPSKB_REROUTED)); ++ rcu_read_unlock(); ++ return ret_val; + } + EXPORT_SYMBOL(ip_output); + diff --git a/queue-5.10/net-netdevice-add-operation-ndo_sk_get_lower_dev.patch b/queue-5.10/net-netdevice-add-operation-ndo_sk_get_lower_dev.patch new file mode 100644 index 0000000000..37cad1079b --- /dev/null +++ b/queue-5.10/net-netdevice-add-operation-ndo_sk_get_lower_dev.patch @@ -0,0 +1,90 @@ +From stable+bounces-208039-greg=kroah.com@vger.kernel.org Mon Jan 12 07:35:17 2026 +From: Keerthana K +Date: Mon, 12 Jan 2026 06:30:38 +0000 +Subject: net: netdevice: Add operation ndo_sk_get_lower_dev +To: stable@vger.kernel.org, gregkh@linuxfoundation.org +Cc: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, yoshfuji@linux-ipv6.org, dsahern@kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bpf@vger.kernel.org, borisp@nvidia.com, john.fastabend@gmail.com, sashal@kernel.org, leitao@debian.org, kuniyu@amazon.com, willemb@google.com, jramaseu@redhat.com, aviadye@mellanox.com, ilyal@mellanox.com, ajay.kaher@broadcom.com, alexey.makhalov@broadcom.com, vamsi-krishna.brahmajosyula@broadcom.com, yin.ding@broadcom.com, tapas.kundu@broadcom.com, Tariq Toukan , Keerthana K +Message-ID: <20260112063039.2968980-3-keerthana.kalyanasundaram@broadcom.com> + +From: Tariq Toukan + +[ Upstream commit 719a402cf60311b1cdff3f6320abaecdcc5e46b7] + +ndo_sk_get_lower_dev returns the lower netdev that corresponds to +a given socket. +Additionally, we implement a helper netdev_sk_get_lowest_dev() to get +the lowest one in chain. + +Signed-off-by: Tariq Toukan +Reviewed-by: Boris Pismenny +Signed-off-by: Jakub Kicinski +[ Keerthana: Backported the patch to v5.10.y ] +Signed-off-by: Keerthana K +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/netdevice.h | 4 ++++ + net/core/dev.c | 33 +++++++++++++++++++++++++++++++++ + 2 files changed, 37 insertions(+) + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1435,6 +1435,8 @@ struct net_device_ops { + struct net_device* (*ndo_get_xmit_slave)(struct net_device *dev, + struct sk_buff *skb, + bool all_slaves); ++ struct net_device* (*ndo_sk_get_lower_dev)(struct net_device *dev, ++ struct sock *sk); + netdev_features_t (*ndo_fix_features)(struct net_device *dev, + netdev_features_t features); + int (*ndo_set_features)(struct net_device *dev, +@@ -2914,6 +2916,8 @@ int init_dummy_netdev(struct net_device + struct net_device *netdev_get_xmit_slave(struct net_device *dev, + struct sk_buff *skb, + bool all_slaves); ++struct net_device *netdev_sk_get_lowest_dev(struct net_device *dev, ++ struct sock *sk); + struct net_device *dev_get_by_index(struct net *net, int ifindex); + struct net_device *__dev_get_by_index(struct net *net, int ifindex); + struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex); +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -8169,6 +8169,39 @@ struct net_device *netdev_get_xmit_slave + } + EXPORT_SYMBOL(netdev_get_xmit_slave); + ++static struct net_device *netdev_sk_get_lower_dev(struct net_device *dev, ++ struct sock *sk) ++{ ++ const struct net_device_ops *ops = dev->netdev_ops; ++ ++ if (!ops->ndo_sk_get_lower_dev) ++ return NULL; ++ return ops->ndo_sk_get_lower_dev(dev, sk); ++} ++ ++/** ++ * netdev_sk_get_lowest_dev - Get the lowest device in chain given device and socket ++ * @dev: device ++ * @sk: the socket ++ * ++ * %NULL is returned if no lower device is found. ++ */ ++ ++struct net_device *netdev_sk_get_lowest_dev(struct net_device *dev, ++ struct sock *sk) ++{ ++ struct net_device *lower; ++ ++ lower = netdev_sk_get_lower_dev(dev, sk); ++ while (lower) { ++ dev = lower; ++ lower = netdev_sk_get_lower_dev(dev, sk); ++ } ++ ++ return dev; ++} ++EXPORT_SYMBOL(netdev_sk_get_lowest_dev); ++ + static void netdev_adjacent_add_links(struct net_device *dev) + { + struct netdev_adjacent *iter; diff --git a/queue-5.10/series b/queue-5.10/series index c5647c889b..24d7f4834d 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -419,3 +419,9 @@ wifi-avoid-kernel-infoleak-from-struct-iw_point.patch libceph-replace-overzealous-bug_on-in-osdmap_apply_incremental.patch libceph-make-free_choose_arg_map-resilient-to-partial-allocation.patch libceph-make-calc_target-set-t-paused-not-just-clear-it.patch +ext4-introduce-itail-helper.patch +ext4-fix-out-of-bound-read-in-ext4_xattr_inode_dec_ref_all.patch +net-add-locking-to-protect-skb-dev-access-in-ip_output.patch +net-netdevice-add-operation-ndo_sk_get_lower_dev.patch +tls-use-__sk_dst_get-and-dst_dev_rcu-in-get_netdev_for_sock.patch +bpf-sockmap-don-t-let-sock_map_-close-destroy-unhash-call-itself.patch diff --git a/queue-5.10/tls-use-__sk_dst_get-and-dst_dev_rcu-in-get_netdev_for_sock.patch b/queue-5.10/tls-use-__sk_dst_get-and-dst_dev_rcu-in-get_netdev_for_sock.patch new file mode 100644 index 0000000000..f9e489d400 --- /dev/null +++ b/queue-5.10/tls-use-__sk_dst_get-and-dst_dev_rcu-in-get_netdev_for_sock.patch @@ -0,0 +1,66 @@ +From stable+bounces-208040-greg=kroah.com@vger.kernel.org Mon Jan 12 07:34:25 2026 +From: Keerthana K +Date: Mon, 12 Jan 2026 06:30:39 +0000 +Subject: tls: Use __sk_dst_get() and dst_dev_rcu() in get_netdev_for_sock(). +To: stable@vger.kernel.org, gregkh@linuxfoundation.org +Cc: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, yoshfuji@linux-ipv6.org, dsahern@kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bpf@vger.kernel.org, borisp@nvidia.com, john.fastabend@gmail.com, sashal@kernel.org, leitao@debian.org, kuniyu@amazon.com, willemb@google.com, jramaseu@redhat.com, aviadye@mellanox.com, ilyal@mellanox.com, ajay.kaher@broadcom.com, alexey.makhalov@broadcom.com, vamsi-krishna.brahmajosyula@broadcom.com, yin.ding@broadcom.com, tapas.kundu@broadcom.com, Kuniyuki Iwashima , Sabrina Dubroca , Keerthana K +Message-ID: <20260112063039.2968980-4-keerthana.kalyanasundaram@broadcom.com> + +From: Kuniyuki Iwashima + +[ Upstream commit c65f27b9c3be2269918e1cbad6d8884741f835c5 ] + +get_netdev_for_sock() is called during setsockopt(), +so not under RCU. + +Using sk_dst_get(sk)->dev could trigger UAF. + +Let's use __sk_dst_get() and dst_dev_rcu(). + +Note that the only ->ndo_sk_get_lower_dev() user is +bond_sk_get_lower_dev(), which uses RCU. + +Fixes: e8f69799810c ("net/tls: Add generic NIC offload infrastructure") +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Reviewed-by: Sabrina Dubroca +Link: https://patch.msgid.link/20250916214758.650211-6-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +[ Keerthana: Backported the patch to v5.10.y ] +Signed-off-by: Keerthana K +Signed-off-by: Greg Kroah-Hartman +--- + net/tls/tls_device.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +--- a/net/tls/tls_device.c ++++ b/net/tls/tls_device.c +@@ -113,17 +113,19 @@ unlock: + /* We assume that the socket is already connected */ + static struct net_device *get_netdev_for_sock(struct sock *sk) + { +- struct dst_entry *dst = sk_dst_get(sk); +- struct net_device *netdev = NULL; ++ struct net_device *dev, *lowest_dev = NULL; ++ struct dst_entry *dst; + +- if (likely(dst)) { +- netdev = dst->dev; +- dev_hold(netdev); ++ rcu_read_lock(); ++ dst = __sk_dst_get(sk); ++ dev = dst ? dst_dev_rcu(dst) : NULL; ++ if (likely(dev)) { ++ lowest_dev = netdev_sk_get_lowest_dev(dev, sk); ++ dev_hold(lowest_dev); + } ++ rcu_read_unlock(); + +- dst_release(dst); +- +- return netdev; ++ return lowest_dev; + } + + static void destroy_record(struct tls_record_info *record)