| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/24 22:59 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"IPV6_MROUTE",
"IPV6_MROUTE_MULTIPLE_TABLES",
"IPV6_PIMSM_V2"
],
"FocusSymbols": [
"ip6_mroute_setsockopt",
"ip6_mroute_getsockopt",
"ip6mr_ioctl",
"ip6mr_compat_ioctl",
"ip6_mr_input",
"ip6_mr_output",
"pim6_rcv",
"reg_vif_xmit",
"mroute6_is_socket",
"ip6mr_sk_done"
],
"Reasoning": "The patch introduces reference counting to IPv6 multicast routing tables (struct mr_table) to fix potential use-after-free issues. It modifies various entry points (socket options, ioctls, netlink, packet rx/tx) to hold a reference to the table while in use. This is a functional change in core networking logic that should be fuzzed.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/24 22:59 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 4db5f8da09e1abd60bbbee540777c4ac0f2c72d1\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Fri Jul 24 22:59:29 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/include/linux/mroute_base.h b/include/linux/mroute_base.h\nindex 4d55827e970537..536fa324620273 100644\n--- a/include/linux/mroute_base.h\n+++ b/include/linux/mroute_base.h\n@@ -2,8 +2,10 @@\n #define __LINUX_MROUTE_BASE_H\n \n #include \u003clinux/netdevice.h\u003e\n+#include \u003clinux/refcount.h\u003e\n #include \u003clinux/rhashtable-types.h\u003e\n #include \u003clinux/spinlock.h\u003e\n+#include \u003clinux/workqueue.h\u003e\n #include \u003cnet/net_namespace.h\u003e\n #include \u003cnet/sock.h\u003e\n #include \u003cnet/fib_notifier.h\u003e\n@@ -242,6 +244,8 @@ struct mr_table_ops {\n * @mroute_do_assert: Whether to inform userspace on wrong ingress\n * @mroute_do_pim: Whether to receive IGMP PIMv1\n * @mroute_reg_vif_num: PIM-device vif index\n+ * @refcnt: lifetime pins for this table\n+ * @destroy_work: process-context cleanup before final RCU free\n */\n struct mr_table {\n \tstruct rcu_work\t\twork;\n@@ -261,6 +265,8 @@ struct mr_table {\n \tbool\t\t\tmroute_do_pim;\n \tbool\t\t\tmroute_do_wrvifwhole;\n \tint\t\t\tmroute_reg_vif_num;\n+\trefcount_t\t\trefcnt;\n+\tstruct work_struct\tdestroy_work;\n };\n \n static inline bool mr_can_free_table(struct net *net)\ndiff --git a/net/ipv4/ipmr_base.c b/net/ipv4/ipmr_base.c\nindex 867b24beded112..9710789cfaf994 100644\n--- a/net/ipv4/ipmr_base.c\n+++ b/net/ipv4/ipmr_base.c\n@@ -32,8 +32,10 @@ static void __mr_free_table(struct work_struct *work)\n {\n \tstruct mr_table *mrt = container_of(to_rcu_work(work),\n \t\t\t\t\t struct mr_table, work);\n+\tstruct net *net = read_pnet(\u0026mrt-\u003enet);\n \n \trhltable_destroy(\u0026mrt-\u003emfc_hash);\n+\tput_net(net);\n \tkfree(mrt);\n }\n \n@@ -56,11 +58,12 @@ mr_table_alloc(struct net *net, u32 id,\n \tif (!mrt)\n \t\treturn ERR_PTR(-ENOMEM);\n \tmrt-\u003eid = id;\n-\twrite_pnet(\u0026mrt-\u003enet, net);\n+\twrite_pnet(\u0026mrt-\u003enet, get_net(net));\n \n \tmrt-\u003eops = *ops;\n \terr = rhltable_init(\u0026mrt-\u003emfc_hash, mrt-\u003eops.rht_params);\n \tif (err) {\n+\t\tput_net(read_pnet(\u0026mrt-\u003enet));\n \t\tkfree(mrt);\n \t\treturn ERR_PTR(err);\n \t}\n@@ -72,6 +75,7 @@ mr_table_alloc(struct net *net, u32 id,\n \ttimer_setup(\u0026mrt-\u003eipmr_expire_timer, expire_func, 0);\n \n \tmrt-\u003emroute_reg_vif_num = -1;\n+\trefcount_set(\u0026mrt-\u003erefcnt, 1);\n \ttable_set(mrt, net);\n \treturn mrt;\n }\ndiff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c\nindex 604a58838901a7..94bb00bdff98c8 100644\n--- a/net/ipv6/ip6mr.c\n+++ b/net/ipv6/ip6mr.c\n@@ -87,6 +87,11 @@ static struct kmem_cache *mrt_cachep __read_mostly;\n static struct mr_table *ip6mr_new_table(struct net *net, u32 id);\n static void ip6mr_free_table(struct mr_table *mrt,\n \t\t\t struct list_head *dev_kill_list);\n+static void ip6mr_free_table_work(struct work_struct *work);\n+static struct mr_table *ip6mr_get_table_hold(struct net *net, u32 id);\n+static void ip6mr_put_table(struct mr_table *mrt);\n+static void __ip6mr_put_table(struct mr_table *mrt,\n+\t\t\t struct list_head *dev_kill_list);\n \n static void ip6_mr_forward(struct net *net, struct mr_table *mrt,\n \t\t\t struct net_device *dev, struct sk_buff *skb,\n@@ -179,7 +184,7 @@ static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,\n \n \targ-\u003etable = fib_rule_get_table(rule, arg);\n \n-\tmrt = __ip6mr_get_table(rule-\u003efr_net, arg-\u003etable);\n+\tmrt = ip6mr_get_table_hold(rule-\u003efr_net, arg-\u003etable);\n \tif (!mrt)\n \t\treturn -EAGAIN;\n \tres-\u003emrt = mrt;\n@@ -271,7 +276,8 @@ static void __net_exit ip6mr_rules_exit_rtnl(struct net *net,\n \n \tlist_for_each_entry_safe(mrt, next, \u0026net-\u003eipv6.mr6_tables, list) {\n \t\tlist_del_rcu(\u0026mrt-\u003elist);\n-\t\tip6mr_free_table(mrt, dev_kill_list);\n+\t\tsynchronize_rcu();\n+\t\t__ip6mr_put_table(mrt, dev_kill_list);\n \t}\n }\n \n@@ -314,7 +320,7 @@ static struct mr_table *__ip6mr_get_table(struct net *net, u32 id)\n static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,\n \t\t\t struct mr_table **mrt)\n {\n-\t*mrt = rcu_dereference(net-\u003eipv6.mrt6);\n+\t*mrt = ip6mr_get_table_hold(net, RT6_TABLE_DFLT);\n \tif (!*mrt)\n \t\treturn -EAGAIN;\n \treturn 0;\n@@ -342,7 +348,8 @@ static void __net_exit ip6mr_rules_exit_rtnl(struct net *net,\n \tstruct mr_table *mrt = rcu_dereference_protected(net-\u003eipv6.mrt6, 1);\n \n \tRCU_INIT_POINTER(net-\u003eipv6.mrt6, NULL);\n-\tip6mr_free_table(mrt, dev_kill_list);\n+\tsynchronize_rcu();\n+\t__ip6mr_put_table(mrt, dev_kill_list);\n }\n \n static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb,\n@@ -368,6 +375,44 @@ static struct mr_table *ip6mr_get_table(struct net *net, u32 id)\n \treturn mrt;\n }\n \n+static struct mr_table *ip6mr_get_table_hold(struct net *net, u32 id)\n+{\n+\tstruct mr_table *mrt;\n+\n+\trcu_read_lock();\n+\tmrt = __ip6mr_get_table(net, id);\n+\tif (mrt \u0026\u0026 !refcount_inc_not_zero(\u0026mrt-\u003erefcnt))\n+\t\tmrt = NULL;\n+\trcu_read_unlock();\n+\n+\treturn mrt;\n+}\n+\n+static void __ip6mr_put_table(struct mr_table *mrt,\n+\t\t\t struct list_head *head)\n+{\n+\tstruct list_head *dev_kill_list;\n+\tLIST_HEAD(local_dev_kill_list);\n+\n+\tif (!refcount_dec_and_test(\u0026mrt-\u003erefcnt))\n+\t\treturn;\n+\n+\tif (!lockdep_rtnl_is_held()) {\n+\t\tschedule_work(\u0026mrt-\u003edestroy_work);\n+\t\treturn;\n+\t}\n+\n+\tdev_kill_list = head ? head : \u0026local_dev_kill_list;\n+\tip6mr_free_table(mrt, dev_kill_list);\n+\tif (!head)\n+\t\tunregister_netdevice_many(dev_kill_list);\n+}\n+\n+static void ip6mr_put_table(struct mr_table *mrt)\n+{\n+\t__ip6mr_put_table(mrt, NULL);\n+}\n+\n static int ip6mr_hash_cmp(struct rhashtable_compare_arg *arg,\n \t\t\t const void *ptr)\n {\n@@ -413,8 +458,12 @@ static struct mr_table *ip6mr_new_table(struct net *net, u32 id)\n \tif (mrt)\n \t\treturn mrt;\n \n-\treturn mr_table_alloc(net, id, \u0026ip6mr_mr_table_ops,\n-\t\t\t ipmr_expire_process, ip6mr_new_table_set);\n+\tmrt = mr_table_alloc(net, id, \u0026ip6mr_mr_table_ops,\n+\t\t\t ipmr_expire_process, ip6mr_new_table_set);\n+\tif (!IS_ERR(mrt))\n+\t\tINIT_WORK(\u0026mrt-\u003edestroy_work, ip6mr_free_table_work);\n+\n+\treturn mrt;\n }\n \n static void ip6mr_free_table(struct mr_table *mrt,\n@@ -423,8 +472,6 @@ static void ip6mr_free_table(struct mr_table *mrt,\n \tstruct net *net = read_pnet(\u0026mrt-\u003enet);\n \tLIST_HEAD(ip6mr_dev_kill_list);\n \n-\tWARN_ON_ONCE(!mr_can_free_table(net));\n-\n \ttimer_shutdown_sync(\u0026mrt-\u003eipmr_expire_timer);\n \tmroute_clean_tables(mrt, MRT6_FLUSH_MIFS | MRT6_FLUSH_MIFS_STATIC |\n \t\t\t MRT6_FLUSH_MFC | MRT6_FLUSH_MFC_STATIC,\n@@ -436,6 +483,17 @@ static void ip6mr_free_table(struct mr_table *mrt,\n \tlist_splice(\u0026ip6mr_dev_kill_list, dev_kill_list);\n }\n \n+static void ip6mr_free_table_work(struct work_struct *work)\n+{\n+\tstruct mr_table *mrt = container_of(work, struct mr_table, destroy_work);\n+\tLIST_HEAD(dev_kill_list);\n+\n+\trtnl_lock();\n+\tip6mr_free_table(mrt, \u0026dev_kill_list);\n+\tunregister_netdevice_many(\u0026dev_kill_list);\n+\trtnl_unlock();\n+}\n+\n #ifdef CONFIG_PROC_FS\n /* The /proc interfaces to multicast routing\n * /proc/ip6_mr_cache /proc/ip6_mr_vif\n@@ -569,7 +627,7 @@ static int pim6_rcv(struct sk_buff *skb)\n \tstruct ipv6hdr *encap;\n \tstruct net_device *reg_dev = NULL;\n \tstruct net *net = dev_net(skb-\u003edev);\n-\tstruct mr_table *mrt;\n+\tstruct mr_table *mrt = NULL;\n \tstruct flowi6 fl6 = {\n \t\t.flowi6_iif\t= skb-\u003edev-\u003eifindex,\n \t\t.flowi6_mark\t= skb-\u003emark,\n@@ -617,9 +675,12 @@ static int pim6_rcv(struct sk_buff *skb)\n \tskb_tunnel_rx(skb, reg_dev, dev_net(reg_dev));\n \n \tnetif_rx(skb);\n+\tip6mr_put_table(mrt);\n \n \treturn 0;\n drop:\n+\tif (mrt)\n+\t\tip6mr_put_table(mrt);\n \tkfree_skb(skb);\n \treturn 0;\n }\n@@ -634,7 +695,7 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,\n \t\t\t\t struct net_device *dev)\n {\n \tstruct net *net = dev_net(dev);\n-\tstruct mr_table *mrt;\n+\tstruct mr_table *mrt = NULL;\n \tstruct flowi6 fl6 = {\n \t\t.flowi6_oif\t= dev-\u003eifindex,\n \t\t.flowi6_iif\t= skb-\u003eskb_iif ? : LOOPBACK_IFINDEX,\n@@ -655,12 +716,15 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,\n \tip6mr_cache_report(mrt, skb, READ_ONCE(mrt-\u003emroute_reg_vif_num),\n \t\t\t MRT6MSG_WHOLEPKT);\n \trcu_read_unlock();\n+\tip6mr_put_table(mrt);\n \tkfree_skb(skb);\n \treturn NETDEV_TX_OK;\n \n tx_lookup_err:\n \trcu_read_unlock();\n tx_err:\n+\tif (mrt)\n+\t\tip6mr_put_table(mrt);\n \tDEV_STATS_INC(dev, tx_errors);\n \tkfree_skb(skb);\n \treturn NETDEV_TX_OK;\n@@ -1615,12 +1679,13 @@ static void mroute_clean_tables(struct mr_table *mrt, int flags,\n \t}\n }\n \n-static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)\n+static int __ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)\n {\n \tint err = 0;\n \tstruct net *net = sock_net(sk);\n \n-\trtnl_lock();\n+\tASSERT_RTNL();\n+\n \tspin_lock(\u0026mrt_lock);\n \tif (rtnl_dereference(mrt-\u003emroute_sk)) {\n \t\terr = -EADDRINUSE;\n@@ -1628,6 +1693,7 @@ static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)\n \t\trcu_assign_pointer(mrt-\u003emroute_sk, sk);\n \t\tsock_set_flag(sk, SOCK_RCU_FREE);\n \t\tatomic_inc(\u0026net-\u003eipv6.devconf_all-\u003emc_forwarding);\n+\t\trefcount_inc(\u0026mrt-\u003erefcnt);\n \t}\n \tspin_unlock(\u0026mrt_lock);\n \n@@ -1636,7 +1702,6 @@ static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)\n \t\t\t\t\t NETCONFA_MC_FORWARDING,\n \t\t\t\t\t NETCONFA_IFINDEX_ALL,\n \t\t\t\t\t net-\u003eipv6.devconf_all);\n-\trtnl_unlock();\n \n \treturn err;\n }\n@@ -1646,6 +1711,7 @@ int ip6mr_sk_done(struct sock *sk)\n \tstruct net *net = sock_net(sk);\n \tstruct ipv6_devconf *devconf;\n \tLIST_HEAD(dev_kill_list);\n+\tstruct mr_table *free_mrt = NULL;\n \tstruct mr_table *mrt;\n \tint err = -EACCES;\n \n@@ -1675,6 +1741,15 @@ int ip6mr_sk_done(struct sock *sk)\n \n \t\t\tmroute_clean_tables(mrt, MRT6_FLUSH_MIFS | MRT6_FLUSH_MFC,\n \t\t\t\t\t \u0026dev_kill_list);\n+\t\t\tif (mrt-\u003eid != RT6_TABLE_DFLT \u0026\u0026\n+\t\t\t !READ_ONCE(mrt-\u003emaxvif) \u0026\u0026\n+\t\t\t !READ_ONCE(mrt-\u003ecache_resolve_queue_len) \u0026\u0026\n+\t\t\t list_empty(\u0026mrt-\u003emfc_cache_list) \u0026\u0026\n+\t\t\t list_empty(\u0026mrt-\u003emfc_unres_queue) \u0026\u0026\n+\t\t\t READ_ONCE(mrt-\u003emroute_reg_vif_num) \u003c 0) {\n+\t\t\t\tlist_del_rcu(\u0026mrt-\u003elist);\n+\t\t\t\tfree_mrt = mrt;\n+\t\t\t}\n \t\t\terr = 0;\n \t\t\tbreak;\n \t\t}\n@@ -1682,6 +1757,14 @@ int ip6mr_sk_done(struct sock *sk)\n \tunregister_netdevice_many(\u0026dev_kill_list);\n \trtnl_unlock();\n \n+\tif (!err)\n+\t\tip6mr_put_table(mrt);\n+\n+\tif (free_mrt) {\n+\t\tsynchronize_rcu();\n+\t\tip6mr_put_table(free_mrt);\n+\t}\n+\n \treturn err;\n }\n \n@@ -1693,11 +1776,15 @@ bool mroute6_is_socket(struct net *net, struct sk_buff *skb)\n \t\t.flowi6_oif\t= skb-\u003edev-\u003eifindex,\n \t\t.flowi6_mark\t= skb-\u003emark,\n \t};\n+\tbool ret;\n \n \tif (ip6mr_fib_lookup(net, \u0026fl6, \u0026mrt) \u003c 0)\n \t\treturn NULL;\n \n-\treturn rcu_access_pointer(mrt-\u003emroute_sk);\n+\tret = rcu_access_pointer(mrt-\u003emroute_sk);\n+\tip6mr_put_table(mrt);\n+\n+\treturn ret;\n }\n EXPORT_SYMBOL(mroute6_is_socket);\n \n@@ -1716,20 +1803,24 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,\n \tstruct mf6cctl mfc;\n \tmifi_t mifi;\n \tstruct net *net = sock_net(sk);\n-\tstruct mr_table *mrt;\n+\tstruct mr_table *mrt = NULL;\n+\tu32 table = raw6_sk(sk)-\u003eip6mr_table ? : RT6_TABLE_DFLT;\n \n \tif (sk-\u003esk_type != SOCK_RAW ||\n \t inet_sk(sk)-\u003einet_num != IPPROTO_ICMPV6)\n \t\treturn -EOPNOTSUPP;\n \n-\tmrt = ip6mr_get_table(net, raw6_sk(sk)-\u003eip6mr_table ? : RT6_TABLE_DFLT);\n-\tif (!mrt)\n-\t\treturn -ENOENT;\n-\n-\tif (optname != MRT6_INIT) {\n+\tif (optname != MRT6_INIT \u0026\u0026\n+\t optname != MRT6_TABLE \u0026\u0026\n+\t optname != MRT6_DONE) {\n+\t\tmrt = ip6mr_get_table_hold(net, table);\n+\t\tif (!mrt)\n+\t\t\treturn -ENOENT;\n \t\tif (sk != rcu_access_pointer(mrt-\u003emroute_sk) \u0026\u0026\n-\t\t !ns_capable(net-\u003euser_ns, CAP_NET_ADMIN))\n+\t\t !ns_capable(net-\u003euser_ns, CAP_NET_ADMIN)) {\n+\t\t\tip6mr_put_table(mrt);\n \t\t\treturn -EACCES;\n+\t\t}\n \t}\n \n \tswitch (optname) {\n@@ -1737,32 +1828,41 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,\n \t\tif (optlen \u003c sizeof(int))\n \t\t\treturn -EINVAL;\n \n-\t\treturn ip6mr_sk_init(mrt, sk);\n+\t\trtnl_lock();\n+\t\tmrt = ip6mr_new_table(net, table);\n+\t\tif (!IS_ERR(mrt))\n+\t\t\tret = __ip6mr_sk_init(mrt, sk);\n+\t\telse\n+\t\t\tret = PTR_ERR(mrt);\n+\t\trtnl_unlock();\n+\t\treturn ret;\n \n \tcase MRT6_DONE:\n \t\treturn ip6mr_sk_done(sk);\n \n \tcase MRT6_ADD_MIF:\n \t\tif (optlen \u003c sizeof(vif))\n-\t\t\treturn -EINVAL;\n+\t\t\tgoto out_put_table_einval;\n \t\tif (copy_from_sockptr(\u0026vif, optval, sizeof(vif)))\n-\t\t\treturn -EFAULT;\n+\t\t\tgoto out_put_table_efault;\n \t\tif (vif.mif6c_mifi \u003e= MAXMIFS)\n-\t\t\treturn -ENFILE;\n+\t\t\tgoto out_put_table_enfile;\n \t\trtnl_lock();\n \t\tret = mif6_add(net, mrt, \u0026vif,\n \t\t\t sk == rtnl_dereference(mrt-\u003emroute_sk));\n \t\trtnl_unlock();\n+\t\tip6mr_put_table(mrt);\n \t\treturn ret;\n \n \tcase MRT6_DEL_MIF:\n \t\tif (optlen \u003c sizeof(mifi_t))\n-\t\t\treturn -EINVAL;\n+\t\t\tgoto out_put_table_einval;\n \t\tif (copy_from_sockptr(\u0026mifi, optval, sizeof(mifi_t)))\n-\t\t\treturn -EFAULT;\n+\t\t\tgoto out_put_table_efault;\n \t\trtnl_lock();\n \t\tret = mif6_delete(mrt, mifi, 0, NULL);\n \t\trtnl_unlock();\n+\t\tip6mr_put_table(mrt);\n \t\treturn ret;\n \n \t/*\n@@ -1776,9 +1876,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,\n \tcase MRT6_ADD_MFC_PROXY:\n \tcase MRT6_DEL_MFC_PROXY:\n \t\tif (optlen \u003c sizeof(mfc))\n-\t\t\treturn -EINVAL;\n+\t\t\tgoto out_put_table_einval;\n \t\tif (copy_from_sockptr(\u0026mfc, optval, sizeof(mfc)))\n-\t\t\treturn -EFAULT;\n+\t\t\tgoto out_put_table_efault;\n \t\tif (parent == 0)\n \t\t\tparent = mfc.mf6cc_parent;\n \n@@ -1793,6 +1893,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,\n \t\t\t\t\t parent);\n \n \t\tmutex_unlock(\u0026net-\u003eipv6.mfc_mutex);\n+\t\tip6mr_put_table(mrt);\n \t\treturn ret;\n \n \tcase MRT6_FLUSH:\n@@ -1801,14 +1902,15 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,\n \t\tint flags;\n \n \t\tif (optlen != sizeof(flags))\n-\t\t\treturn -EINVAL;\n+\t\t\tgoto out_put_table_einval;\n \t\tif (copy_from_sockptr(\u0026flags, optval, sizeof(flags)))\n-\t\t\treturn -EFAULT;\n+\t\t\tgoto out_put_table_efault;\n \n \t\trtnl_lock();\n \t\tmroute_clean_tables(mrt, flags, \u0026dev_kill_list);\n \t\tunregister_netdevice_many(\u0026dev_kill_list);\n \t\trtnl_unlock();\n+\t\tip6mr_put_table(mrt);\n \t\treturn 0;\n \t}\n \n@@ -1820,10 +1922,11 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,\n \t\tint v;\n \n \t\tif (optlen != sizeof(v))\n-\t\t\treturn -EINVAL;\n+\t\t\tgoto out_put_table_einval;\n \t\tif (copy_from_sockptr(\u0026v, optval, sizeof(v)))\n-\t\t\treturn -EFAULT;\n+\t\t\tgoto out_put_table_efault;\n \t\tWRITE_ONCE(mrt-\u003emroute_do_assert, v);\n+\t\tip6mr_put_table(mrt);\n \t\treturn 0;\n \t}\n \n@@ -1834,9 +1937,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,\n \t\tint v;\n \n \t\tif (optlen != sizeof(v))\n-\t\t\treturn -EINVAL;\n+\t\t\tgoto out_put_table_einval;\n \t\tif (copy_from_sockptr(\u0026v, optval, sizeof(v)))\n-\t\t\treturn -EFAULT;\n+\t\t\tgoto out_put_table_efault;\n \n \t\tdo_wrmifwhole = (v == MRT6MSG_WRMIFWHOLE);\n \t\tv = !!v;\n@@ -1848,6 +1951,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,\n \t\t\tWRITE_ONCE(mrt-\u003emroute_do_wrvifwhole, do_wrmifwhole);\n \t\t}\n \t\trtnl_unlock();\n+\t\tip6mr_put_table(mrt);\n \t\treturn ret;\n \t}\n \n@@ -1864,18 +1968,22 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,\n \t\t/* \"pim6reg%u\" should not exceed 16 bytes (IFNAMSIZ) */\n \t\tif (v != RT_TABLE_DEFAULT \u0026\u0026 v \u003e= 100000000)\n \t\t\treturn -EINVAL;\n-\t\tif (sk == rcu_access_pointer(mrt-\u003emroute_sk))\n+\n+\t\tmrt = ip6mr_get_table_hold(net, table);\n+\t\tif (mrt \u0026\u0026 sk == rcu_access_pointer(mrt-\u003emroute_sk)) {\n+\t\t\tip6mr_put_table(mrt);\n \t\t\treturn -EBUSY;\n+\t\t}\n+\t\tif (!ns_capable(net-\u003euser_ns, CAP_NET_ADMIN)) {\n+\t\t\tif (mrt)\n+\t\t\t\tip6mr_put_table(mrt);\n+\t\t\treturn -EACCES;\n+\t\t}\n+\t\tif (mrt)\n+\t\t\tip6mr_put_table(mrt);\n \n-\t\trtnl_lock();\n-\t\tret = 0;\n-\t\tmrt = ip6mr_new_table(net, v);\n-\t\tif (IS_ERR(mrt))\n-\t\t\tret = PTR_ERR(mrt);\n-\t\telse\n-\t\t\traw6_sk(sk)-\u003eip6mr_table = v;\n-\t\trtnl_unlock();\n-\t\treturn ret;\n+\t\traw6_sk(sk)-\u003eip6mr_table = v;\n+\t\treturn 0;\n \t}\n #endif\n \t/*\n@@ -1883,8 +1991,25 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,\n \t *\tset.\n \t */\n \tdefault:\n+\t\tif (mrt)\n+\t\t\tip6mr_put_table(mrt);\n \t\treturn -ENOPROTOOPT;\n \t}\n+\n+out_put_table_efault:\n+\tif (mrt)\n+\t\tip6mr_put_table(mrt);\n+\treturn -EFAULT;\n+\n+out_put_table_einval:\n+\tif (mrt)\n+\t\tip6mr_put_table(mrt);\n+\treturn -EINVAL;\n+\n+out_put_table_enfile:\n+\tif (mrt)\n+\t\tip6mr_put_table(mrt);\n+\treturn -ENFILE;\n }\n \n /*\n@@ -1895,6 +2020,7 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,\n \t\t\t sockptr_t optlen)\n {\n \tint olr;\n+\tint ret = 0;\n \tint val;\n \tstruct net *net = sock_net(sk);\n \tstruct mr_table *mrt;\n@@ -1903,7 +2029,7 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,\n \t inet_sk(sk)-\u003einet_num != IPPROTO_ICMPV6)\n \t\treturn -EOPNOTSUPP;\n \n-\tmrt = ip6mr_get_table(net, raw6_sk(sk)-\u003eip6mr_table ? : RT6_TABLE_DFLT);\n+\tmrt = ip6mr_get_table_hold(net, raw6_sk(sk)-\u003eip6mr_table ? : RT6_TABLE_DFLT);\n \tif (!mrt)\n \t\treturn -ENOENT;\n \n@@ -1920,26 +2046,33 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,\n \t\tval = READ_ONCE(mrt-\u003emroute_do_assert);\n \t\tbreak;\n \tdefault:\n-\t\treturn -ENOPROTOOPT;\n+\t\tret = -ENOPROTOOPT;\n+\t\tgoto out;\n \t}\n \n-\tif (copy_from_sockptr(\u0026olr, optlen, sizeof(int)))\n-\t\treturn -EFAULT;\n+\tif (copy_from_sockptr(\u0026olr, optlen, sizeof(int))) {\n+\t\tret = -EFAULT;\n+\t\tgoto out;\n+\t}\n \n \tolr = min_t(int, olr, sizeof(int));\n-\tif (olr \u003c 0)\n-\t\treturn -EINVAL;\n+\tif (olr \u003c 0) {\n+\t\tret = -EINVAL;\n+\t\tgoto out;\n+\t}\n \n-\tif (copy_to_sockptr(optlen, \u0026olr, sizeof(int)))\n-\t\treturn -EFAULT;\n-\tif (copy_to_sockptr(optval, \u0026val, olr))\n-\t\treturn -EFAULT;\n-\treturn 0;\n+\tif (copy_to_sockptr(optlen, \u0026olr, sizeof(int)) ||\n+\t copy_to_sockptr(optval, \u0026val, olr))\n+\t\tret = -EFAULT;\n+out:\n+\tip6mr_put_table(mrt);\n+\treturn ret;\n }\n \n /*\n *\tThe IP multicast ioctl support routines.\n */\n+\n int ip6mr_ioctl(struct sock *sk, int cmd, void *arg)\n {\n \tstruct sioc_sg_req6 *sr;\n@@ -1949,7 +2082,7 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void *arg)\n \tstruct net *net = sock_net(sk);\n \tstruct mr_table *mrt;\n \n-\tmrt = ip6mr_get_table(net, raw6_sk(sk)-\u003eip6mr_table ? : RT6_TABLE_DFLT);\n+\tmrt = ip6mr_get_table_hold(net, raw6_sk(sk)-\u003eip6mr_table ? : RT6_TABLE_DFLT);\n \tif (!mrt)\n \t\treturn -ENOENT;\n \n@@ -1957,7 +2090,7 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void *arg)\n \tcase SIOCGETMIFCNT_IN6:\n \t\tvr = (struct sioc_mif_req6 *)arg;\n \t\tif (vr-\u003emifi \u003e= mrt-\u003emaxvif)\n-\t\t\treturn -EINVAL;\n+\t\t\tgoto out_put_table_einval;\n \t\tvr-\u003emifi = array_index_nospec(vr-\u003emifi, mrt-\u003emaxvif);\n \t\trcu_read_lock();\n \t\tvif = \u0026mrt-\u003evif_table[vr-\u003emifi];\n@@ -1967,9 +2100,11 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void *arg)\n \t\t\tvr-\u003eibytes = READ_ONCE(vif-\u003ebytes_in);\n \t\t\tvr-\u003eobytes = READ_ONCE(vif-\u003ebytes_out);\n \t\t\trcu_read_unlock();\n+\t\t\tip6mr_put_table(mrt);\n \t\t\treturn 0;\n \t\t}\n \t\trcu_read_unlock();\n+\t\tip6mr_put_table(mrt);\n \t\treturn -EADDRNOTAVAIL;\n \tcase SIOCGETSGCNT_IN6:\n \t\tsr = (struct sioc_sg_req6 *)arg;\n@@ -1982,15 +2117,21 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void *arg)\n \t\t\tsr-\u003ebytecnt = atomic_long_read(\u0026c-\u003e_c.mfc_un.res.bytes);\n \t\t\tsr-\u003ewrong_if = atomic_long_read(\u0026c-\u003e_c.mfc_un.res.wrong_if);\n \t\t\trcu_read_unlock();\n+\t\t\tip6mr_put_table(mrt);\n \t\t\treturn 0;\n \t\t}\n \t\trcu_read_unlock();\n+\t\tip6mr_put_table(mrt);\n \t\treturn -EADDRNOTAVAIL;\n \tdefault:\n+\t\tip6mr_put_table(mrt);\n \t\treturn -ENOIOCTLCMD;\n \t}\n-}\n \n+out_put_table_einval:\n+\tip6mr_put_table(mrt);\n+\treturn -EINVAL;\n+}\n #ifdef CONFIG_COMPAT\n struct compat_sioc_sg_req6 {\n \tstruct sockaddr_in6 src;\n@@ -2017,16 +2158,16 @@ int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)\n \tstruct net *net = sock_net(sk);\n \tstruct mr_table *mrt;\n \n-\tmrt = ip6mr_get_table(net, raw6_sk(sk)-\u003eip6mr_table ? : RT6_TABLE_DFLT);\n+\tmrt = ip6mr_get_table_hold(net, raw6_sk(sk)-\u003eip6mr_table ? : RT6_TABLE_DFLT);\n \tif (!mrt)\n \t\treturn -ENOENT;\n \n \tswitch (cmd) {\n \tcase SIOCGETMIFCNT_IN6:\n \t\tif (copy_from_user(\u0026vr, arg, sizeof(vr)))\n-\t\t\treturn -EFAULT;\n+\t\t\tgoto out_put_table_efault;\n \t\tif (vr.mifi \u003e= mrt-\u003emaxvif)\n-\t\t\treturn -EINVAL;\n+\t\t\tgoto out_put_table_einval;\n \t\tvr.mifi = array_index_nospec(vr.mifi, mrt-\u003emaxvif);\n \t\trcu_read_lock();\n \t\tvif = \u0026mrt-\u003evif_table[vr.mifi];\n@@ -2038,14 +2179,16 @@ int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)\n \t\t\trcu_read_unlock();\n \n \t\t\tif (copy_to_user(arg, \u0026vr, sizeof(vr)))\n-\t\t\t\treturn -EFAULT;\n+\t\t\t\tgoto out_put_table_efault;\n+\t\t\tip6mr_put_table(mrt);\n \t\t\treturn 0;\n \t\t}\n \t\trcu_read_unlock();\n+\t\tip6mr_put_table(mrt);\n \t\treturn -EADDRNOTAVAIL;\n \tcase SIOCGETSGCNT_IN6:\n \t\tif (copy_from_user(\u0026sr, arg, sizeof(sr)))\n-\t\t\treturn -EFAULT;\n+\t\t\tgoto out_put_table_efault;\n \n \t\trcu_read_lock();\n \t\tc = ip6mr_cache_find(mrt, \u0026sr.src.sin6_addr, \u0026sr.grp.sin6_addr);\n@@ -2056,14 +2199,25 @@ int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)\n \t\t\trcu_read_unlock();\n \n \t\t\tif (copy_to_user(arg, \u0026sr, sizeof(sr)))\n-\t\t\t\treturn -EFAULT;\n+\t\t\t\tgoto out_put_table_efault;\n+\t\t\tip6mr_put_table(mrt);\n \t\t\treturn 0;\n \t\t}\n \t\trcu_read_unlock();\n+\t\tip6mr_put_table(mrt);\n \t\treturn -EADDRNOTAVAIL;\n \tdefault:\n+\t\tip6mr_put_table(mrt);\n \t\treturn -ENOIOCTLCMD;\n \t}\n+\n+out_put_table_efault:\n+\tip6mr_put_table(mrt);\n+\treturn -EFAULT;\n+\n+out_put_table_einval:\n+\tip6mr_put_table(mrt);\n+\treturn -EINVAL;\n }\n #endif\n \n@@ -2392,13 +2546,16 @@ int ip6_mr_input(struct sk_buff *skb)\n \t\tif (vif \u003e= 0) {\n \t\t\tint err = ip6mr_cache_unresolved(mrt, vif, skb, dev);\n \n+\t\t\tip6mr_put_table(mrt);\n \t\t\treturn err;\n \t\t}\n+\t\tip6mr_put_table(mrt);\n \t\tkfree_skb(skb);\n \t\treturn -ENODEV;\n \t}\n \n \tip6_mr_forward(net, mrt, dev, skb, cache);\n+\tip6mr_put_table(mrt);\n \n \treturn 0;\n }\n@@ -2441,19 +2598,25 @@ int ip6_mr_output(struct net *net, struct sock *sk, struct sk_buff *skb)\n \t/* No usable cache entry */\n \tif (!cache) {\n \t\tvif = ip6mr_find_vif(mrt, dev);\n-\t\tif (vif \u003e= 0)\n-\t\t\treturn ip6mr_cache_unresolved(mrt, vif, skb, dev);\n-\t\tgoto ip6_output;\n+\t\tif (vif \u003e= 0) {\n+\t\t\terr = ip6mr_cache_unresolved(mrt, vif, skb, dev);\n+\t\t\tip6mr_put_table(mrt);\n+\t\t\treturn err;\n+\t\t}\n+\t\tgoto out_put;\n \t}\n \n \t/* Wrong interface */\n \tvif = cache-\u003e_c.mfc_parent;\n \tif (rcu_access_pointer(mrt-\u003evif_table[vif].dev) != dev)\n-\t\tgoto ip6_output;\n+\t\tgoto out_put;\n \n \tip6_mr_output_finish(net, mrt, dev, skb, cache);\n+\tip6mr_put_table(mrt);\n \treturn 0;\n \n+out_put:\n+\tip6mr_put_table(mrt);\n ip6_output:\n \treturn ip6_output(net, sk, skb);\n }\n@@ -2755,33 +2918,35 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,\n \t\tgrp = nla_get_in6_addr(tb[RTA_DST]);\n \ttableid = nla_get_u32_default(tb[RTA_TABLE], 0);\n \n-\trcu_read_lock();\n-\n-\tmrt = __ip6mr_get_table(net, tableid ?: RT_TABLE_DEFAULT);\n+\tmrt = ip6mr_get_table_hold(net, tableid ?: RT_TABLE_DEFAULT);\n \tif (!mrt) {\n \t\tNL_SET_ERR_MSG_MOD(extack, \"MR table does not exist\");\n \t\terr = -ENOENT;\n-\t\tgoto err;\n+\t\tgoto err_free;\n \t}\n \n+\trcu_read_lock();\n \tcache = ip6mr_cache_find(mrt, \u0026src, \u0026grp);\n \tif (!cache) {\n+\t\trcu_read_unlock();\n \t\tNL_SET_ERR_MSG_MOD(extack, \"MR cache entry not found\");\n \t\terr = -ENOENT;\n-\t\tgoto err;\n+\t\tgoto err_put;\n \t}\n \n \terr = ip6mr_fill_mroute(mrt, skb, NETLINK_CB(in_skb).portid,\n \t\t\t\tnlh-\u003enlmsg_seq, cache, RTM_NEWROUTE, 0);\n-\tif (err \u003c 0)\n-\t\tgoto err;\n-\n \trcu_read_unlock();\n+\tif (err \u003c 0)\n+\t\tgoto err_put;\n \n-\treturn rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);\n+\terr = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);\n+\tip6mr_put_table(mrt);\n+\treturn err;\n \n-err:\n-\trcu_read_unlock();\n+err_put:\n+\tip6mr_put_table(mrt);\n+err_free:\n \tkfree_skb(skb);\n \treturn err;\n }\n@@ -2804,7 +2969,7 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)\n \tif (filter.table_id) {\n \t\tstruct mr_table *mrt;\n \n-\t\tmrt = __ip6mr_get_table(sock_net(skb-\u003esk), filter.table_id);\n+\t\tmrt = ip6mr_get_table_hold(sock_net(skb-\u003esk), filter.table_id);\n \t\tif (!mrt) {\n \t\t\tif (rtnl_msg_family(cb-\u003enlh) != RTNL_FAMILY_IP6MR) {\n \t\t\t\terr = skb-\u003elen;\n@@ -2818,6 +2983,7 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)\n \n \t\terr = mr_table_dump(mrt, skb, cb, _ip6mr_fill_mroute,\n \t\t\t\t \u0026mfc_unres_lock, \u0026filter);\n+\t\tip6mr_put_table(mrt);\n \t\terr = skb-\u003elen ? : err;\n \t\tgoto unlock;\n \t}\n"
} |
| 2/1 | 2026/07/24 22:59 | agent | patch-evaluator |
0mModel:best-expensive Args: null Results: {
"EnableConfigs": [
"IPV6_MROUTE",
"IPV6_MROUTE_MULTIPLE_TABLES",
"IPV6_PIMSM_V2"
],
"FocusSymbols": [
"ip6_mroute_setsockopt",
"ip6_mroute_getsockopt",
"ip6mr_ioctl",
"ip6mr_compat_ioctl",
"ip6_mr_input",
"ip6_mr_output",
"pim6_rcv",
"reg_vif_xmit",
"mroute6_is_socket",
"ip6mr_sk_done"
],
"Reasoning": "The patch introduces reference counting to IPv6 multicast routing tables (struct mr_table) to fix potential use-after-free issues. It modifies various entry points (socket options, ioctls, netlink, packet rx/tx) to hold a reference to the table while in use. This is a functional change in core networking logic that should be fuzzed.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). - Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed, ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU. - Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove) that are executed only during PCI hot-unplug or sysfs driver unbind operations. If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. Prefer non-static, non-inlined API entrypoint functions over internal static helper functions (which are inlined by the compiler and do not have distinct symbol addresses). 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit 4db5f8da09e1abd60bbbee540777c4ac0f2c72d1
Author: syz-cluster <triage@syzkaller.com>
Date: Fri Jul 24 22:59:29 2026 +0000
syz-cluster: applied patch under review
diff --git a/include/linux/mroute_base.h b/include/linux/mroute_base.h
index 4d55827e970537..536fa324620273 100644
--- a/include/linux/mroute_base.h
+++ b/include/linux/mroute_base.h
@@ -2,8 +2,10 @@
#define __LINUX_MROUTE_BASE_H
#include <linux/netdevice.h>
+#include <linux/refcount.h>
#include <linux/rhashtable-types.h>
#include <linux/spinlock.h>
+#include <linux/workqueue.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/fib_notifier.h>
@@ -242,6 +244,8 @@ struct mr_table_ops {
* @mroute_do_assert: Whether to inform userspace on wrong ingress
* @mroute_do_pim: Whether to receive IGMP PIMv1
* @mroute_reg_vif_num: PIM-device vif index
+ * @refcnt: lifetime pins for this table
+ * @destroy_work: process-context cleanup before final RCU free
*/
struct mr_table {
struct rcu_work work;
@@ -261,6 +265,8 @@ struct mr_table {
bool mroute_do_pim;
bool mroute_do_wrvifwhole;
int mroute_reg_vif_num;
+ refcount_t refcnt;
+ struct work_struct destroy_work;
};
static inline bool mr_can_free_table(struct net *net)
diff --git a/net/ipv4/ipmr_base.c b/net/ipv4/ipmr_base.c
index 867b24beded112..9710789cfaf994 100644
--- a/net/ipv4/ipmr_base.c
+++ b/net/ipv4/ipmr_base.c
@@ -32,8 +32,10 @@ static void __mr_free_table(struct work_struct *work)
{
struct mr_table *mrt = container_of(to_rcu_work(work),
struct mr_table, work);
+ struct net *net = read_pnet(&mrt->net);
rhltable_destroy(&mrt->mfc_hash);
+ put_net(net);
kfree(mrt);
}
@@ -56,11 +58,12 @@ mr_table_alloc(struct net *net, u32 id,
if (!mrt)
return ERR_PTR(-ENOMEM);
mrt->id = id;
- write_pnet(&mrt->net, net);
+ write_pnet(&mrt->net, get_net(net));
mrt->ops = *ops;
err = rhltable_init(&mrt->mfc_hash, mrt->ops.rht_params);
if (err) {
+ put_net(read_pnet(&mrt->net));
kfree(mrt);
return ERR_PTR(err);
}
@@ -72,6 +75,7 @@ mr_table_alloc(struct net *net, u32 id,
timer_setup(&mrt->ipmr_expire_timer, expire_func, 0);
mrt->mroute_reg_vif_num = -1;
+ refcount_set(&mrt->refcnt, 1);
table_set(mrt, net);
return mrt;
}
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 604a58838901a7..94bb00bdff98c8 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -87,6 +87,11 @@ static struct kmem_cache *mrt_cachep __read_mostly;
static struct mr_table *ip6mr_new_table(struct net *net, u32 id);
static void ip6mr_free_table(struct mr_table *mrt,
struct list_head *dev_kill_list);
+static void ip6mr_free_table_work(struct work_struct *work);
+static struct mr_table *ip6mr_get_table_hold(struct net *net, u32 id);
+static void ip6mr_put_table(struct mr_table *mrt);
+static void __ip6mr_put_table(struct mr_table *mrt,
+ struct list_head *dev_kill_list);
static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
struct net_device *dev, struct sk_buff *skb,
@@ -179,7 +184,7 @@ static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
arg->table = fib_rule_get_table(rule, arg);
- mrt = __ip6mr_get_table(rule->fr_net, arg->table);
+ mrt = ip6mr_get_table_hold(rule->fr_net, arg->table);
if (!mrt)
return -EAGAIN;
res->mrt = mrt;
@@ -271,7 +276,8 @@ static void __net_exit ip6mr_rules_exit_rtnl(struct net *net,
list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
list_del_rcu(&mrt->list);
- ip6mr_free_table(mrt, dev_kill_list);
+ synchronize_rcu();
+ __ip6mr_put_table(mrt, dev_kill_list);
}
}
@@ -314,7 +320,7 @@ static struct mr_table *__ip6mr_get_table(struct net *net, u32 id)
static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
struct mr_table **mrt)
{
- *mrt = rcu_dereference(net->ipv6.mrt6);
+ *mrt = ip6mr_get_table_hold(net, RT6_TABLE_DFLT);
if (!*mrt)
return -EAGAIN;
return 0;
@@ -342,7 +348,8 @@ static void __net_exit ip6mr_rules_exit_rtnl(struct net *net,
struct mr_table *mrt = rcu_dereference_protected(net->ipv6.mrt6, 1);
RCU_INIT_POINTER(net->ipv6.mrt6, NULL);
- ip6mr_free_table(mrt, dev_kill_list);
+ synchronize_rcu();
+ __ip6mr_put_table(mrt, dev_kill_list);
}
static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb,
@@ -368,6 +375,44 @@ static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
return mrt;
}
+static struct mr_table *ip6mr_get_table_hold(struct net *net, u32 id)
+{
+ struct mr_table *mrt;
+
+ rcu_read_lock();
+ mrt = __ip6mr_get_table(net, id);
+ if (mrt && !refcount_inc_not_zero(&mrt->refcnt))
+ mrt = NULL;
+ rcu_read_unlock();
+
+ return mrt;
+}
+
+static void __ip6mr_put_table(struct mr_table *mrt,
+ struct list_head *head)
+{
+ struct list_head *dev_kill_list;
+ LIST_HEAD(local_dev_kill_list);
+
+ if (!refcount_dec_and_test(&mrt->refcnt))
+ return;
+
+ if (!lockdep_rtnl_is_held()) {
+ schedule_work(&mrt->destroy_work);
+ return;
+ }
+
+ dev_kill_list = head ? head : &local_dev_kill_list;
+ ip6mr_free_table(mrt, dev_kill_list);
+ if (!head)
+ unregister_netdevice_many(dev_kill_list);
+}
+
+static void ip6mr_put_table(struct mr_table *mrt)
+{
+ __ip6mr_put_table(mrt, NULL);
+}
+
static int ip6mr_hash_cmp(struct rhashtable_compare_arg *arg,
const void *ptr)
{
@@ -413,8 +458,12 @@ static struct mr_table *ip6mr_new_table(struct net *net, u32 id)
if (mrt)
return mrt;
- return mr_table_alloc(net, id, &ip6mr_mr_table_ops,
- ipmr_expire_process, ip6mr_new_table_set);
+ mrt = mr_table_alloc(net, id, &ip6mr_mr_table_ops,
+ ipmr_expire_process, ip6mr_new_table_set);
+ if (!IS_ERR(mrt))
+ INIT_WORK(&mrt->destroy_work, ip6mr_free_table_work);
+
+ return mrt;
}
static void ip6mr_free_table(struct mr_table *mrt,
@@ -423,8 +472,6 @@ static void ip6mr_free_table(struct mr_table *mrt,
struct net *net = read_pnet(&mrt->net);
LIST_HEAD(ip6mr_dev_kill_list);
- WARN_ON_ONCE(!mr_can_free_table(net));
-
timer_shutdown_sync(&mrt->ipmr_expire_timer);
mroute_clean_tables(mrt, MRT6_FLUSH_MIFS | MRT6_FLUSH_MIFS_STATIC |
MRT6_FLUSH_MFC | MRT6_FLUSH_MFC_STATIC,
@@ -436,6 +483,17 @@ static void ip6mr_free_table(struct mr_table *mrt,
list_splice(&ip6mr_dev_kill_list, dev_kill_list);
}
+static void ip6mr_free_table_work(struct work_struct *work)
+{
+ struct mr_table *mrt = container_of(work, struct mr_table, destroy_work);
+ LIST_HEAD(dev_kill_list);
+
+ rtnl_lock();
+ ip6mr_free_table(mrt, &dev_kill_list);
+ unregister_netdevice_many(&dev_kill_list);
+ rtnl_unlock();
+}
+
#ifdef CONFIG_PROC_FS
/* The /proc interfaces to multicast routing
* /proc/ip6_mr_cache /proc/ip6_mr_vif
@@ -569,7 +627,7 @@ static int pim6_rcv(struct sk_buff *skb)
struct ipv6hdr *encap;
struct net_device *reg_dev = NULL;
struct net *net = dev_net(skb->dev);
- struct mr_table *mrt;
+ struct mr_table *mrt = NULL;
struct flowi6 fl6 = {
.flowi6_iif = skb->dev->ifindex,
.flowi6_mark = skb->mark,
@@ -617,9 +675,12 @@ static int pim6_rcv(struct sk_buff *skb)
skb_tunnel_rx(skb, reg_dev, dev_net(reg_dev));
netif_rx(skb);
+ ip6mr_put_table(mrt);
return 0;
drop:
+ if (mrt)
+ ip6mr_put_table(mrt);
kfree_skb(skb);
return 0;
}
@@ -634,7 +695,7 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct net *net = dev_net(dev);
- struct mr_table *mrt;
+ struct mr_table *mrt = NULL;
struct flowi6 fl6 = {
.flowi6_oif = dev->ifindex,
.flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
@@ -655,12 +716,15 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
ip6mr_cache_report(mrt, skb, READ_ONCE(mrt->mroute_reg_vif_num),
MRT6MSG_WHOLEPKT);
rcu_read_unlock();
+ ip6mr_put_table(mrt);
kfree_skb(skb);
return NETDEV_TX_OK;
tx_lookup_err:
rcu_read_unlock();
tx_err:
+ if (mrt)
+ ip6mr_put_table(mrt);
DEV_STATS_INC(dev, tx_errors);
kfree_skb(skb);
return NETDEV_TX_OK;
@@ -1615,12 +1679,13 @@ static void mroute_clean_tables(struct mr_table *mrt, int flags,
}
}
-static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
+static int __ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
{
int err = 0;
struct net *net = sock_net(sk);
- rtnl_lock();
+ ASSERT_RTNL();
+
spin_lock(&mrt_lock);
if (rtnl_dereference(mrt->mroute_sk)) {
err = -EADDRINUSE;
@@ -1628,6 +1693,7 @@ static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
rcu_assign_pointer(mrt->mroute_sk, sk);
sock_set_flag(sk, SOCK_RCU_FREE);
atomic_inc(&net->ipv6.devconf_all->mc_forwarding);
+ refcount_inc(&mrt->refcnt);
}
spin_unlock(&mrt_lock);
@@ -1636,7 +1702,6 @@ static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
NETCONFA_MC_FORWARDING,
NETCONFA_IFINDEX_ALL,
net->ipv6.devconf_all);
- rtnl_unlock();
return err;
}
@@ -1646,6 +1711,7 @@ int ip6mr_sk_done(struct sock *sk)
struct net *net = sock_net(sk);
struct ipv6_devconf *devconf;
LIST_HEAD(dev_kill_list);
+ struct mr_table *free_mrt = NULL;
struct mr_table *mrt;
int err = -EACCES;
@@ -1675,6 +1741,15 @@ int ip6mr_sk_done(struct sock *sk)
mroute_clean_tables(mrt, MRT6_FLUSH_MIFS | MRT6_FLUSH_MFC,
&dev_kill_list);
+ if (mrt->id != RT6_TABLE_DFLT &&
+ !READ_ONCE(mrt->maxvif) &&
+ !READ_ONCE(mrt->cache_resolve_queue_len) &&
+ list_empty(&mrt->mfc_cache_list) &&
+ list_empty(&mrt->mfc_unres_queue) &&
+ READ_ONCE(mrt->mroute_reg_vif_num) < 0) {
+ list_del_rcu(&mrt->list);
+ free_mrt = mrt;
+ }
err = 0;
break;
}
@@ -1682,6 +1757,14 @@ int ip6mr_sk_done(struct sock *sk)
unregister_netdevice_many(&dev_kill_list);
rtnl_unlock();
+ if (!err)
+ ip6mr_put_table(mrt);
+
+ if (free_mrt) {
+ synchronize_rcu();
+ ip6mr_put_table(free_mrt);
+ }
+
return err;
}
@@ -1693,11 +1776,15 @@ bool mroute6_is_socket(struct net *net, struct sk_buff *skb)
.flowi6_oif = skb->dev->ifindex,
.flowi6_mark = skb->mark,
};
+ bool ret;
if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
return NULL;
- return rcu_access_pointer(mrt->mroute_sk);
+ ret = rcu_access_pointer(mrt->mroute_sk);
+ ip6mr_put_table(mrt);
+
+ return ret;
}
EXPORT_SYMBOL(mroute6_is_socket);
@@ -1716,20 +1803,24 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
struct mf6cctl mfc;
mifi_t mifi;
struct net *net = sock_net(sk);
- struct mr_table *mrt;
+ struct mr_table *mrt = NULL;
+ u32 table = raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT;
if (sk->sk_type != SOCK_RAW ||
inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
return -EOPNOTSUPP;
- mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
- if (!mrt)
- return -ENOENT;
-
- if (optname != MRT6_INIT) {
+ if (optname != MRT6_INIT &&
+ optname != MRT6_TABLE &&
+ optname != MRT6_DONE) {
+ mrt = ip6mr_get_table_hold(net, table);
+ if (!mrt)
+ return -ENOENT;
if (sk != rcu_access_pointer(mrt->mroute_sk) &&
- !ns_capable(net->user_ns, CAP_NET_ADMIN))
+ !ns_capable(net->user_ns, CAP_NET_ADMIN)) {
+ ip6mr_put_table(mrt);
return -EACCES;
+ }
}
switch (optname) {
@@ -1737,32 +1828,41 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
if (optlen < sizeof(int))
return -EINVAL;
- return ip6mr_sk_init(mrt, sk);
+ rtnl_lock();
+ mrt = ip6mr_new_table(net, table);
+ if (!IS_ERR(mrt))
+ ret = __ip6mr_sk_init(mrt, sk);
+ else
+ ret = PTR_ERR(mrt);
+ rtnl_unlock();
+ return ret;
case MRT6_DONE:
return ip6mr_sk_done(sk);
case MRT6_ADD_MIF:
if (optlen < sizeof(vif))
- return -EINVAL;
+ goto out_put_table_einval;
if (copy_from_sockptr(&vif, optval, sizeof(vif)))
- return -EFAULT;
+ goto out_put_table_efault;
if (vif.mif6c_mifi >= MAXMIFS)
- return -ENFILE;
+ goto out_put_table_enfile;
rtnl_lock();
ret = mif6_add(net, mrt, &vif,
sk == rtnl_dereference(mrt->mroute_sk));
rtnl_unlock();
+ ip6mr_put_table(mrt);
return ret;
case MRT6_DEL_MIF:
if (optlen < sizeof(mifi_t))
- return -EINVAL;
+ goto out_put_table_einval;
if (copy_from_sockptr(&mifi, optval, sizeof(mifi_t)))
- return -EFAULT;
+ goto out_put_table_efault;
rtnl_lock();
ret = mif6_delete(mrt, mifi, 0, NULL);
rtnl_unlock();
+ ip6mr_put_table(mrt);
return ret;
/*
@@ -1776,9 +1876,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
case MRT6_ADD_MFC_PROXY:
case MRT6_DEL_MFC_PROXY:
if (optlen < sizeof(mfc))
- return -EINVAL;
+ goto out_put_table_einval;
if (copy_from_sockptr(&mfc, optval, sizeof(mfc)))
- return -EFAULT;
+ goto out_put_table_efault;
if (parent == 0)
parent = mfc.mf6cc_parent;
@@ -1793,6 +1893,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
parent);
mutex_unlock(&net->ipv6.mfc_mutex);
+ ip6mr_put_table(mrt);
return ret;
case MRT6_FLUSH:
@@ -1801,14 +1902,15 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
int flags;
if (optlen != sizeof(flags))
- return -EINVAL;
+ goto out_put_table_einval;
if (copy_from_sockptr(&flags, optval, sizeof(flags)))
- return -EFAULT;
+ goto out_put_table_efault;
rtnl_lock();
mroute_clean_tables(mrt, flags, &dev_kill_list);
unregister_netdevice_many(&dev_kill_list);
rtnl_unlock();
+ ip6mr_put_table(mrt);
return 0;
}
@@ -1820,10 +1922,11 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
int v;
if (optlen != sizeof(v))
- return -EINVAL;
+ goto out_put_table_einval;
if (copy_from_sockptr(&v, optval, sizeof(v)))
- return -EFAULT;
+ goto out_put_table_efault;
WRITE_ONCE(mrt->mroute_do_assert, v);
+ ip6mr_put_table(mrt);
return 0;
}
@@ -1834,9 +1937,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
int v;
if (optlen != sizeof(v))
- return -EINVAL;
+ goto out_put_table_einval;
if (copy_from_sockptr(&v, optval, sizeof(v)))
- return -EFAULT;
+ goto out_put_table_efault;
do_wrmifwhole = (v == MRT6MSG_WRMIFWHOLE);
v = !!v;
@@ -1848,6 +1951,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
WRITE_ONCE(mrt->mroute_do_wrvifwhole, do_wrmifwhole);
}
rtnl_unlock();
+ ip6mr_put_table(mrt);
return ret;
}
@@ -1864,18 +1968,22 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
/* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
if (v != RT_TABLE_DEFAULT && v >= 100000000)
return -EINVAL;
- if (sk == rcu_access_pointer(mrt->mroute_sk))
+
+ mrt = ip6mr_get_table_hold(net, table);
+ if (mrt && sk == rcu_access_pointer(mrt->mroute_sk)) {
+ ip6mr_put_table(mrt);
return -EBUSY;
+ }
+ if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) {
+ if (mrt)
+ ip6mr_put_table(mrt);
+ return -EACCES;
+ }
+ if (mrt)
+ ip6mr_put_table(mrt);
- rtnl_lock();
- ret = 0;
- mrt = ip6mr_new_table(net, v);
- if (IS_ERR(mrt))
- ret = PTR_ERR(mrt);
- else
- raw6_sk(sk)->ip6mr_table = v;
- rtnl_unlock();
- return ret;
+ raw6_sk(sk)->ip6mr_table = v;
+ return 0;
}
#endif
/*
@@ -1883,8 +1991,25 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
* set.
*/
default:
+ if (mrt)
+ ip6mr_put_table(mrt);
return -ENOPROTOOPT;
}
+
+out_put_table_efault:
+ if (mrt)
+ ip6mr_put_table(mrt);
+ return -EFAULT;
+
+out_put_table_einval:
+ if (mrt)
+ ip6mr_put_table(mrt);
+ return -EINVAL;
+
+out_put_table_enfile:
+ if (mrt)
+ ip6mr_put_table(mrt);
+ return -ENFILE;
}
/*
@@ -1895,6 +2020,7 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,
sockptr_t optlen)
{
int olr;
+ int ret = 0;
int val;
struct net *net = sock_net(sk);
struct mr_table *mrt;
@@ -1903,7 +2029,7 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,
inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
return -EOPNOTSUPP;
- mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
+ mrt = ip6mr_get_table_hold(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
if (!mrt)
return -ENOENT;
@@ -1920,26 +2046,33 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,
val = READ_ONCE(mrt->mroute_do_assert);
break;
default:
- return -ENOPROTOOPT;
+ ret = -ENOPROTOOPT;
+ goto out;
}
- if (copy_from_sockptr(&olr, optlen, sizeof(int)))
- return -EFAULT;
+ if (copy_from_sockptr(&olr, optlen, sizeof(int))) {
+ ret = -EFAULT;
+ goto out;
+ }
olr = min_t(int, olr, sizeof(int));
- if (olr < 0)
- return -EINVAL;
+ if (olr < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
- if (copy_to_sockptr(optlen, &olr, sizeof(int)))
- return -EFAULT;
- if (copy_to_sockptr(optval, &val, olr))
- return -EFAULT;
- return 0;
+ if (copy_to_sockptr(optlen, &olr, sizeof(int)) ||
+ copy_to_sockptr(optval, &val, olr))
+ ret = -EFAULT;
+out:
+ ip6mr_put_table(mrt);
+ return ret;
}
/*
* The IP multicast ioctl support routines.
*/
+
int ip6mr_ioctl(struct sock *sk, int cmd, void *arg)
{
struct sioc_sg_req6 *sr;
@@ -1949,7 +2082,7 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void *arg)
struct net *net = sock_net(sk);
struct mr_table *mrt;
- mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
+ mrt = ip6mr_get_table_hold(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
if (!mrt)
return -ENOENT;
@@ -1957,7 +2090,7 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void *arg)
case SIOCGETMIFCNT_IN6:
vr = (struct sioc_mif_req6 *)arg;
if (vr->mifi >= mrt->maxvif)
- return -EINVAL;
+ goto out_put_table_einval;
vr->mifi = array_index_nospec(vr->mifi, mrt->maxvif);
rcu_read_lock();
vif = &mrt->vif_table[vr->mifi];
@@ -1967,9 +2100,11 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void *arg)
vr->ibytes = READ_ONCE(vif->bytes_in);
vr->obytes = READ_ONCE(vif->bytes_out);
rcu_read_unlock();
+ ip6mr_put_table(mrt);
return 0;
}
rcu_read_unlock();
+ ip6mr_put_table(mrt);
return -EADDRNOTAVAIL;
case SIOCGETSGCNT_IN6:
sr = (struct sioc_sg_req6 *)arg;
@@ -1982,15 +2117,21 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void *arg)
sr->bytecnt = atomic_long_read(&c->_c.mfc_un.res.bytes);
sr->wrong_if = atomic_long_read(&c->_c.mfc_un.res.wrong_if);
rcu_read_unlock();
+ ip6mr_put_table(mrt);
return 0;
}
rcu_read_unlock();
+ ip6mr_put_table(mrt);
return -EADDRNOTAVAIL;
default:
+ ip6mr_put_table(mrt);
return -ENOIOCTLCMD;
}
-}
+out_put_table_einval:
+ ip6mr_put_table(mrt);
+ return -EINVAL;
+}
#ifdef CONFIG_COMPAT
struct compat_sioc_sg_req6 {
struct sockaddr_in6 src;
@@ -2017,16 +2158,16 @@ int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
struct net *net = sock_net(sk);
struct mr_table *mrt;
- mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
+ mrt = ip6mr_get_table_hold(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
if (!mrt)
return -ENOENT;
switch (cmd) {
case SIOCGETMIFCNT_IN6:
if (copy_from_user(&vr, arg, sizeof(vr)))
- return -EFAULT;
+ goto out_put_table_efault;
if (vr.mifi >= mrt->maxvif)
- return -EINVAL;
+ goto out_put_table_einval;
vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif);
rcu_read_lock();
vif = &mrt->vif_table[vr.mifi];
@@ -2038,14 +2179,16 @@ int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
rcu_read_unlock();
if (copy_to_user(arg, &vr, sizeof(vr)))
- return -EFAULT;
+ goto out_put_table_efault;
+ ip6mr_put_table(mrt);
return 0;
}
rcu_read_unlock();
+ ip6mr_put_table(mrt);
return -EADDRNOTAVAIL;
case SIOCGETSGCNT_IN6:
if (copy_from_user(&sr, arg, sizeof(sr)))
- return -EFAULT;
+ goto out_put_table_efault;
rcu_read_lock();
c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
@@ -2056,14 +2199,25 @@ int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
rcu_read_unlock();
if (copy_to_user(arg, &sr, sizeof(sr)))
- return -EFAULT;
+ goto out_put_table_efault;
+ ip6mr_put_table(mrt);
return 0;
}
rcu_read_unlock();
+ ip6mr_put_table(mrt);
return -EADDRNOTAVAIL;
default:
+ ip6mr_put_table(mrt);
return -ENOIOCTLCMD;
}
+
+out_put_table_efault:
+ ip6mr_put_table(mrt);
+ return -EFAULT;
+
+out_put_table_einval:
+ ip6mr_put_table(mrt);
+ return -EINVAL;
}
#endif
@@ -2392,13 +2546,16 @@ int ip6_mr_input(struct sk_buff *skb)
if (vif >= 0) {
int err = ip6mr_cache_unresolved(mrt, vif, skb, dev);
+ ip6mr_put_table(mrt);
return err;
}
+ ip6mr_put_table(mrt);
kfree_skb(skb);
return -ENODEV;
}
ip6_mr_forward(net, mrt, dev, skb, cache);
+ ip6mr_put_table(mrt);
return 0;
}
@@ -2441,19 +2598,25 @@ int ip6_mr_output(struct net *net, struct sock *sk, struct sk_buff *skb)
/* No usable cache entry */
if (!cache) {
vif = ip6mr_find_vif(mrt, dev);
- if (vif >= 0)
- return ip6mr_cache_unresolved(mrt, vif, skb, dev);
- goto ip6_output;
+ if (vif >= 0) {
+ err = ip6mr_cache_unresolved(mrt, vif, skb, dev);
+ ip6mr_put_table(mrt);
+ return err;
+ }
+ goto out_put;
}
/* Wrong interface */
vif = cache->_c.mfc_parent;
if (rcu_access_pointer(mrt->vif_table[vif].dev) != dev)
- goto ip6_output;
+ goto out_put;
ip6_mr_output_finish(net, mrt, dev, skb, cache);
+ ip6mr_put_table(mrt);
return 0;
+out_put:
+ ip6mr_put_table(mrt);
ip6_output:
return ip6_output(net, sk, skb);
}
@@ -2755,33 +2918,35 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
grp = nla_get_in6_addr(tb[RTA_DST]);
tableid = nla_get_u32_default(tb[RTA_TABLE], 0);
- rcu_read_lock();
-
- mrt = __ip6mr_get_table(net, tableid ?: RT_TABLE_DEFAULT);
+ mrt = ip6mr_get_table_hold(net, tableid ?: RT_TABLE_DEFAULT);
if (!mrt) {
NL_SET_ERR_MSG_MOD(extack, "MR table does not exist");
err = -ENOENT;
- goto err;
+ goto err_free;
}
+ rcu_read_lock();
cache = ip6mr_cache_find(mrt, &src, &grp);
if (!cache) {
+ rcu_read_unlock();
NL_SET_ERR_MSG_MOD(extack, "MR cache entry not found");
err = -ENOENT;
- goto err;
+ goto err_put;
}
err = ip6mr_fill_mroute(mrt, skb, NETLINK_CB(in_skb).portid,
nlh->nlmsg_seq, cache, RTM_NEWROUTE, 0);
- if (err < 0)
- goto err;
-
rcu_read_unlock();
+ if (err < 0)
+ goto err_put;
- return rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
+ err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
+ ip6mr_put_table(mrt);
+ return err;
-err:
- rcu_read_unlock();
+err_put:
+ ip6mr_put_table(mrt);
+err_free:
kfree_skb(skb);
return err;
}
@@ -2804,7 +2969,7 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
if (filter.table_id) {
struct mr_table *mrt;
- mrt = __ip6mr_get_table(sock_net(skb->sk), filter.table_id);
+ mrt = ip6mr_get_table_hold(sock_net(skb->sk), filter.table_id);
if (!mrt) {
if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IP6MR) {
err = skb->len;
@@ -2818,6 +2983,7 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
err = mr_table_dump(mrt, skb, cb, _ip6mr_fill_mroute,
&mfc_unres_lock, &filter);
+ ip6mr_put_table(mrt);
err = skb->len ? : err;
goto unlock;
}
|
| 3/2 | 2026/07/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 12896 output: 19 thoughts: 577 Thoughts: **Fuzzing Target Identification: IPv6 Multicast Routing Patch** Okay, so I've got this patch affecting IPv6 multicast routing, specifically touching `net/ipv6/ip6mr.c`, `net/ipv4/ipmr_base.c`, and `include/linux/mroute_base.h`. The core of it is the introduction of reference counting for `struct mr_table` – `refcnt` and `destroy_work` – and a corresponding change in the table management functions. Basically, they are trying to fix a potential use-after-free situation, which is critical. My initial assessment is, *yes*, this warrants fuzzing. It's touching core networking code, specifically IPv6 multicast routing, which means it’s definitely critical infrastructure. It is accessible in virtualized environments as well. Now, let's identify the key symbols modified by this patch to construct a list of fuzz targets. The most important ones seem to be the new `ip6mr_get_table_hold`, `__ip6mr_put_table`, `ip6mr_put_table`, and `ip6mr_free_table_work`, but the modifications aren't limited to that. They also modified how the other functions are used like `ip6mr_new_table`, `ip6mr_free_table`, `pim6_rcv`, `reg_vif_xmit`, `__ip6mr_sk_init`, `ip6mr_sk_done`, `mroute6_is_socket`, `ip6_mroute_setsockopt`, `ip6_mroute_getsockopt`, `ip6mr_ioctl`, `ip6mr_compat_ioctl`, `ip6_mr_input`, `ip6_mr_output`, `ip6mr_rtm_getroute`, and `ip6mr_rtm_dumproute`. Thinking about the most effective fuzzing targets, I'd hone in on these: `ip6_mroute_setsockopt`, `ip6_mroute_getsockopt`, `ip6mr_ioctl`, `ip6mr_compat_ioctl`, `ip6_mr_input`, `ip6_mr_output`, `ip6mr_rtm_getroute`, `ip6mr_rtm_dumproute`, `pim6_rcv`, and `reg_vif_xmit`. Socket options and ioctls are always good starting points, since they provide direct interaction with the kernel. The routing table interaction and packet input/output functions are also important. Finally, a quick sanity check of the Kconfig options. I need to make sure that IPv6 multicast routing (`CONFIG_IPV6_MROUTE`) is enabled. I'll need to confirm that with a `grepper` search. |
| 4/2 | 2026/07/24 22:59 | tool | grepper |
0mArgs:{
"Expression": "IPV6_MROUTE"
}Results: {
"Output": "arch/arm/configs/keystone_defconfig=70=CONFIG_IPV6_SUBTREES=y\narch/arm/configs/keystone_defconfig:71:CONFIG_IPV6_MROUTE=y\narch/arm/configs/keystone_defconfig-72-CONFIG_IPV6_PIMSM_V2=y\n--\narch/loongarch/configs/loongson32_defconfig=159=CONFIG_IPV6_MULTIPLE_TABLES=y\narch/loongarch/configs/loongson32_defconfig:160:CONFIG_IPV6_MROUTE=y\narch/loongarch/configs/loongson32_defconfig-161-CONFIG_MPTCP=y\n--\narch/loongarch/configs/loongson64_defconfig=175=CONFIG_IPV6_MULTIPLE_TABLES=y\narch/loongarch/configs/loongson64_defconfig:176:CONFIG_IPV6_MROUTE=y\narch/loongarch/configs/loongson64_defconfig-177-CONFIG_MPTCP=y\n--\narch/mips/configs/bcm47xx_defconfig=25=CONFIG_IPV6_SUBTREES=y\narch/mips/configs/bcm47xx_defconfig:26:CONFIG_IPV6_MROUTE=y\narch/mips/configs/bcm47xx_defconfig-27-CONFIG_NETFILTER=y\n--\narch/mips/configs/db1xxx_defconfig=65=CONFIG_IPV6_SUBTREES=y\narch/mips/configs/db1xxx_defconfig:66:CONFIG_IPV6_MROUTE=y\narch/mips/configs/db1xxx_defconfig:67:CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y\narch/mips/configs/db1xxx_defconfig-68-CONFIG_IPV6_PIMSM_V2=y\n--\narch/mips/configs/ip22_defconfig=48=CONFIG_IPV6_SUBTREES=y\narch/mips/configs/ip22_defconfig:49:CONFIG_IPV6_MROUTE=y\narch/mips/configs/ip22_defconfig-50-CONFIG_IPV6_PIMSM_V2=y\n--\narch/mips/configs/ip27_defconfig=47=CONFIG_IPV6_SUBTREES=y\narch/mips/configs/ip27_defconfig:48:CONFIG_IPV6_MROUTE=y\narch/mips/configs/ip27_defconfig-49-CONFIG_IPV6_PIMSM_V2=y\n--\narch/mips/configs/ip30_defconfig=47=CONFIG_IPV6_SUBTREES=y\narch/mips/configs/ip30_defconfig:48:CONFIG_IPV6_MROUTE=y\narch/mips/configs/ip30_defconfig-49-CONFIG_IPV6_PIMSM_V2=y\n--\narch/mips/configs/malta_defconfig=51=CONFIG_IPV6_TUNNEL=m\narch/mips/configs/malta_defconfig:52:CONFIG_IPV6_MROUTE=y\narch/mips/configs/malta_defconfig-53-CONFIG_IPV6_PIMSM_V2=y\n--\narch/mips/configs/malta_kvm_defconfig=55=CONFIG_IPV6_TUNNEL=m\narch/mips/configs/malta_kvm_defconfig:56:CONFIG_IPV6_MROUTE=y\narch/mips/configs/malta_kvm_defconfig-57-CONFIG_IPV6_PIMSM_V2=y\n--\narch/mips/configs/maltaup_xpa_defconfig=54=CONFIG_IPV6_TUNNEL=m\narch/mips/configs/maltaup_xpa_defconfig:55:CONFIG_IPV6_MROUTE=y\narch/mips/configs/maltaup_xpa_defconfig-56-CONFIG_IPV6_PIMSM_V2=y\n--\narch/powerpc/configs/ppc6xx_defconfig=117=CONFIG_IPV6_SUBTREES=y\narch/powerpc/configs/ppc6xx_defconfig:118:CONFIG_IPV6_MROUTE=y\narch/powerpc/configs/ppc6xx_defconfig-119-CONFIG_IPV6_PIMSM_V2=y\n--\ndrivers/net/vrf.c=1517=static int vrf_add_fib_rules(const struct net_device *dev)\n--\ndrivers/net/vrf.c-1534-\ndrivers/net/vrf.c:1535:#if IS_ENABLED(CONFIG_IPV6_MROUTE_MULTIPLE_TABLES)\ndrivers/net/vrf.c-1536-\terr = vrf_fib_rule(dev, RTNL_FAMILY_IP6MR, true);\n--\ndrivers/net/vrf.c-1542-\ndrivers/net/vrf.c:1543:#if IS_ENABLED(CONFIG_IPV6_MROUTE_MULTIPLE_TABLES)\ndrivers/net/vrf.c-1544-ip6mr_err:\n--\ninclude/linux/ipv6.h=13=struct ipv6_devconf {\n--\ninclude/linux/ipv6.h-62-#endif\ninclude/linux/ipv6.h:63:#ifdef CONFIG_IPV6_MROUTE\ninclude/linux/ipv6.h-64-\tatomic_t\tmc_forwarding;\n--\ninclude/linux/mroute6.h-13-\ninclude/linux/mroute6.h:14:#ifdef CONFIG_IPV6_MROUTE\ninclude/linux/mroute6.h-15-static inline int ip6_mroute_opt(int opt)\n--\ninclude/linux/mroute6.h=26=struct sock;\ninclude/linux/mroute6.h-27-\ninclude/linux/mroute6.h:28:#ifdef CONFIG_IPV6_MROUTE\ninclude/linux/mroute6.h-29-extern int ip6_mroute_setsockopt(struct sock *, int, sockptr_t, unsigned int);\n--\ninclude/linux/mroute6.h=68=static inline void ip6_mr_cleanup(void)\n--\ninclude/linux/mroute6.h-73-\ninclude/linux/mroute6.h:74:#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES\ninclude/linux/mroute6.h-75-bool ip6mr_rule_default(const struct fib_rule *rule);\n--\ninclude/linux/mroute6.h=104=extern int ip6mr_get_route(struct net *net, struct sk_buff *skb,\n--\ninclude/linux/mroute6.h-106-\ninclude/linux/mroute6.h:107:#ifdef CONFIG_IPV6_MROUTE\ninclude/linux/mroute6.h-108-bool mroute6_is_socket(struct net *net, struct sk_buff *skb);\n--\ninclude/net/netns/ipv6.h=66=struct netns_ipv6 {\n--\ninclude/net/netns/ipv6.h-107-\ninclude/net/netns/ipv6.h:108:#ifdef CONFIG_IPV6_MROUTE\ninclude/net/netns/ipv6.h:109:#ifndef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES\ninclude/net/netns/ipv6.h-110-\tstruct mr_table\t\t*mrt6;\n--\ninclude/uapi/linux/rtnetlink.h=682=enum {\n--\ninclude/uapi/linux/rtnetlink.h-702-#define RTMGRP_IPV6_IFADDR\t0x100\ninclude/uapi/linux/rtnetlink.h:703:#define RTMGRP_IPV6_MROUTE\t0x200\ninclude/uapi/linux/rtnetlink.h-704-#define RTMGRP_IPV6_ROUTE\t0x400\n--\ninclude/uapi/linux/rtnetlink.h=714=enum rtnetlink_groups {\n--\ninclude/uapi/linux/rtnetlink.h-734-#define RTNLGRP_IPV6_IFADDR\tRTNLGRP_IPV6_IFADDR\ninclude/uapi/linux/rtnetlink.h:735:\tRTNLGRP_IPV6_MROUTE,\ninclude/uapi/linux/rtnetlink.h:736:#define RTNLGRP_IPV6_MROUTE\tRTNLGRP_IPV6_MROUTE\ninclude/uapi/linux/rtnetlink.h-737-\tRTNLGRP_IPV6_ROUTE,\n--\ninclude/uapi/linux/rtnetlink.h-774-#define RTNLGRP_IPV4_MROUTE_R\tRTNLGRP_IPV4_MROUTE_R\ninclude/uapi/linux/rtnetlink.h:775:\tRTNLGRP_IPV6_MROUTE_R,\ninclude/uapi/linux/rtnetlink.h:776:#define RTNLGRP_IPV6_MROUTE_R\tRTNLGRP_IPV6_MROUTE_R\ninclude/uapi/linux/rtnetlink.h-777-\tRTNLGRP_NEXTHOP,\n--\nnet/batman-adv/multicast.c=110=static u8 batadv_mcast_mla_rtr_flags_meshif_get_ipv4(struct net_device *dev)\n--\nnet/batman-adv/multicast.c-130- */\nnet/batman-adv/multicast.c:131:#if IS_ENABLED(CONFIG_IPV6_MROUTE)\nnet/batman-adv/multicast.c-132-static u8 batadv_mcast_mla_rtr_flags_meshif_get_ipv6(struct net_device *dev)\n--\nnet/core/rtnetlink.c=7106=static int rtnetlink_bind(struct net *net, int group)\n--\nnet/core/rtnetlink.c-7109-\tcase RTNLGRP_IPV4_MROUTE_R:\nnet/core/rtnetlink.c:7110:\tcase RTNLGRP_IPV6_MROUTE_R:\nnet/core/rtnetlink.c-7111-\t\tif (!ns_capable(net-\u003euser_ns, CAP_NET_ADMIN))\n--\nnet/ipv4/Kconfig=216=config IP_MROUTE_COMMON\nnet/ipv4/Kconfig-217-\tbool\nnet/ipv4/Kconfig:218:\tdepends on IP_MROUTE || IPV6_MROUTE\nnet/ipv4/Kconfig-219-\n--\nnet/ipv6/Kconfig=243=config IPV6_SUBTREES\n--\nnet/ipv6/Kconfig-256-\nnet/ipv6/Kconfig:257:config IPV6_MROUTE\nnet/ipv6/Kconfig-258-\tbool \"IPv6: multicast routing\"\n--\nnet/ipv6/Kconfig-264-\nnet/ipv6/Kconfig:265:config IPV6_MROUTE_MULTIPLE_TABLES\nnet/ipv6/Kconfig-266-\tbool \"IPv6: multicast policy routing\"\nnet/ipv6/Kconfig:267:\tdepends on IPV6_MROUTE\nnet/ipv6/Kconfig-268-\tselect FIB_RULES\n--\nnet/ipv6/Kconfig=279=config IPV6_PIMSM_V2\nnet/ipv6/Kconfig-280-\tbool \"IPv6: PIM-SM version 2 support\"\nnet/ipv6/Kconfig:281:\tdepends on IPV6_MROUTE\nnet/ipv6/Kconfig-282-\thelp\n--\nnet/ipv6/Makefile=15=ipv6-$(CONFIG_SYSCTL) += sysctl_net_ipv6.o\nnet/ipv6/Makefile:16:ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o\nnet/ipv6/Makefile-17-\n--\nnet/ipv6/addrconf.c=508=static int inet6_netconf_msgsize_devconf(int type)\n--\nnet/ipv6/addrconf.c-518-\t\tsize += nla_total_size(4);\nnet/ipv6/addrconf.c:519:#ifdef CONFIG_IPV6_MROUTE\nnet/ipv6/addrconf.c-520-\tif (all || type == NETCONFA_MC_FORWARDING)\n--\nnet/ipv6/addrconf.c=532=static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex,\n--\nnet/ipv6/addrconf.c-561-\t\tgoto nla_put_failure;\nnet/ipv6/addrconf.c:562:#ifdef CONFIG_IPV6_MROUTE\nnet/ipv6/addrconf.c-563-\tif ((all || type == NETCONFA_MC_FORWARDING) \u0026\u0026\n--\nnet/ipv6/addrconf.c=5662=static void ipv6_store_devconf(const struct ipv6_devconf *cnf,\n--\nnet/ipv6/addrconf.c-5715-#endif\nnet/ipv6/addrconf.c:5716:#ifdef CONFIG_IPV6_MROUTE\nnet/ipv6/addrconf.c-5717-\tarray[DEVCONF_MC_FORWARDING] = atomic_read(\u0026cnf-\u003emc_forwarding);\n--\nnet/ipv6/addrconf.c=6863=static const struct ctl_table addrconf_sysctl[] = {\n--\nnet/ipv6/addrconf.c-7131-#endif\nnet/ipv6/addrconf.c:7132:#ifdef CONFIG_IPV6_MROUTE\nnet/ipv6/addrconf.c-7133-\t{\n--\nnet/ipv6/ip6_input.c=554=int ip6_mc_input(struct sk_buff *skb)\n--\nnet/ipv6/ip6_input.c-576-\nnet/ipv6/ip6_input.c:577:#ifdef CONFIG_IPV6_MROUTE\nnet/ipv6/ip6_input.c-578-\t/*\n--\nnet/ipv6/ip6mr.c=110=static void ipmr_expire_process(struct timer_list *t);\nnet/ipv6/ip6mr.c-111-\nnet/ipv6/ip6mr.c:112:#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES\nnet/ipv6/ip6mr.c-113-#define ip6mr_for_each_table(mrt, net) \\\n--\nnet/ipv6/ip6mr.c=435=static void ip6mr_new_table_set(struct mr_table *mrt,\n--\nnet/ipv6/ip6mr.c-437-{\nnet/ipv6/ip6mr.c:438:#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES\nnet/ipv6/ip6mr.c-439-\tlist_add_tail_rcu(\u0026mrt-\u003elist, \u0026net-\u003eipv6.mr6_tables);\n--\nnet/ipv6/ip6mr.c=1798=int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,\n--\nnet/ipv6/ip6mr.c-1958-#endif\nnet/ipv6/ip6mr.c:1959:#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES\nnet/ipv6/ip6mr.c-1960-\tcase MRT6_TABLE:\n--\nnet/ipv6/ip6mr.c=2769=static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,\n--\nnet/ipv6/ip6mr.c-2783-\nnet/ipv6/ip6mr.c:2784:\trtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC);\nnet/ipv6/ip6mr.c-2785-\treturn;\n--\nnet/ipv6/ip6mr.c-2788-\tkfree_skb(skb);\nnet/ipv6/ip6mr.c:2789:\trtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err);\nnet/ipv6/ip6mr.c-2790-}\n--\nnet/ipv6/ip6mr.c=2809=static void mrt6msg_netlink_event(const struct mr_table *mrt, struct sk_buff *pkt)\n--\nnet/ipv6/ip6mr.c-2846-\nnet/ipv6/ip6mr.c:2847:\trtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE_R, NULL, GFP_ATOMIC);\nnet/ipv6/ip6mr.c-2848-\treturn;\n--\nnet/ipv6/ip6mr.c-2853-\tkfree_skb(skb);\nnet/ipv6/ip6mr.c:2854:\trtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE_R, -ENOBUFS);\nnet/ipv6/ip6mr.c-2855-}\n--\nnet/ipv6/raw.c=1115=static int rawv6_ioctl(struct sock *sk, int cmd, int *karg)\n--\nnet/ipv6/raw.c-1135-\tdefault:\nnet/ipv6/raw.c:1136:#ifdef CONFIG_IPV6_MROUTE\nnet/ipv6/raw.c-1137-\t\treturn ip6mr_ioctl(sk, cmd, karg);\n--\nnet/ipv6/raw.c=1145=static int compat_rawv6_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)\n--\nnet/ipv6/raw.c-1151-\tdefault:\nnet/ipv6/raw.c:1152:#ifdef CONFIG_IPV6_MROUTE\nnet/ipv6/raw.c-1153-\t\treturn ip6mr_compat_ioctl(sk, cmd, compat_ptr(arg));\n--\nnet/ipv6/route.c=5774=static int rt6_fill_node(struct net *net, struct sk_buff *skb,\n--\nnet/ipv6/route.c-5839-\tif (iif) {\nnet/ipv6/route.c:5840:#ifdef CONFIG_IPV6_MROUTE\nnet/ipv6/route.c-5841-\t\tif (ipv6_addr_is_multicast(\u0026rt6_dst-\u003eaddr)) {\n--\ntools/include/uapi/linux/rtnetlink.h=682=enum {\n--\ntools/include/uapi/linux/rtnetlink.h-702-#define RTMGRP_IPV6_IFADDR\t0x100\ntools/include/uapi/linux/rtnetlink.h:703:#define RTMGRP_IPV6_MROUTE\t0x200\ntools/include/uapi/linux/rtnetlink.h-704-#define RTMGRP_IPV6_ROUTE\t0x400\n--\ntools/include/uapi/linux/rtnetlink.h=714=enum rtnetlink_groups {\n--\ntools/include/uapi/linux/rtnetlink.h-734-#define RTNLGRP_IPV6_IFADDR\tRTNLGRP_IPV6_IFADDR\ntools/include/uapi/linux/rtnetlink.h:735:\tRTNLGRP_IPV6_MROUTE,\ntools/include/uapi/linux/rtnetlink.h:736:#define RTNLGRP_IPV6_MROUTE\tRTNLGRP_IPV6_MROUTE\ntools/include/uapi/linux/rtnetlink.h-737-\tRTNLGRP_IPV6_ROUTE,\n--\ntools/include/uapi/linux/rtnetlink.h-774-#define RTNLGRP_IPV4_MROUTE_R\tRTNLGRP_IPV4_MROUTE_R\ntools/include/uapi/linux/rtnetlink.h:775:\tRTNLGRP_IPV6_MROUTE_R,\ntools/include/uapi/linux/rtnetlink.h:776:#define RTNLGRP_IPV6_MROUTE_R\tRTNLGRP_IPV6_MROUTE_R\ntools/include/uapi/linux/rtnetlink.h-777-\tRTNLGRP_NEXTHOP,\n--\ntools/testing/selftests/net/config=43=CONFIG_IPV6_IOAM6_LWTUNNEL=y\ntools/testing/selftests/net/config:44:CONFIG_IPV6_MROUTE=y\ntools/testing/selftests/net/config-45-CONFIG_IPV6_MULTIPLE_TABLES=y\n--\ntools/testing/selftests/net/forwarding/config=12=CONFIG_IPV6_GRE=m\ntools/testing/selftests/net/forwarding/config:13:CONFIG_IPV6_MROUTE=y\ntools/testing/selftests/net/forwarding/config:14:CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y\ntools/testing/selftests/net/forwarding/config-15-CONFIG_IPV6_MULTIPLE_TABLES=y\n"
} |
| 5/2 | 2026/07/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 19516 output: 18 thoughts: 109 Thoughts: **Configuration Verification** Okay, so I need to make sure a few specific configurations are enabled for this to work correctly. The core necessities seem to be `IPV6_MROUTE` and `IPV6_MROUTE_MULTIPLE_TABLES`. Ideally, for robust testing of `pim6_rcv`, I should also include `IPV6_PIMSM_V2` as well. Since this involves ipmr_base.c modifications, I have to enable both `IP_MROUTE` and `IP_MROUTE_MULTIPLE_TABLES` too. Right, let's start by double-checking those `IP_MROUTE` configurations to confirm they're enabled as expected. |
| 6/2 | 2026/07/24 22:59 | tool | grepper |
0mArgs:{
"Expression": "IP_MROUTE"
}Results: {
"Output": "arch/arm/configs/ixp4xx_defconfig=30=CONFIG_IP_PNP_BOOTP=y\narch/arm/configs/ixp4xx_defconfig:31:CONFIG_IP_MROUTE=y\narch/arm/configs/ixp4xx_defconfig-32-CONFIG_IP_PIMSM_V1=y\n--\narch/arm/configs/keystone_defconfig=59=CONFIG_NET_IPGRE=y\narch/arm/configs/keystone_defconfig:60:CONFIG_IP_MROUTE=y\narch/arm/configs/keystone_defconfig:61:CONFIG_IP_MROUTE_MULTIPLE_TABLES=y\narch/arm/configs/keystone_defconfig-62-CONFIG_IP_PIMSM_V2=y\n--\narch/arm/configs/nhk8815_defconfig=30=CONFIG_NET_IPIP=y\narch/arm/configs/nhk8815_defconfig:31:CONFIG_IP_MROUTE=y\narch/arm/configs/nhk8815_defconfig-32-# CONFIG_IPV6 is not set\n--\narch/loongarch/configs/loongson32_defconfig=130=CONFIG_NET_IPGRE_BROADCAST=y\narch/loongarch/configs/loongson32_defconfig:131:CONFIG_IP_MROUTE=y\narch/loongarch/configs/loongson32_defconfig:132:CONFIG_IP_MROUTE_MULTIPLE_TABLES=y\narch/loongarch/configs/loongson32_defconfig-133-CONFIG_IP_PIMSM_V1=y\n--\narch/loongarch/configs/loongson64_defconfig=146=CONFIG_NET_IPGRE_BROADCAST=y\narch/loongarch/configs/loongson64_defconfig:147:CONFIG_IP_MROUTE=y\narch/loongarch/configs/loongson64_defconfig:148:CONFIG_IP_MROUTE_MULTIPLE_TABLES=y\narch/loongarch/configs/loongson64_defconfig-149-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/bcm47xx_defconfig=19=CONFIG_IP_ROUTE_MULTIPATH=y\narch/mips/configs/bcm47xx_defconfig:20:CONFIG_IP_MROUTE=y\narch/mips/configs/bcm47xx_defconfig:21:CONFIG_IP_MROUTE_MULTIPLE_TABLES=y\narch/mips/configs/bcm47xx_defconfig-22-CONFIG_SYN_COOKIES=y\n--\narch/mips/configs/bigsur_defconfig=44=CONFIG_IP_PNP_BOOTP=y\narch/mips/configs/bigsur_defconfig:45:CONFIG_IP_MROUTE=y\narch/mips/configs/bigsur_defconfig-46-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/bmips_stb_defconfig=61=CONFIG_IP_PNP_RARP=y\narch/mips/configs/bmips_stb_defconfig:62:CONFIG_IP_MROUTE=y\narch/mips/configs/bmips_stb_defconfig-63-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/cavium_octeon_defconfig=39=CONFIG_IP_PNP_RARP=y\narch/mips/configs/cavium_octeon_defconfig:40:CONFIG_IP_MROUTE=y\narch/mips/configs/cavium_octeon_defconfig-41-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/lemote2f_defconfig=40=CONFIG_NET_IPIP=m\narch/mips/configs/lemote2f_defconfig:41:CONFIG_IP_MROUTE=y\narch/mips/configs/lemote2f_defconfig-42-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/malta_defconfig=36=CONFIG_NET_IPIP=m\narch/mips/configs/malta_defconfig:37:CONFIG_IP_MROUTE=y\narch/mips/configs/malta_defconfig-38-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/malta_kvm_defconfig=40=CONFIG_NET_IPIP=m\narch/mips/configs/malta_kvm_defconfig:41:CONFIG_IP_MROUTE=y\narch/mips/configs/malta_kvm_defconfig-42-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/malta_qemu_32r6_defconfig=35=CONFIG_NET_IPIP=m\narch/mips/configs/malta_qemu_32r6_defconfig:36:CONFIG_IP_MROUTE=y\narch/mips/configs/malta_qemu_32r6_defconfig-37-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/maltaaprp_defconfig=37=CONFIG_NET_IPIP=m\narch/mips/configs/maltaaprp_defconfig:38:CONFIG_IP_MROUTE=y\narch/mips/configs/maltaaprp_defconfig-39-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/maltasmvp_defconfig=38=CONFIG_NET_IPIP=m\narch/mips/configs/maltasmvp_defconfig:39:CONFIG_IP_MROUTE=y\narch/mips/configs/maltasmvp_defconfig-40-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/maltasmvp_eva_defconfig=39=CONFIG_NET_IPIP=m\narch/mips/configs/maltasmvp_eva_defconfig:40:CONFIG_IP_MROUTE=y\narch/mips/configs/maltasmvp_eva_defconfig-41-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/maltaup_defconfig=36=CONFIG_NET_IPIP=m\narch/mips/configs/maltaup_defconfig:37:CONFIG_IP_MROUTE=y\narch/mips/configs/maltaup_defconfig-38-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/maltaup_xpa_defconfig=39=CONFIG_NET_IPIP=m\narch/mips/configs/maltaup_xpa_defconfig:40:CONFIG_IP_MROUTE=y\narch/mips/configs/maltaup_xpa_defconfig-41-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/mtx1_defconfig=51=CONFIG_NET_IPIP=m\narch/mips/configs/mtx1_defconfig:52:CONFIG_IP_MROUTE=y\narch/mips/configs/mtx1_defconfig-53-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/qi_lb60_defconfig=28=CONFIG_IP_ROUTE_VERBOSE=y\narch/mips/configs/qi_lb60_defconfig:29:CONFIG_IP_MROUTE=y\narch/mips/configs/qi_lb60_defconfig:30:CONFIG_IP_MROUTE_MULTIPLE_TABLES=y\narch/mips/configs/qi_lb60_defconfig-31-# CONFIG_INET_DIAG is not set\n--\narch/mips/configs/rm200_defconfig=27=CONFIG_NET_IPIP=m\narch/mips/configs/rm200_defconfig:28:CONFIG_IP_MROUTE=y\narch/mips/configs/rm200_defconfig-29-CONFIG_IP_PIMSM_V1=y\n--\narch/mips/configs/rs90_defconfig=50=CONFIG_IP_ROUTE_VERBOSE=y\narch/mips/configs/rs90_defconfig:51:CONFIG_IP_MROUTE=y\narch/mips/configs/rs90_defconfig:52:CONFIG_IP_MROUTE_MULTIPLE_TABLES=y\narch/mips/configs/rs90_defconfig-53-# CONFIG_INET_DIAG is not set\n--\narch/mips/configs/rt305x_defconfig=34=CONFIG_IP_ROUTE_VERBOSE=y\narch/mips/configs/rt305x_defconfig:35:CONFIG_IP_MROUTE=y\narch/mips/configs/rt305x_defconfig:36:CONFIG_IP_MROUTE_MULTIPLE_TABLES=y\narch/mips/configs/rt305x_defconfig-37-CONFIG_SYN_COOKIES=y\n--\narch/mips/configs/xway_defconfig=36=CONFIG_IP_ROUTE_VERBOSE=y\narch/mips/configs/xway_defconfig:37:CONFIG_IP_MROUTE=y\narch/mips/configs/xway_defconfig:38:CONFIG_IP_MROUTE_MULTIPLE_TABLES=y\narch/mips/configs/xway_defconfig-39-CONFIG_SYN_COOKIES=y\n--\narch/powerpc/configs/85xx/ge_imp3a_defconfig=54=CONFIG_NET_IPIP=m\narch/powerpc/configs/85xx/ge_imp3a_defconfig:55:CONFIG_IP_MROUTE=y\narch/powerpc/configs/85xx/ge_imp3a_defconfig-56-CONFIG_IP_PIMSM_V1=y\n--\narch/powerpc/configs/85xx/xes_mpc85xx_defconfig=50=CONFIG_NET_IPIP=y\narch/powerpc/configs/85xx/xes_mpc85xx_defconfig:51:CONFIG_IP_MROUTE=y\narch/powerpc/configs/85xx/xes_mpc85xx_defconfig-52-CONFIG_IP_PIMSM_V1=y\n--\narch/powerpc/configs/fsl-emb-nonhw.config=58=CONFIG_IP_ADVANCED_ROUTER=y\narch/powerpc/configs/fsl-emb-nonhw.config:59:CONFIG_IP_MROUTE=y\narch/powerpc/configs/fsl-emb-nonhw.config-60-CONFIG_IP_MULTICAST=y\n--\narch/powerpc/configs/ppc6xx_defconfig=90=CONFIG_NET_IPIP=m\narch/powerpc/configs/ppc6xx_defconfig:91:CONFIG_IP_MROUTE=y\narch/powerpc/configs/ppc6xx_defconfig-92-CONFIG_IP_PIMSM_V1=y\n--\narch/s390/configs/debug_defconfig=145=CONFIG_NET_IPGRE_BROADCAST=y\narch/s390/configs/debug_defconfig:146:CONFIG_IP_MROUTE=y\narch/s390/configs/debug_defconfig:147:CONFIG_IP_MROUTE_MULTIPLE_TABLES=y\narch/s390/configs/debug_defconfig-148-CONFIG_IP_PIMSM_V1=y\n--\narch/s390/configs/defconfig=136=CONFIG_NET_IPGRE_BROADCAST=y\narch/s390/configs/defconfig:137:CONFIG_IP_MROUTE=y\narch/s390/configs/defconfig:138:CONFIG_IP_MROUTE_MULTIPLE_TABLES=y\narch/s390/configs/defconfig-139-CONFIG_IP_PIMSM_V1=y\n--\narch/sh/configs/se7712_defconfig=38=CONFIG_IP_PNP_BOOTP=y\narch/sh/configs/se7712_defconfig:39:CONFIG_IP_MROUTE=y\narch/sh/configs/se7712_defconfig-40-CONFIG_IP_PIMSM_V1=y\n--\narch/sh/configs/se7721_defconfig=37=CONFIG_IP_PNP_DHCP=y\narch/sh/configs/se7721_defconfig:38:CONFIG_IP_MROUTE=y\narch/sh/configs/se7721_defconfig-39-CONFIG_IP_PIMSM_V1=y\n--\narch/sh/configs/titan_defconfig=41=CONFIG_NET_IPGRE_BROADCAST=y\narch/sh/configs/titan_defconfig:42:CONFIG_IP_MROUTE=y\narch/sh/configs/titan_defconfig-43-CONFIG_IP_PIMSM_V1=y\n--\narch/sparc/configs/sparc64_defconfig=39=CONFIG_NET_IPGRE_BROADCAST=y\narch/sparc/configs/sparc64_defconfig:40:CONFIG_IP_MROUTE=y\narch/sparc/configs/sparc64_defconfig-41-CONFIG_IP_PIMSM_V1=y\n--\narch/x86/configs/i386_defconfig=73=CONFIG_IP_PNP_RARP=y\narch/x86/configs/i386_defconfig:74:CONFIG_IP_MROUTE=y\narch/x86/configs/i386_defconfig-75-CONFIG_IP_PIMSM_V1=y\n--\narch/x86/configs/x86_64_defconfig=74=CONFIG_IP_PNP_RARP=y\narch/x86/configs/x86_64_defconfig:75:CONFIG_IP_MROUTE=y\narch/x86/configs/x86_64_defconfig-76-CONFIG_IP_PIMSM_V1=y\n--\ndrivers/net/vrf.c=1517=static int vrf_add_fib_rules(const struct net_device *dev)\n--\ndrivers/net/vrf.c-1528-\ndrivers/net/vrf.c:1529:#if IS_ENABLED(CONFIG_IP_MROUTE_MULTIPLE_TABLES)\ndrivers/net/vrf.c-1530-\terr = vrf_fib_rule(dev, RTNL_FAMILY_IPMR, true);\n--\ndrivers/net/vrf.c-1547-\ndrivers/net/vrf.c:1548:#if IS_ENABLED(CONFIG_IP_MROUTE_MULTIPLE_TABLES)\ndrivers/net/vrf.c-1549-ipmr_err:\n--\ninclude/linux/mroute.h-12-\ninclude/linux/mroute.h:13:#ifdef CONFIG_IP_MROUTE\ninclude/linux/mroute.h-14-static inline int ip_mroute_opt(int opt)\n--\ninclude/linux/mroute_base.h=272=static inline bool mr_can_free_table(struct net *net)\n--\ninclude/linux/mroute_base.h-276-\ninclude/linux/mroute_base.h:277:#ifdef CONFIG_IP_MROUTE_COMMON\ninclude/linux/mroute_base.h-278-void vif_device_init(struct vif_device *v,\n--\ninclude/linux/mroute_base.h=397=struct mr_mfc_iter {\n--\ninclude/linux/mroute_base.h-405-\ninclude/linux/mroute_base.h:406:#ifdef CONFIG_IP_MROUTE_COMMON\ninclude/linux/mroute_base.h-407-void *mr_vif_seq_idx(struct net *net, struct mr_vif_iter *iter, loff_t pos);\n--\ninclude/net/netns/ipv4.h=55=struct netns_ipv4 {\n--\ninclude/net/netns/ipv4.h-275-\ninclude/net/netns/ipv4.h:276:#ifdef CONFIG_IP_MROUTE\ninclude/net/netns/ipv4.h:277:#ifndef CONFIG_IP_MROUTE_MULTIPLE_TABLES\ninclude/net/netns/ipv4.h-278-\tstruct mr_table __rcu\t*mrt;\n--\nnet/ipv4/Kconfig=207=config NET_IPGRE_BROADCAST\n--\nnet/ipv4/Kconfig-215-\nnet/ipv4/Kconfig:216:config IP_MROUTE_COMMON\nnet/ipv4/Kconfig-217-\tbool\nnet/ipv4/Kconfig:218:\tdepends on IP_MROUTE || IPV6_MROUTE\nnet/ipv4/Kconfig-219-\nnet/ipv4/Kconfig:220:config IP_MROUTE\nnet/ipv4/Kconfig-221-\tbool \"IP: multicast routing\"\nnet/ipv4/Kconfig-222-\tdepends on IP_MULTICAST\nnet/ipv4/Kconfig:223:\tselect IP_MROUTE_COMMON\nnet/ipv4/Kconfig-224-\thelp\n--\nnet/ipv4/Kconfig-231-\nnet/ipv4/Kconfig:232:config IP_MROUTE_MULTIPLE_TABLES\nnet/ipv4/Kconfig-233-\tbool \"IP: multicast policy routing\"\nnet/ipv4/Kconfig:234:\tdepends on IP_MROUTE \u0026\u0026 IP_ADVANCED_ROUTER\nnet/ipv4/Kconfig-235-\tselect FIB_RULES\n--\nnet/ipv4/Kconfig=246=config IP_PIMSM_V1\nnet/ipv4/Kconfig-247-\tbool \"IP: PIM-SM version 1 support\"\nnet/ipv4/Kconfig:248:\tdepends on IP_MROUTE\nnet/ipv4/Kconfig-249-\thelp\n--\nnet/ipv4/Kconfig=259=config IP_PIMSM_V2\nnet/ipv4/Kconfig-260-\tbool \"IP: PIM-SM version 2 support\"\nnet/ipv4/Kconfig:261:\tdepends on IP_MROUTE\nnet/ipv4/Kconfig-262-\thelp\n--\nnet/ipv4/Makefile=22=obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o\nnet/ipv4/Makefile:23:obj-$(CONFIG_IP_MROUTE) += ipmr.o\nnet/ipv4/Makefile:24:obj-$(CONFIG_IP_MROUTE_COMMON) += ipmr_base.o\nnet/ipv4/Makefile-25-obj-$(CONFIG_NET_IPIP) += ipip.o\n--\nnet/ipv4/af_inet.c-116-#include \u003cnet/secure_seq.h\u003e\nnet/ipv4/af_inet.c:117:#ifdef CONFIG_IP_MROUTE\nnet/ipv4/af_inet.c-118-#include \u003clinux/mroute.h\u003e\n--\nnet/ipv4/af_inet.c=1882=static int __init inet_init(void)\n--\nnet/ipv4/af_inet.c-1988-\t */\nnet/ipv4/af_inet.c:1989:#if defined(CONFIG_IP_MROUTE)\nnet/ipv4/af_inet.c-1990-\tif (ip_mr_init())\n--\nnet/ipv4/igmp.c-101-#include \u003clinux/netfilter_ipv4.h\u003e\nnet/ipv4/igmp.c:102:#ifdef CONFIG_IP_MROUTE\nnet/ipv4/igmp.c-103-#include \u003clinux/mroute.h\u003e\n--\nnet/ipv4/ip_output.c=367=int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb)\n--\nnet/ipv4/ip_output.c-383-\t\tif (sk_mc_loop(sk)\nnet/ipv4/ip_output.c:384:#ifdef CONFIG_IP_MROUTE\nnet/ipv4/ip_output.c-385-\t\t/* Small optimization: do not loopback not local frames,\n--\nnet/ipv4/ipmr.c=118=static void ipmr_expire_process(struct timer_list *t);\nnet/ipv4/ipmr.c-119-\nnet/ipv4/ipmr.c:120:#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES\nnet/ipv4/ipmr.c-121-#define ipmr_for_each_table(mrt, net)\t\t\t\t\t\\\n--\nnet/ipv4/ipmr.c=408=static void ipmr_new_table_set(struct mr_table *mrt,\n--\nnet/ipv4/ipmr.c-410-{\nnet/ipv4/ipmr.c:411:#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES\nnet/ipv4/ipmr.c-412-\tlist_add_tail_rcu(\u0026mrt-\u003elist, \u0026net-\u003eipv4.mr_tables);\n--\nnet/ipv4/ipmr.c=1410=int ip_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,\n--\nnet/ipv4/ipmr.c-1578-\tcase MRT_TABLE:\nnet/ipv4/ipmr.c:1579:\t\tif (!IS_BUILTIN(CONFIG_IP_MROUTE_MULTIPLE_TABLES)) {\nnet/ipv4/ipmr.c-1580-\t\t\tret = -ENOPROTOOPT;\n--\nnet/ipv4/raw.c=871=static int raw_ioctl(struct sock *sk, int cmd, int *karg)\n--\nnet/ipv4/raw.c-891-\tdefault:\nnet/ipv4/raw.c:892:#ifdef CONFIG_IP_MROUTE\nnet/ipv4/raw.c-893-\t\treturn ipmr_ioctl(sk, cmd, karg);\n--\nnet/ipv4/raw.c=901=static int compat_raw_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)\n--\nnet/ipv4/raw.c-907-\tdefault:\nnet/ipv4/raw.c:908:#ifdef CONFIG_IP_MROUTE\nnet/ipv4/raw.c-909-\t\treturn ipmr_compat_ioctl(sk, cmd, compat_ptr(arg));\n--\nnet/ipv4/route.c=1739=ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,\n--\nnet/ipv4/route.c-1769-\nnet/ipv4/route.c:1770:#ifdef CONFIG_IP_MROUTE\nnet/ipv4/route.c-1771-\tif (!ipv4_is_local_multicast(daddr) \u0026\u0026 IN_DEV_MFORWARD(in_dev))\n--\nnet/ipv4/route.c=2491=ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr,\n--\nnet/ipv4/route.c-2527-\t\tif (our\nnet/ipv4/route.c:2528:#ifdef CONFIG_IP_MROUTE\nnet/ipv4/route.c-2529-\t\t\t||\n--\nnet/ipv4/route.c=2559=static struct rtable *__mkroute_output(const struct fib_result *res,\n--\nnet/ipv4/route.c-2666-\t\t}\nnet/ipv4/route.c:2667:#ifdef CONFIG_IP_MROUTE\nnet/ipv4/route.c-2668-\t\tif (type == RTN_MULTICAST) {\n--\nnet/ipv4/route.c=2946=static int rt_fill_info(struct net *net, __be32 dst, __be32 src,\n--\nnet/ipv4/route.c-3048-\t\tif (rt_is_input_route(rt)) {\nnet/ipv4/route.c:3049:#ifdef CONFIG_IP_MROUTE\nnet/ipv4/route.c-3050-\t\t\tif (ipv4_is_multicast(dst) \u0026\u0026\n--\nnet/ipv6/Kconfig=257=config IPV6_MROUTE\n--\nnet/ipv6/Kconfig-259-\tdepends on IPV6\nnet/ipv6/Kconfig:260:\tselect IP_MROUTE_COMMON\nnet/ipv6/Kconfig-261-\thelp\n--\ntools/testing/selftests/bpf/config.x86_64=106=CONFIG_IP_ADVANCED_ROUTER=y\ntools/testing/selftests/bpf/config.x86_64:107:CONFIG_IP_MROUTE=y\ntools/testing/selftests/bpf/config.x86_64-108-CONFIG_IP_MULTICAST=y\n--\ntools/testing/selftests/hid/config.common=93=CONFIG_IP_ADVANCED_ROUTER=y\ntools/testing/selftests/hid/config.common:94:CONFIG_IP_MROUTE=y\ntools/testing/selftests/hid/config.common-95-CONFIG_IP_MULTICAST=y\n--\ntools/testing/selftests/net/forwarding/config=6=CONFIG_DUMMY=m\ntools/testing/selftests/net/forwarding/config:7:CONFIG_IP_MROUTE=y\ntools/testing/selftests/net/forwarding/config:8:CONFIG_IP_MROUTE_MULTIPLE_TABLES=y\ntools/testing/selftests/net/forwarding/config-9-CONFIG_IP_PIMSM_V1=y\n"
} |
| 7/2 | 2026/07/24 22:59 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 26369 output: 236 thoughts: 1350 Thoughts: **Analysis of the IPv6 Multicast Routing Patch** Okay, so I've been tasked with analyzing this patch, and here's my breakdown. First off, I see the core configurations involved: `IPV6_MROUTE`, `IPV6_MROUTE_MULTIPLE_TABLES`, and `IPV6_PIMSM_V2`. Let's clarify why, because the patch only touches `net/ipv6/ip6mr.c` and `net/ipv4/ipmr_base.c`. `ipmr_base.c` is compiled under `CONFIG_IP_MROUTE_COMMON`, which gets enabled when we have either `IPV6_MROUTE` or `IP_MROUTE`. Since the patch *isn't* touching IPv4 specific routing code (like `net/ipv4/ipmr.c`), `IPV6_MROUTE` is the critical config here. And since multiple tables and PIMv2 are relevant parts of IPv6 multicast routing, those configurations are also necessary. So, yes, the set includes `IPV6_MROUTE`, `IPV6_MROUTE_MULTIPLE_TABLES`, and `IPV6_PIMSM_V2`. Just to confirm: `CONFIG_IPV6_MROUTE` is dependent on `CONFIG_IPV6`. `CONFIG_IPV6_MROUTE_MULTIPLE_TABLES` depends on `CONFIG_IPV6_MROUTE` and selects `CONFIG_FIB_RULES`. `CONFIG_IPV6_PIMSM_V2` depends on `CONFIG_IPV6_MROUTE`. Now, focusing on the symbols. I've compiled a list: `ip6_mroute_setsockopt`, `ip6_mroute_getsockopt`, `ip6mr_ioctl`, `ip6mr_compat_ioctl`, `ip6_mr_input`, `ip6_mr_output`, `ip6mr_rtm_getroute`, `ip6mr_rtm_dumproute`, `pim6_rcv`, and `reg_vif_xmit`. Let's verify these in the patch and also that they are not static/inlined, per instructions. `ip6_mroute_setsockopt` and `ip6_mroute_getsockopt` seem to be exported, meaning global. Same with `ip6mr_ioctl` and `ip6mr_compat_ioctl`. `ip6_mr_input` and `ip6_mr_output` also appear to be exported and global. Now, `ip6mr_rtm_getroute` and `ip6mr_rtm_dumproute` are static but registered as netlink callbacks. That means their addresses are being taken, so they won't be inlined. `pim6_rcv` is also static, but a protocol handler and `reg_vif_xmit` is static, but a netdev op -- both are fine. That means we don't have to change the list. So, the focus symbols are: `ip6_mroute_setsockopt`, `ip6_mroute_getsockopt`, `ip6mr_ioctl`, `ip6mr_compat_ioctl`, `ip6_mr_input`, `ip6_mr_output`, `pim6_rcv`, `reg_vif_xmit`, `ip6mr_rtm_getroute`, and `ip6mr_rtm_dumproute`. Alright, let's verify if the relevant symbols are in the patch. I see modifications to `ip6mr_rtm_getroute` and `ip6mr_rtm_dumproute` to use `ip6mr_get_table_hold` and `ip6mr_put_table`, which is good. Also, `ip6_mr_input`, `ip6_mr_output`, `pim6_rcv`, and `reg_vif_xmit` are modified. Likewise, `ip6_mroute_setsockopt`, `ip6_mroute_getsockopt`, `ip6mr_ioctl`, and `ip6mr_compat_ioctl` are updated. Checking for any missed entry points... Ah, I see that `mroute6_is_socket` is modified as well, along with `ip6mr_sk_done`. That's important! So, to be absolutely sure, here's my final list of symbols to include: `ip6_mroute_setsockopt`, `ip6_mroute_getsockopt`, `ip6mr_ioctl`, `ip6mr_compat_ioctl`, `ip6_mr_input`, `ip6_mr_output`, `pim6_rcv`, ` |
| 8/2 | 2026/07/24 23:00 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"IPV6_MROUTE",
"IPV6_MROUTE_MULTIPLE_TABLES",
"IPV6_PIMSM_V2"
],
"FocusSymbols": [
"ip6_mroute_setsockopt",
"ip6_mroute_getsockopt",
"ip6mr_ioctl",
"ip6mr_compat_ioctl",
"ip6_mr_input",
"ip6_mr_output",
"pim6_rcv",
"reg_vif_xmit",
"mroute6_is_socket",
"ip6mr_sk_done"
],
"Reasoning": "The patch introduces reference counting to IPv6 multicast routing tables (struct mr_table) to fix potential use-after-free issues. It modifies various entry points (socket options, ioctls, netlink, packet rx/tx) to hold a reference to the table while in use. This is a functional change in core networking logic that should be fuzzed.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"IPV6_MROUTE",
"IPV6_MROUTE_MULTIPLE_TABLES",
"IPV6_PIMSM_V2"
],
"FocusSymbols": [
"ip6_mroute_setsockopt",
"ip6_mroute_getsockopt",
"ip6mr_ioctl",
"ip6mr_compat_ioctl",
"ip6_mr_input",
"ip6_mr_output",
"pim6_rcv",
"reg_vif_xmit",
"mroute6_is_socket",
"ip6mr_sk_done"
],
"Reasoning": "The patch introduces reference counting to IPv6 multicast routing tables (struct mr_table) to fix potential use-after-free issues. It modifies various entry points (socket options, ioctls, netlink, packet rx/tx) to hold a reference to the table while in use. This is a functional change in core networking logic that should be fuzzed.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|