summaryrefslogtreecommitdiffstats
path: root/include/net/netns/ipv6.h
diff options
context:
space:
mode:
authorJinke Han <jinkehan@didiglobal.com>2026-09-08 15:37:42 +0800
committerIngo Molnar <mingo@kernel.org>2026-09-17 09:48:42 +0200
commita5f7a5bb3b7f28ba7e4fa246775b29a0e5537255 (patch)
tree73fef824f9a846cf935869d0dbc5070ef6e2f741 /include/net/netns/ipv6.h
downloadlinux-stable-a5f7a5bb3b7f28ba7e4fa246775b29a0e5537255.tar.gz
linux-stable-a5f7a5bb3b7f28ba7e4fa246775b29a0e5537255.zip
x86/kprobes: Fix crash when probing CS CALL instructionsgrafted
When using eBPF to probe CS CALL instructions within a function, a crash can be triggered. The eBPF tool probes offset 257 of the __hrtimer_run_queues() function: <__hrtimer_run_queues+249>: nopl 0x0(%rax,%rax,1) <__hrtimer_run_queues+254>: mov %r14,%rdi <__hrtimer_run_queues+257>: cs call <__x86_indirect_thunk_r12> <__hrtimer_run_queues+263>: mov %eax,%r12d <__hrtimer_run_queues+266>: xchg %ax,%ax <__hrtimer_run_queues+268>: mov %r13,%rdi Which triggers this crash: BUG: unable to handle page fault for address: 00000000000f41c9 #PF: supervisor write access in kernel mode #PF: error_code(0x0002) - not-present page PGD 0 P4D 0 Oops: 0002 [#1] SMP NOPTI CPU: 1 PID: 0 Comm: swapper/1 Kdump: loaded Tainted: P RIP: 0010:__hrtimer_run_queues+0x106/0x230 Note that __hrtimer_run_queues+0x106 is __hrtimer_run_queues+262, which is at the 6th byte of the above CS CALL instruction. Since the CS CALL instruction occupies 6 bytes, the exception occurred in the middle of that call instruction. The root cause is that when using eBPF tools to probe in the middle of a function, a kprobe with INT3 is used as the underlying implementation. During single-step emulation of the original CALL instruction, int3_emulate_call() assumes that the probed CALL instruction is 5 bytes long. However, the actual CS-prefixed CALL instruction occupies 6 bytes, so it constructs an incorrect exception return address. When the CPU returns from the kprobe handler, the next instruction to be executed is at the address of the last byte of that CS CALL instruction. Coincidentally, starting from that address, the CPU fetches and decodes a completely different instruction, which ultimately triggers a kernel crash. Fix the issue by using the actual instruction length obtained from the instruction decoder when constructing the exception return address, rather than relying on the hardcoded CALL_INSN_SIZE macro. [ mingo: Refined the changelog ] Fixes: 6256e668b7af ("x86/kprobes: Use int3 instead of debug trap for single-step") Suggested-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Signed-off-by: Jinke Han <jinkehan@didiglobal.com> Signed-off-by: Ingo Molnar <mingo@kernel.org> Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Acked-by: Yafang Shao <laoar.shao@gmail.com> Acked-by: Borislav Petkov <bp@alien8.de> Cc: Peter Zijlstra <peterz@infradead.org> Link: https://patch.msgid.link/20260908073742.GA10517@didi-ThinkCentre-M920t-N000
Diffstat (limited to 'include/net/netns/ipv6.h')
-rw-r--r--include/net/netns/ipv6.h138
1 files changed, 138 insertions, 0 deletions
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
new file mode 100644
index 000000000..ffda15318
--- /dev/null
+++ b/include/net/netns/ipv6.h
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ipv6 in net namespaces
+ */
+
+#include <net/inet_frag.h>
+
+#ifndef __NETNS_IPV6_H__
+#define __NETNS_IPV6_H__
+#include <net/dst_ops.h>
+#include <uapi/linux/icmpv6.h>
+
+struct ctl_table_header;
+
+struct netns_sysctl_ipv6 {
+#ifdef CONFIG_SYSCTL
+ struct ctl_table_header *hdr;
+ struct ctl_table_header *route_hdr;
+ struct ctl_table_header *icmp_hdr;
+ struct ctl_table_header *frags_hdr;
+ struct ctl_table_header *xfrm6_hdr;
+#endif
+ int flush_delay;
+ int ip6_rt_max_size;
+ int ip6_rt_gc_min_interval;
+ int ip6_rt_gc_timeout;
+ int ip6_rt_gc_interval;
+ int ip6_rt_gc_elasticity;
+ int ip6_rt_mtu_expires;
+ int ip6_rt_min_advmss;
+ u32 multipath_hash_fields;
+ u8 multipath_hash_policy;
+
+ __cacheline_group_begin(sysctl_ipv6_flowlabel);
+ u8 flowlabel_consistency;
+ u8 auto_flowlabels;
+ u8 flowlabel_state_ranges;
+ __cacheline_group_end(sysctl_ipv6_flowlabel);
+
+ u8 icmpv6_echo_ignore_all;
+ u8 icmpv6_echo_ignore_multicast;
+ u8 icmpv6_echo_ignore_anycast;
+ int icmpv6_time;
+ DECLARE_BITMAP(icmpv6_ratemask, ICMPV6_MSG_MAX + 1);
+ unsigned long *icmpv6_ratemask_ptr;
+ u8 anycast_src_echo_reply;
+ u8 bindv6only;
+ u8 ip_nonlocal_bind;
+ u8 fwmark_reflect;
+ int idgen_retries;
+ int idgen_delay;
+ int flowlabel_reflect;
+ int max_dst_opts_cnt;
+ int max_hbh_opts_cnt;
+ int max_dst_opts_len;
+ int max_hbh_opts_len;
+ int seg6_flowlabel;
+ u32 ioam6_id;
+ u64 ioam6_id_wide;
+ u8 skip_notify_on_dev_down;
+ u8 fib_notify_on_flag_change;
+ u8 icmpv6_error_anycast_as_unicast;
+ u8 icmpv6_errors_extension_mask;
+};
+
+struct netns_ipv6 {
+ /* Keep ip6_dst_ops at the beginning of netns_sysctl_ipv6 */
+ struct dst_ops ip6_dst_ops;
+
+ struct netns_sysctl_ipv6 sysctl;
+ struct ipv6_devconf *devconf_all;
+ struct ipv6_devconf *devconf_dflt;
+ struct inet_peer_base *peers;
+ struct fqdir *fqdir;
+ struct fib6_info *fib6_null_entry;
+ struct rt6_info *ip6_null_entry;
+ struct rt6_statistics *rt6_stats;
+ struct timer_list ip6_fib_timer;
+ struct hlist_head *fib_table_hash;
+ spinlock_t fib_table_hash_lock;
+ struct fib6_table *fib6_main_tbl;
+ struct list_head fib6_walkers;
+ rwlock_t fib6_walker_lock;
+ spinlock_t fib6_gc_lock;
+ atomic_t ip6_rt_gc_expire;
+ unsigned long ip6_rt_last_gc;
+ unsigned char flowlabel_has_excl;
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ bool fib6_has_custom_rules;
+ unsigned int fib6_rules_require_fldissect;
+#ifdef CONFIG_IPV6_SUBTREES
+ unsigned int fib6_routes_require_src;
+#endif
+ struct rt6_info *ip6_prohibit_entry;
+ struct rt6_info *ip6_blk_hole_entry;
+ struct fib6_table *fib6_local_tbl;
+ struct fib_rules_ops *fib6_rules_ops;
+#endif
+ struct sock *ndisc_sk;
+ struct sock *tcp_sk;
+ struct sock *igmp_sk;
+ struct sock *mc_autojoin_sk;
+
+ struct hlist_head *inet6_addr_lst;
+ spinlock_t addrconf_hash_lock;
+ struct delayed_work addr_chk_work;
+
+#ifdef CONFIG_IPV6_MROUTE
+#ifndef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
+ struct mr_table *mrt6;
+#else
+ struct list_head mr6_tables;
+ struct fib_rules_ops *mr6_rules_ops;
+#endif
+ struct fib_notifier_ops *ip6mr_notifier_ops;
+ atomic_t ipmr_seq;
+ struct mutex mfc_mutex;
+#endif
+ atomic_t dev_addr_genid;
+ atomic_t fib6_sernum;
+ struct seg6_pernet_data *seg6_data;
+ struct fib_notifier_ops *notifier_ops;
+ int flowlabel_count;
+ struct {
+ struct hlist_head head;
+ spinlock_t lock;
+ u32 seq;
+ } ip6addrlbl_table;
+ struct ioam6_pernet_data *ioam6_data;
+};
+
+#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
+struct netns_nf_frag {
+ struct fqdir *fqdir;
+};
+#endif
+
+#endif