| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/08/17 07:04 | flow | patch-triage |
10mArgs:null Results: {
"EnableConfigs": [
"TIPC"
],
"FocusSymbols": [
"tipc_named_distribute",
"tipc_nametb_insert_self_node_pub",
"tipc_nametbl_publish",
"tipc_named_node_up"
],
"KMSANReasoning": "The patch modifies the TIPC subsystem to handle memory allocation failures (returning `-ENOBUFS`) during name table distribution. It adds error handling to functions like `tipc_named_distribute`, `tipc_named_node_up`, and `tipc_nametbl_publish`, and introduces flags to track the state of the name table and node address. All newly introduced variables and structures (e.g., `struct tipc_socket_addr sk`, `struct tipc_uaddr ua`) are fully initialized before use (e.g., via explicit assignment or the `tipc_uaddr()` helper). No new structures are copied to user space, and no complex data structures are allocated where uninitialized fields could be read later. The changes primarily affect control flow and error handling for memory allocation failures, which do not expose uninitialized memory risks. Standard KASAN and other bug detectors are sufficient to catch any potential out-of-bounds accesses or use-after-free bugs. Therefore, a dedicated KMSAN fuzzing session is not necessary.",
"NeedsKMSAN": false,
"Reasoning": "The patch modifies the core TIPC logic to handle memory allocation failures during name table distribution. It adds error code returns to functions like `tipc_nametbl_publish` and `tipc_named_node_up`, and introduces `tipc_nametb_insert_self_node_pub` and `tipc_named_distribute` to handle bulk redistribution of cluster-scope publications. These are functional changes to reachable core kernel logic, and should be fuzzed.",
"WorthFuzzing": true
} |
| 1/1 | 2026/08/17 07:04 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit ea7c3d4b9b40a93d311459bcbe2bd66bd922d385\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Aug 17 07:03:58 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/net/tipc/core.c b/net/tipc/core.c\nindex 315975c3be818..0f1d3ddeae095 100644\n--- a/net/tipc/core.c\n+++ b/net/tipc/core.c\n@@ -61,6 +61,9 @@ static int __net_init tipc_init_net(struct net *net)\n \ttn-\u003etrial_addr = 0;\n \ttn-\u003eaddr_trial_end = 0;\n \ttn-\u003ecapabilities = TIPC_NODE_CAPABILITIES;\n+\ttn-\u003ent_stop = false;\n+\ttn-\u003ent_self_node_exist = false;\n+\tatomic_set(\u0026tn-\u003enode_addr_set, 0);\n \tINIT_WORK(\u0026tn-\u003ework, tipc_net_finalize_work);\n \tmemset(tn-\u003enode_id, 0, sizeof(tn-\u003enode_id));\n \tmemset(tn-\u003enode_id_string, 0, sizeof(tn-\u003enode_id_string));\ndiff --git a/net/tipc/core.h b/net/tipc/core.h\nindex 9ce5f9ff6cc03..975b1d48186e6 100644\n--- a/net/tipc/core.h\n+++ b/net/tipc/core.h\n@@ -145,6 +145,12 @@ struct tipc_net {\n \tstruct work_struct work;\n \t/* The numbers of work queues in schedule */\n \tatomic_t wq_count;\n+\t/* Flag to indicate that the node's address is set */\n+\tatomic_t node_addr_set;\n+\t/* The name table has stopped working */\n+\tbool nt_stop;\n+\t/* Node's self address publication is available in the name table */\n+\tbool nt_self_node_exist;\n };\n \n static inline struct tipc_net *tipc_net(struct net *net)\ndiff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c\nindex ba4f4906e13b7..83e3ed8f2c512 100644\n--- a/net/tipc/name_distr.c\n+++ b/net/tipc/name_distr.c\n@@ -95,9 +95,7 @@ struct sk_buff *tipc_named_publish(struct net *net, struct publication *p)\n \t\tlist_add_tail_rcu(\u0026p-\u003ebinding_node, \u0026nt-\u003enode_scope);\n \t\treturn NULL;\n \t}\n-\twrite_lock_bh(\u0026nt-\u003ecluster_scope_lock);\n \tlist_add_tail(\u0026p-\u003ebinding_node, \u0026nt-\u003ecluster_scope);\n-\twrite_unlock_bh(\u0026nt-\u003ecluster_scope_lock);\n \tskb = named_prepare_buf(net, PUBLICATION, ITEM_SIZE, 0);\n \tif (!skb) {\n \t\tpr_warn(\"Publication distribution failure\\n\");\n@@ -121,9 +119,7 @@ struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *p)\n \tstruct distr_item *item;\n \tstruct sk_buff *skb;\n \n-\twrite_lock_bh(\u0026nt-\u003ecluster_scope_lock);\n \tlist_del(\u0026p-\u003ebinding_node);\n-\twrite_unlock_bh(\u0026nt-\u003ecluster_scope_lock);\n \tif (p-\u003escope == TIPC_NODE_SCOPE)\n \t\treturn NULL;\n \n@@ -146,9 +142,14 @@ struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *p)\n * @dnode: node to be updated\n * @pls: linked list of publication items to be packed into buffer chain\n * @seqno: sequence number for this message\n+ *\n+ * Return:\n+ * * 0 - Success\n+ * * -ENOBUFS - No buffer space is available\n+ *\n */\n-static void named_distribute(struct net *net, struct sk_buff_head *list,\n-\t\t\t u32 dnode, struct list_head *pls, u16 seqno)\n+static int named_distribute(struct net *net, struct sk_buff_head *list,\n+\t\t\t u32 dnode, struct list_head *pls, u16 seqno)\n {\n \tstruct publication *publ;\n \tstruct sk_buff *skb = NULL;\n@@ -164,8 +165,9 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,\n \t\t\tskb = named_prepare_buf(net, PUBLICATION, msg_rem,\n \t\t\t\t\t\tdnode);\n \t\t\tif (!skb) {\n+\t\t\t\t__skb_queue_purge(list);\n \t\t\t\tpr_warn(\"Bulk publication failure\\n\");\n-\t\t\t\treturn;\n+\t\t\t\treturn -ENOBUFS;\n \t\t\t}\n \t\t\thdr = buf_msg(skb);\n \t\t\tmsg_set_bc_ack_invalid(hdr, true);\n@@ -195,6 +197,90 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,\n \thdr = buf_msg(skb_peek_tail(list));\n \tmsg_set_last_bulk(hdr);\n \tmsg_set_named_seqno(hdr, seqno);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * __tipc_named_distribute - build a list of publications need to be distributed\n+ * @net: the associated network namespace\n+ * @dnode: destination node\n+ * @head: list of publications\n+ *\n+ * Return:\n+ * * 0 - Success\n+ * * -ENOBUFS - No buffer space is available\n+ *\n+ */\n+static int __tipc_named_distribute(struct net *net, u32 dnode,\n+\t\t\t\t struct sk_buff_head *head)\n+{\n+\tstruct name_table *nt = tipc_name_table(net);\n+\tstruct tipc_net *tn = tipc_net(net);\n+\n+\t/* Name table has been deleted after namespace teardown or\n+\t * TIPC module exit.\n+\t */\n+\tif (unlikely(tn-\u003ent_stop))\n+\t\treturn 0;\n+\n+\t/* Node's self-address is not set yet */\n+\tif (!atomic_read(\u0026tn-\u003enode_addr_set)) {\n+\t\t/* Defer the distribution to node's timer */\n+\t\ttipc_node_set_dist_bulk(net, dnode);\n+\t\treturn 0;\n+\t}\n+\n+\t/* Previous call to tipc_nametb_insert_self_node_pub() was successful.\n+\t * The node's self-address publication was added to 'nt-\u003ecluster_scope'.\n+\t * So, 'nt-\u003ecluster_scope' is not empty now. Go to distribution.\n+\t */\n+\tif (tn-\u003ent_self_node_exist)\n+\t\tgoto distribute;\n+\n+\tif (tipc_nametb_insert_self_node_pub(net))\n+\t\treturn -ENOBUFS;\n+\n+\ttn-\u003ent_self_node_exist = true;\n+\n+distribute:\n+\tif (named_distribute(net, head, dnode,\n+\t\t\t \u0026nt-\u003ecluster_scope, nt-\u003esnd_nxt) == -ENOBUFS)\n+\t\treturn -ENOBUFS;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * tipc_named_distribute - distribute all publications to specified node\n+ * @net: the associated network namespace\n+ * @dnode: destination node\n+ *\n+ * Return:\n+ * * 0 - Success\n+ * * -ENOBUFS - No buffer space is available\n+ *\n+ */\n+int tipc_named_distribute(struct net *net, u32 dnode)\n+{\n+\tstruct tipc_net *tn = tipc_net(net);\n+\tstruct sk_buff_head head;\n+\tint rc = 0;\n+\n+\t__skb_queue_head_init(\u0026head);\n+\tspin_lock_bh(\u0026tn-\u003enametbl_lock);\n+\trc = __tipc_named_distribute(net, dnode, \u0026head);\n+\tspin_unlock_bh(\u0026tn-\u003enametbl_lock);\n+\tif (!rc \u0026\u0026 !skb_queue_empty(\u0026head)) {\n+\t\trc = tipc_node_xmit(net, \u0026head, dnode, 0);\n+\t\t/* The link is congested after the list is inserted into the\n+\t\t * link's send queue. Return 0, as this is normal.\n+\t\t */\n+\t\tif (rc == -ELINKCONG)\n+\t\t\trc = 0;\n+\t}\n+\n+\treturn rc;\n }\n \n /**\n@@ -202,25 +288,36 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,\n * @net: the associated network namespace\n * @dnode: destination node\n * @capabilities: peer node's capabilities\n+ *\n+ * Return:\n+ * * 0 - Success\n+ * * -ENOBUFS - No buffer space is available\n+ *\n */\n-void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)\n+int tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)\n {\n \tstruct name_table *nt = tipc_name_table(net);\n \tstruct tipc_net *tn = tipc_net(net);\n \tstruct sk_buff_head head;\n-\tu16 seqno;\n+\tint rc = 0;\n \n \t__skb_queue_head_init(\u0026head);\n \tspin_lock_bh(\u0026tn-\u003enametbl_lock);\n \tif (!(capabilities \u0026 TIPC_NAMED_BCAST))\n \t\tnt-\u003erc_dests++;\n-\tseqno = nt-\u003esnd_nxt;\n+\n+\trc = __tipc_named_distribute(net, dnode, \u0026head);\n \tspin_unlock_bh(\u0026tn-\u003enametbl_lock);\n+\tif (!rc \u0026\u0026 !skb_queue_empty(\u0026head)) {\n+\t\trc = tipc_node_xmit(net, \u0026head, dnode, 0);\n+\t\t/* The link is congested after the list is inserted into the\n+\t\t * link's send queue. Return 0, as this is normal.\n+\t\t */\n+\t\tif (rc == -ELINKCONG)\n+\t\t\trc = 0;\n+\t}\n \n-\tread_lock_bh(\u0026nt-\u003ecluster_scope_lock);\n-\tnamed_distribute(net, \u0026head, dnode, \u0026nt-\u003ecluster_scope, seqno);\n-\ttipc_node_xmit(net, \u0026head, dnode, 0);\n-\tread_unlock_bh(\u0026nt-\u003ecluster_scope_lock);\n+\treturn rc;\n }\n \n /**\n@@ -299,7 +396,7 @@ static bool tipc_update_nametbl(struct net *net, struct distr_item *i,\n \tsk.node = node;\n \n \tif (dtype == PUBLICATION) {\n-\t\tp = tipc_nametbl_insert_publ(net, \u0026ua, \u0026sk, key);\n+\t\tp = tipc_nametbl_insert_publ(net, \u0026ua, \u0026sk, key, NULL);\n \t\tif (p) {\n \t\t\ttipc_node_subscribe(net, \u0026p-\u003ebinding_node, node);\n \t\t\treturn true;\n@@ -416,5 +513,6 @@ void tipc_named_reinit(struct net *net)\n \tlist_for_each_entry_rcu(p, \u0026nt-\u003ecluster_scope, binding_node)\n \t\tp-\u003esk.node = self;\n \tnt-\u003erc_dests = 0;\n+\ttn-\u003ent_stop = false;\n \tspin_unlock_bh(\u0026tn-\u003enametbl_lock);\n }\ndiff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h\nindex c677f6f082dfb..2043096ae967d 100644\n--- a/net/tipc/name_distr.h\n+++ b/net/tipc/name_distr.h\n@@ -69,11 +69,12 @@ struct distr_item {\n \n struct sk_buff *tipc_named_publish(struct net *net, struct publication *publ);\n struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ);\n-void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities);\n+int tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities);\n void tipc_named_rcv(struct net *net, struct sk_buff_head *namedq,\n \t\t u16 *rcv_nxt, bool *open);\n void tipc_named_reinit(struct net *net);\n void tipc_publ_notify(struct net *net, struct list_head *nsub_list,\n \t\t u32 addr, u16 capabilities);\n+int tipc_named_distribute(struct net *net, u32 dnode);\n \n #endif\ndiff --git a/net/tipc/name_table.c b/net/tipc/name_table.c\nindex 253c72d1366eb..beed40a21368a 100644\n--- a/net/tipc/name_table.c\n+++ b/net/tipc/name_table.c\n@@ -329,7 +329,7 @@ static struct service_range *tipc_service_create_range(struct tipc_service *sc,\n \n static bool tipc_service_insert_publ(struct net *net,\n \t\t\t\t struct tipc_service *sc,\n-\t\t\t\t struct publication *p)\n+\t\t\t\t struct publication *p, int *err)\n {\n \tstruct tipc_subscription *sub, *tmp;\n \tstruct service_range *sr;\n@@ -339,10 +339,12 @@ static bool tipc_service_insert_publ(struct net *net,\n \tbool res = false;\n \tu32 key = p-\u003ekey;\n \n-\tspin_lock_bh(\u0026sc-\u003elock);\n \tsr = tipc_service_create_range(sc, p);\n-\tif (!sr)\n-\t\tgoto exit;\n+\tif (!sr) {\n+\t\tif (err)\n+\t\t\t*err = -ENOBUFS;\n+\t\tgoto exit;\n+\t}\n \n \tfirst = list_empty(\u0026sr-\u003eall_publ);\n \n@@ -353,6 +355,8 @@ static bool tipc_service_insert_publ(struct net *net,\n \t\t\tpr_debug(\"Failed to bind duplicate %u,%u,%u/%u:%u/%u\\n\",\n \t\t\t\t p-\u003esr.type, p-\u003esr.lower, p-\u003esr.upper,\n \t\t\t\t node, p-\u003esk.ref, key);\n+\t\t\tif (err)\n+\t\t\t\t*err = -EEXIST;\n \t\t\tgoto exit;\n \t\t}\n \t}\n@@ -371,7 +375,6 @@ static bool tipc_service_insert_publ(struct net *net,\n \tif (!res)\n \t\tpr_warn(\"Failed to bind to %u,%u,%u\\n\",\n \t\t\tp-\u003esr.type, p-\u003esr.lower, p-\u003esr.upper);\n-\tspin_unlock_bh(\u0026sc-\u003elock);\n \treturn res;\n }\n \n@@ -478,20 +481,33 @@ static struct tipc_service *tipc_service_find(struct net *net,\n struct publication *tipc_nametbl_insert_publ(struct net *net,\n \t\t\t\t\t struct tipc_uaddr *ua,\n \t\t\t\t\t struct tipc_socket_addr *sk,\n-\t\t\t\t\t u32 key)\n+\t\t\t\t\t u32 key, int *err)\n {\n \tstruct tipc_service *sc;\n \tstruct publication *p;\n \n \tp = tipc_publ_create(ua, sk, key);\n-\tif (!p)\n+\tif (!p) {\n+\t\tif (err)\n+\t\t\t*err = -ENOBUFS;\n \t\treturn NULL;\n+\t}\n \n \tsc = tipc_service_find(net, ua);\n \tif (!sc)\n \t\tsc = tipc_service_create(net, ua);\n-\tif (sc \u0026\u0026 tipc_service_insert_publ(net, sc, p))\n-\t\treturn p;\n+\n+\tif (sc) {\n+\t\tspin_lock_bh(\u0026sc-\u003elock);\n+\t\tif (tipc_service_insert_publ(net, sc, p, err)) {\n+\t\t\tspin_unlock_bh(\u0026sc-\u003elock);\n+\t\t\treturn p;\n+\t\t}\n+\t\tspin_unlock_bh(\u0026sc-\u003elock);\n+\t} else if (err) {\n+\t\t*err = -ENOBUFS;\n+\t}\n+\n \tkfree(p);\n \treturn NULL;\n }\n@@ -760,26 +776,55 @@ void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,\n /* tipc_nametbl_publish - add service binding to name table\n */\n struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,\n-\t\t\t\t\t struct tipc_socket_addr *sk, u32 key)\n+\t\t\t\t\t struct tipc_socket_addr *sk,\n+\t\t\t\t\t u32 key, int *err)\n {\n \tstruct name_table *nt = tipc_name_table(net);\n+\tu32 max_user_pub = TIPC_MAX_PUBL - 1;\n \tstruct tipc_net *tn = tipc_net(net);\n \tstruct publication *p = NULL;\n \tstruct sk_buff *skb = NULL;\n+\tbool protocol_type = false;\n+\tint error = 0;\n \tu32 rc_dests;\n \n+\tif (ua-\u003esr.type == TIPC_NODE_STATE || ua-\u003esr.type == TIPC_LINK_STATE ||\n+\t ua-\u003esr.type == TIPC_TOP_SRV)\n+\t\tprotocol_type = true;\n+\n \tspin_lock_bh(\u0026tn-\u003enametbl_lock);\n+\tif (protocol_type)\n+\t\tgoto insert;\n \n-\tif (nt-\u003elocal_publ_count \u003e= TIPC_MAX_PUBL) {\n-\t\tpr_warn(\"Bind failed, max limit %u reached\\n\", TIPC_MAX_PUBL);\n+\t/* Reserve one entry for node state service type because it has cluster\n+\t * scope and it is distributed in bulk. So, the maximum number of user's\n+\t * publications is (TIPC_MAX_PUBL - 1).\n+\t */\n+\tif (nt-\u003elocal_publ_count \u003e= max_user_pub) {\n+\t\tpr_warn(\"Bind failed, max limit %u reached\\n\", max_user_pub);\n \t\tgoto exit;\n \t}\n \n-\tp = tipc_nametbl_insert_publ(net, ua, sk, key);\n+insert:\n+\tp = tipc_nametbl_insert_publ(net, ua, sk, key, \u0026error);\n \tif (p) {\n-\t\tnt-\u003elocal_publ_count++;\n+\t\t/* Not count node state, link state and topology server types\n+\t\t * so that maximum nt-\u003elocal_publ_count does not prevent\n+\t\t * protocol service types from being inserted into the name\n+\t\t * table.\n+\t\t */\n+\t\tif (!protocol_type)\n+\t\t\tnt-\u003elocal_publ_count++;\n \t\tskb = tipc_named_publish(net, p);\n+\t\t/* Local-scope publication is not published (skb is NULL), only\n+\t\t * cluster-cope one is.\n+\t\t */\n+\t\tif (!skb \u0026\u0026 p-\u003escope == TIPC_CLUSTER_SCOPE \u0026\u0026 err)\n+\t\t\t*err = -ENOBUFS;\n+\t} else if ((error == -ENOBUFS) \u0026\u0026 err) {\n+\t\t*err = -ENOBUFS;\n \t}\n+\n \trc_dests = nt-\u003erc_dests;\n exit:\n \tspin_unlock_bh(\u0026tn-\u003enametbl_lock);\n@@ -787,7 +832,102 @@ struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,\n \tif (skb)\n \t\ttipc_node_broadcast(net, skb, rc_dests);\n \treturn p;\n+}\n+\n+/**\n+ * tipc_nametb_insert_self_node_pub - insert publication of node's self address\n+ * @net: network namespace\n+ *\n+ * Return:\n+ * * 0 - Success\n+ * * -ENOBUFS - No buffer space is available\n+ *\n+ */\n+int tipc_nametb_insert_self_node_pub(struct net *net)\n+{\n+\tstruct name_table *nt = tipc_name_table(net);\n+\tstruct tipc_net *tn = tipc_net(net);\n+\tstruct tipc_socket_addr sk;\n+\tstruct service_range *sr;\n+\tstruct tipc_service *sc;\n+\tbool sc_created = false;\n+\tstruct publication *p;\n+\tstruct tipc_uaddr ua;\n+\tint err = 0;\n+\n+\tsk.ref = 0;\n+\tsk.node = tn-\u003enode_addr;\n+\ttipc_uaddr(\u0026ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,\n+\t\t TIPC_NODE_STATE, tn-\u003enode_addr, tn-\u003enode_addr);\n+\tsc = tipc_service_find(net, \u0026ua);\n+\tif (!sc) {\n+\t\tsc = tipc_service_create(net, \u0026ua);\n+\t\tif (!sc)\n+\t\t\treturn -ENOBUFS;\n+\t\tsc_created = true;\n+\t}\n \n+\tspin_lock_bh(\u0026sc-\u003elock);\n+\t/* Check whether a range exists in the name table with\n+\t * lower == tn-\u003enode_addr, upper == tn-\u003enode_addr, and type\n+\t * TIPC_NODE_STATE (0). If 'sr' is not NULL, this range exists\n+\t * due to a previous call to tipc_nametb_insert_self_node_pub()\n+\t * or tipc_net_finalize().\n+\t *\n+\t * Note that user applications can only insert types greater than\n+\t * or equal to 64 (TIPC_RESERVED_TYPES), as enforced by tipc_bind().\n+\t * Remote nodes also only send protocol publications with type\n+\t * TIPC_NODE_STATE (0), with both lower and upper set to the remote\n+\t * node's address. These ranges cannot be the same as this node's\n+\t * range because a remote node's address must differ from this\n+\t * node's address (tn-\u003enode_addr).\n+\t *\n+\t * Therefore, tipc_update_nametbl() cannot build and insert a remote\n+\t * publication with the same type (0) and range\n+\t * (lower == tn-\u003enode_addr, upper == tn-\u003enode_addr) as this node's\n+\t * self-address publication in the name table.\n+\t *\n+\t * Because the combination of type 0 and\n+\t * (lower == tn-\u003enode_addr, upper == tn-\u003enode_addr) is unique in the\n+\t * name table, it is not necessary to check sk.node, sk.ref, key, or\n+\t * cluster_scope membership.\n+\t */\n+\tsr = tipc_service_find_range(sc, \u0026ua);\n+\t/* 1. tipc_net_finalize_work() is not scheduled because of namespace\n+\t * teardown.\n+\t * 2. Or tipc_net_finalize() ---\u003e tipc_nametbl_publish() has failed\n+\t * to insert node self address publication into nt-\u003ecluster_scope\n+\t * due to memory allocation failure.\n+\t * 3. Or tipc_net_finalize() ---\u003e tipc_nametbl_publish() has not\n+\t * executed yet.\n+\t */\n+\tif (!sr) {\n+\t\tp = tipc_publ_create(\u0026ua, \u0026sk, tn-\u003enode_addr);\n+\t\tif (!p)\n+\t\t\tgoto error;\n+\n+\t\tif (!tipc_service_insert_publ(net, sc, p, \u0026err) \u0026\u0026\n+\t\t (err == -ENOBUFS)) {\n+\t\t\tkfree(p);\n+\t\t\tgoto error;\n+\t\t}\n+\n+\t\tlist_add_tail(\u0026p-\u003ebinding_node, \u0026nt-\u003ecluster_scope);\n+\t\tgoto exit;\n+error:\n+\t\tif (sc_created) {\n+\t\t\thlist_del_init_rcu(\u0026sc-\u003eservice_list);\n+\t\t\tspin_unlock_bh(\u0026sc-\u003elock);\n+\t\t\tkfree_rcu(sc, rcu);\n+\t\t\treturn -ENOBUFS;\n+\t\t}\n+\n+\t\tspin_unlock_bh(\u0026sc-\u003elock);\n+\t\treturn -ENOBUFS;\n+\t}\n+exit:\n+\tspin_unlock_bh(\u0026sc-\u003elock);\n+\treturn 0;\n }\n \n /**\n@@ -810,7 +950,10 @@ void tipc_nametbl_withdraw(struct net *net, struct tipc_uaddr *ua,\n \n \tp = tipc_nametbl_remove_publ(net, ua, sk, key);\n \tif (p) {\n-\t\tnt-\u003elocal_publ_count--;\n+\t\tif (p-\u003esr.type != TIPC_NODE_STATE \u0026\u0026\n+\t\t p-\u003esr.type != TIPC_LINK_STATE \u0026\u0026\n+\t\t p-\u003esr.type != TIPC_TOP_SRV)\n+\t\t\tnt-\u003elocal_publ_count--;\n \t\tskb = tipc_named_withdraw(net, p);\n \t\tlist_del_init(\u0026p-\u003ebinding_sock);\n \t\tkfree_rcu(p, rcu);\n@@ -899,7 +1042,6 @@ int tipc_nametbl_init(struct net *net)\n \n \tINIT_LIST_HEAD(\u0026nt-\u003enode_scope);\n \tINIT_LIST_HEAD(\u0026nt-\u003ecluster_scope);\n-\trwlock_init(\u0026nt-\u003ecluster_scope_lock);\n \ttn-\u003enametbl = nt;\n \tspin_lock_init(\u0026tn-\u003enametbl_lock);\n \treturn 0;\n@@ -912,6 +1054,7 @@ int tipc_nametbl_init(struct net *net)\n */\n static void tipc_service_delete(struct net *net, struct tipc_service *sc)\n {\n+\tstruct tipc_net *tn = tipc_net(net);\n \tstruct service_range *sr, *tmpr;\n \tstruct publication *p, *tmp;\n \n@@ -919,6 +1062,15 @@ static void tipc_service_delete(struct net *net, struct tipc_service *sc)\n \trbtree_postorder_for_each_entry_safe(sr, tmpr, \u0026sc-\u003eranges, tree_node) {\n \t\tlist_for_each_entry_safe(p, tmp, \u0026sr-\u003eall_publ, all_publ) {\n \t\t\ttipc_service_remove_publ(sr, \u0026p-\u003esk, p-\u003ekey);\n+\t\t\t/* tipc_nametbl_withdraw() does not delete\n+\t\t\t * 'p-\u003ebinding_node' with type TIPC_NODE_STATE and\n+\t\t\t * range [tn-\u003enode_addr, tn-\u003enode_addr] from\n+\t\t\t * 'tn-\u003ecluster_scope'. So, delete it here.\n+\t\t\t */\n+\t\t\tif (p-\u003esr.type == TIPC_NODE_STATE \u0026\u0026\n+\t\t\t p-\u003esr.lower == tn-\u003enode_addr \u0026\u0026\n+\t\t\t p-\u003esr.upper == tn-\u003enode_addr)\n+\t\t\t\tlist_del(\u0026p-\u003ebinding_node);\n \t\t\tkfree_rcu(p, rcu);\n \t\t}\n \t\trb_erase_augmented(\u0026sr-\u003etree_node, \u0026sc-\u003eranges, \u0026sr_callbacks);\n@@ -949,6 +1101,8 @@ void tipc_nametbl_stop(struct net *net)\n \t\t\ttipc_service_delete(net, service);\n \t\t}\n \t}\n+\ttn-\u003ent_stop = true;\n+\ttn-\u003ent_self_node_exist = false;\n \tspin_unlock_bh(\u0026tn-\u003enametbl_lock);\n \n \t/* TODO: clear tn-\u003enametbl, implement proper RCU rules ? */\ndiff --git a/net/tipc/name_table.h b/net/tipc/name_table.h\nindex 7ff6eeebaae64..4390e79a4660e 100644\n--- a/net/tipc/name_table.h\n+++ b/net/tipc/name_table.h\n@@ -97,8 +97,7 @@ struct publication {\n * @cluster_scope: all local publications with cluster scope\n * - used by name_distr to send bulk updates to new nodes\n * - used by name_distr during re-init of name table\n- * @cluster_scope_lock: lock for accessing @cluster_scope\n- * @local_publ_count: number of publications issued by this node\n+ * @local_publ_count: the number of user's publications issued by this node\n * @rc_dests: destination node counter\n * @snd_nxt: next sequence number to be used\n */\n@@ -107,7 +106,6 @@ struct name_table {\n \tstruct hlist_head services[TIPC_NAMETBL_SIZE];\n \tstruct list_head node_scope;\n \tstruct list_head cluster_scope;\n-\trwlock_t cluster_scope_lock;\n \tu32 local_publ_count;\n \tu32 rc_dests;\n \tu32 snd_nxt;\n@@ -126,13 +124,15 @@ bool tipc_nametbl_lookup_group(struct net *net, struct tipc_uaddr *ua,\n void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,\n \t\t\t struct tipc_uaddr *ua);\n struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,\n-\t\t\t\t\t struct tipc_socket_addr *sk, u32 key);\n+\t\t\t\t\t struct tipc_socket_addr *sk,\n+\t\t\t\t\t u32 key, int *err);\n void tipc_nametbl_withdraw(struct net *net, struct tipc_uaddr *ua,\n \t\t\t struct tipc_socket_addr *sk, u32 key);\n struct publication *tipc_nametbl_insert_publ(struct net *net,\n \t\t\t\t\t struct tipc_uaddr *ua,\n \t\t\t\t\t struct tipc_socket_addr *sk,\n-\t\t\t\t\t u32 key);\n+\t\t\t\t\t u32 key, int *err);\n+int tipc_nametb_insert_self_node_pub(struct net *net);\n struct publication *tipc_nametbl_remove_publ(struct net *net,\n \t\t\t\t\t struct tipc_uaddr *ua,\n \t\t\t\t\t struct tipc_socket_addr *sk,\ndiff --git a/net/tipc/net.c b/net/tipc/net.c\nindex 7e65d0b0c4a8d..7a2c1e67aca3d 100644\n--- a/net/tipc/net.c\n+++ b/net/tipc/net.c\n@@ -110,11 +110,14 @@ static void tipc_net_finalize(struct net *net, u32 addr);\n \n int tipc_net_init(struct net *net, u8 *node_id, u32 addr)\n {\n+\tstruct tipc_net *tn = tipc_net(net);\n+\n \tif (tipc_own_id(net)) {\n \t\tpr_info(\"Cannot configure node identity twice\\n\");\n \t\treturn -1;\n \t}\n \tpr_info(\"Started in network mode\\n\");\n+\tatomic_set(\u0026tn-\u003enode_addr_set, 0);\n \n \tif (node_id)\n \t\ttipc_set_node_id(net, node_id);\n@@ -125,8 +128,8 @@ int tipc_net_init(struct net *net, u8 *node_id, u32 addr)\n \n static void tipc_net_finalize(struct net *net, u32 addr)\n {\n-\tstruct tipc_net *tn = tipc_net(net);\n \tstruct tipc_socket_addr sk = {0, addr};\n+\tstruct tipc_net *tn = tipc_net(net);\n \tstruct tipc_uaddr ua;\n \n \ttipc_uaddr(\u0026ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,\n@@ -138,7 +141,11 @@ static void tipc_net_finalize(struct net *net, u32 addr)\n \ttipc_named_reinit(net);\n \ttipc_sk_reinit(net);\n \ttipc_mon_reinit_self(net);\n-\ttipc_nametbl_publish(net, \u0026ua, \u0026sk, addr);\n+\tatomic_set(\u0026tn-\u003enode_addr_set, 1);\n+\t/* Redistribute bulk of publications via node-up event or node's timer\n+\t * if tipc_nametbl_publish() fails.\n+\t */\n+\ttipc_nametbl_publish(net, \u0026ua, \u0026sk, addr, NULL);\n }\n \n void tipc_net_finalize_work(struct work_struct *work)\ndiff --git a/net/tipc/node.c b/net/tipc/node.c\nindex 683a136e53efc..f1eee674a678e 100644\n--- a/net/tipc/node.c\n+++ b/net/tipc/node.c\n@@ -111,6 +111,7 @@ struct tipc_bclink_entry {\n * @peer_net: peer's net namespace\n * @peer_hash_mix: hash for this peer (FIXME)\n * @crypto_rx: RX crypto handler\n+ * @dist_bulk: flag to redistribute cluster-scope publications\n */\n struct tipc_node {\n \tu32 addr;\n@@ -145,6 +146,7 @@ struct tipc_node {\n #ifdef CONFIG_TIPC_CRYPTO\n \tstruct tipc_crypto *crypto_rx;\n #endif\n+\tatomic_t dist_bulk;\n };\n \n /* Node FSM states and events:\n@@ -345,6 +347,17 @@ static struct tipc_node *tipc_node_find(struct net *net, u32 addr)\n \treturn node;\n }\n \n+void tipc_node_set_dist_bulk(struct net *net, u32 addr)\n+{\n+\tstruct tipc_node *node;\n+\n+\tnode = tipc_node_find(net, addr);\n+\tif (node) {\n+\t\tatomic_set(\u0026node-\u003edist_bulk, 1);\n+\t\ttipc_node_put(node);\n+\t}\n+}\n+\n /* tipc_node_find_by_id - locate specified node object by its 128-bit id\n * Note: this function is called only when a discovery request failed\n * to find the node by its 32-bit id, and is not time critical\n@@ -393,6 +406,14 @@ static void tipc_node_write_unlock_fast(struct tipc_node *n)\n \twrite_unlock_bh(\u0026n-\u003elock);\n }\n \n+static void tipc_node_down(struct tipc_node *n)\n+{\n+\tint bearer_id;\n+\n+\tfor (bearer_id = 0; bearer_id \u003c MAX_BEARERS; bearer_id++)\n+\t\ttipc_node_link_down(n, bearer_id, false);\n+}\n+\n static void tipc_node_write_unlock(struct tipc_node *n)\n \t__releases(n-\u003elock)\n {\n@@ -402,6 +423,7 @@ static void tipc_node_write_unlock(struct tipc_node *n)\n \tstruct list_head *publ_list;\n \tstruct tipc_uaddr ua;\n \tu32 bearer_id, node;\n+\tint rc = 0, err = 0;\n \n \tif (likely(!flags)) {\n \t\twrite_unlock_bh(\u0026n-\u003elock);\n@@ -425,16 +447,24 @@ static void tipc_node_write_unlock(struct tipc_node *n)\n \t\ttipc_publ_notify(net, publ_list, node, n-\u003ecapabilities);\n \n \tif (flags \u0026 TIPC_NOTIFY_NODE_UP)\n-\t\ttipc_named_node_up(net, node, n-\u003ecapabilities);\n+\t\trc = tipc_named_node_up(net, node, n-\u003ecapabilities);\n \n \tif (flags \u0026 TIPC_NOTIFY_LINK_UP) {\n \t\ttipc_mon_peer_up(net, node, bearer_id);\n-\t\ttipc_nametbl_publish(net, \u0026ua, \u0026sk, sk.ref);\n+\t\ttipc_nametbl_publish(net, \u0026ua, \u0026sk, sk.ref, \u0026err);\n \t}\n \tif (flags \u0026 TIPC_NOTIFY_LINK_DOWN) {\n \t\ttipc_mon_peer_down(net, node, bearer_id);\n \t\ttipc_nametbl_withdraw(net, \u0026ua, \u0026sk, sk.ref);\n \t}\n+\n+\t/* Memory allocation has failed. Bring the node down to start over bulk\n+\t * distribution when the first link is up again.\n+\t */\n+\tif (rc \u003c 0)\n+\t\ttipc_node_down(n);\n+\telse if (err == -ENOBUFS)\n+\t\ttipc_node_link_down(n, bearer_id, false);\n }\n \n static void tipc_node_assign_peer_net(struct tipc_node *n, u32 hash_mixes)\n@@ -564,6 +594,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u8 *peer_id,\n \tINIT_LIST_HEAD(\u0026n-\u003elist);\n \tINIT_LIST_HEAD(\u0026n-\u003epubl_list);\n \tINIT_LIST_HEAD(\u0026n-\u003econn_sks);\n+\tatomic_set(\u0026n-\u003edist_bulk, 0);\n \tskb_queue_head_init(\u0026n-\u003ebc_entry.namedq);\n \tskb_queue_head_init(\u0026n-\u003ebc_entry.inputq1);\n \t__skb_queue_head_init(\u0026n-\u003ebc_entry.arrvq);\n@@ -803,7 +834,8 @@ static void tipc_node_timeout(struct timer_list *t)\n \tstruct tipc_node *n = timer_container_of(n, t, timer);\n \tstruct tipc_link_entry *le;\n \tstruct sk_buff_head xmitq;\n-\tint remains = n-\u003elink_cnt;\n+\tint remains = 0;\n+\tint dist_rc = 0;\n \tint bearer_id;\n \tint rc = 0;\n \n@@ -814,6 +846,9 @@ static void tipc_node_timeout(struct timer_list *t)\n \t\treturn;\n \t}\n \n+\tif (atomic_xchg(\u0026n-\u003edist_bulk, 0))\n+\t\tdist_rc = tipc_named_distribute(n-\u003enet, n-\u003eaddr);\n+\n #ifdef CONFIG_TIPC_CRYPTO\n \t/* Take any crypto key related actions first */\n \ttipc_crypto_timeout(n-\u003ecrypto_rx);\n@@ -825,6 +860,7 @@ static void tipc_node_timeout(struct timer_list *t)\n \t */\n \ttipc_node_read_lock(n);\n \tn-\u003ekeepalive_intv = 10000;\n+\tremains = n-\u003elink_cnt;\n \ttipc_node_read_unlock(n);\n \tfor (bearer_id = 0; remains \u0026\u0026 (bearer_id \u003c MAX_BEARERS); bearer_id++) {\n \t\ttipc_node_read_lock(n);\n@@ -835,11 +871,13 @@ static void tipc_node_timeout(struct timer_list *t)\n \t\t\ttipc_node_calculate_timer(n, le-\u003elink);\n \t\t\trc = tipc_link_timeout(le-\u003elink, \u0026xmitq);\n \t\t\tspin_unlock_bh(\u0026le-\u003elock);\n-\t\t\tremains--;\n+\t\t\tif (dist_rc \u003c 0)\n+\t\t\t\tremains--;\n \t\t}\n \t\ttipc_node_read_unlock(n);\n \t\ttipc_bearer_xmit(n-\u003enet, bearer_id, \u0026xmitq, \u0026le-\u003emaddr, n);\n-\t\tif (rc \u0026 TIPC_LINK_DOWN_EVT)\n+\t\t/* Force the node down in case the redistribution failed */\n+\t\tif ((rc \u0026 TIPC_LINK_DOWN_EVT) || dist_rc \u003c 0)\n \t\t\ttipc_node_link_down(n, bearer_id, false);\n \t}\n \tmod_timer(\u0026n-\u003etimer, jiffies + msecs_to_jiffies(n-\u003ekeepalive_intv));\ndiff --git a/net/tipc/node.h b/net/tipc/node.h\nindex 154a5bbb0d29d..0f777cfe7c01e 100644\n--- a/net/tipc/node.h\n+++ b/net/tipc/node.h\n@@ -128,4 +128,5 @@ int tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info);\n int tipc_nl_node_flush_key(struct sk_buff *skb, struct genl_info *info);\n #endif\n void tipc_node_pre_cleanup_net(struct net *exit_net);\n+void tipc_node_set_dist_bulk(struct net *net, u32 addr);\n #endif\ndiff --git a/net/tipc/socket.c b/net/tipc/socket.c\nindex d5d70eb230b56..6b83bdfc439c3 100644\n--- a/net/tipc/socket.c\n+++ b/net/tipc/socket.c\n@@ -2919,7 +2919,7 @@ static int tipc_sk_publish(struct tipc_sock *tsk, struct tipc_uaddr *ua)\n \t\treturn -EADDRINUSE;\n \tskaddr.ref = tsk-\u003eportid;\n \tskaddr.node = tipc_own_addr(net);\n-\tp = tipc_nametbl_publish(net, ua, \u0026skaddr, key);\n+\tp = tipc_nametbl_publish(net, ua, \u0026skaddr, key, NULL);\n \tif (unlikely(!p))\n \t\treturn -EINVAL;\n \n"
} |
| 2/1 | 2026/08/17 07:04 | agent | patch-evaluator |
1mModel:best-expensive Args: null Results: {
"EnableConfigs": [
"TIPC"
],
"FocusSymbols": [
"tipc_named_distribute",
"tipc_nametb_insert_self_node_pub",
"tipc_nametbl_publish",
"tipc_named_node_up"
],
"Reasoning": "The patch modifies the core TIPC logic to handle memory allocation failures during name table distribution. It adds error code returns to functions like `tipc_nametbl_publish` and `tipc_named_node_up`, and introduces `tipc_nametb_insert_self_node_pub` and `tipc_named_distribute` to handle bulk redistribution of cluster-scope publications. These are functional changes to reachable core kernel logic, and 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 ea7c3d4b9b40a93d311459bcbe2bd66bd922d385
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Aug 17 07:03:58 2026 +0000
syz-cluster: applied patch under review
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 315975c3be818..0f1d3ddeae095 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -61,6 +61,9 @@ static int __net_init tipc_init_net(struct net *net)
tn->trial_addr = 0;
tn->addr_trial_end = 0;
tn->capabilities = TIPC_NODE_CAPABILITIES;
+ tn->nt_stop = false;
+ tn->nt_self_node_exist = false;
+ atomic_set(&tn->node_addr_set, 0);
INIT_WORK(&tn->work, tipc_net_finalize_work);
memset(tn->node_id, 0, sizeof(tn->node_id));
memset(tn->node_id_string, 0, sizeof(tn->node_id_string));
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 9ce5f9ff6cc03..975b1d48186e6 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -145,6 +145,12 @@ struct tipc_net {
struct work_struct work;
/* The numbers of work queues in schedule */
atomic_t wq_count;
+ /* Flag to indicate that the node's address is set */
+ atomic_t node_addr_set;
+ /* The name table has stopped working */
+ bool nt_stop;
+ /* Node's self address publication is available in the name table */
+ bool nt_self_node_exist;
};
static inline struct tipc_net *tipc_net(struct net *net)
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index ba4f4906e13b7..83e3ed8f2c512 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -95,9 +95,7 @@ struct sk_buff *tipc_named_publish(struct net *net, struct publication *p)
list_add_tail_rcu(&p->binding_node, &nt->node_scope);
return NULL;
}
- write_lock_bh(&nt->cluster_scope_lock);
list_add_tail(&p->binding_node, &nt->cluster_scope);
- write_unlock_bh(&nt->cluster_scope_lock);
skb = named_prepare_buf(net, PUBLICATION, ITEM_SIZE, 0);
if (!skb) {
pr_warn("Publication distribution failure\n");
@@ -121,9 +119,7 @@ struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *p)
struct distr_item *item;
struct sk_buff *skb;
- write_lock_bh(&nt->cluster_scope_lock);
list_del(&p->binding_node);
- write_unlock_bh(&nt->cluster_scope_lock);
if (p->scope == TIPC_NODE_SCOPE)
return NULL;
@@ -146,9 +142,14 @@ struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *p)
* @dnode: node to be updated
* @pls: linked list of publication items to be packed into buffer chain
* @seqno: sequence number for this message
+ *
+ * Return:
+ * * 0 - Success
+ * * -ENOBUFS - No buffer space is available
+ *
*/
-static void named_distribute(struct net *net, struct sk_buff_head *list,
- u32 dnode, struct list_head *pls, u16 seqno)
+static int named_distribute(struct net *net, struct sk_buff_head *list,
+ u32 dnode, struct list_head *pls, u16 seqno)
{
struct publication *publ;
struct sk_buff *skb = NULL;
@@ -164,8 +165,9 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,
skb = named_prepare_buf(net, PUBLICATION, msg_rem,
dnode);
if (!skb) {
+ __skb_queue_purge(list);
pr_warn("Bulk publication failure\n");
- return;
+ return -ENOBUFS;
}
hdr = buf_msg(skb);
msg_set_bc_ack_invalid(hdr, true);
@@ -195,6 +197,90 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,
hdr = buf_msg(skb_peek_tail(list));
msg_set_last_bulk(hdr);
msg_set_named_seqno(hdr, seqno);
+
+ return 0;
+}
+
+/**
+ * __tipc_named_distribute - build a list of publications need to be distributed
+ * @net: the associated network namespace
+ * @dnode: destination node
+ * @head: list of publications
+ *
+ * Return:
+ * * 0 - Success
+ * * -ENOBUFS - No buffer space is available
+ *
+ */
+static int __tipc_named_distribute(struct net *net, u32 dnode,
+ struct sk_buff_head *head)
+{
+ struct name_table *nt = tipc_name_table(net);
+ struct tipc_net *tn = tipc_net(net);
+
+ /* Name table has been deleted after namespace teardown or
+ * TIPC module exit.
+ */
+ if (unlikely(tn->nt_stop))
+ return 0;
+
+ /* Node's self-address is not set yet */
+ if (!atomic_read(&tn->node_addr_set)) {
+ /* Defer the distribution to node's timer */
+ tipc_node_set_dist_bulk(net, dnode);
+ return 0;
+ }
+
+ /* Previous call to tipc_nametb_insert_self_node_pub() was successful.
+ * The node's self-address publication was added to 'nt->cluster_scope'.
+ * So, 'nt->cluster_scope' is not empty now. Go to distribution.
+ */
+ if (tn->nt_self_node_exist)
+ goto distribute;
+
+ if (tipc_nametb_insert_self_node_pub(net))
+ return -ENOBUFS;
+
+ tn->nt_self_node_exist = true;
+
+distribute:
+ if (named_distribute(net, head, dnode,
+ &nt->cluster_scope, nt->snd_nxt) == -ENOBUFS)
+ return -ENOBUFS;
+
+ return 0;
+}
+
+/**
+ * tipc_named_distribute - distribute all publications to specified node
+ * @net: the associated network namespace
+ * @dnode: destination node
+ *
+ * Return:
+ * * 0 - Success
+ * * -ENOBUFS - No buffer space is available
+ *
+ */
+int tipc_named_distribute(struct net *net, u32 dnode)
+{
+ struct tipc_net *tn = tipc_net(net);
+ struct sk_buff_head head;
+ int rc = 0;
+
+ __skb_queue_head_init(&head);
+ spin_lock_bh(&tn->nametbl_lock);
+ rc = __tipc_named_distribute(net, dnode, &head);
+ spin_unlock_bh(&tn->nametbl_lock);
+ if (!rc && !skb_queue_empty(&head)) {
+ rc = tipc_node_xmit(net, &head, dnode, 0);
+ /* The link is congested after the list is inserted into the
+ * link's send queue. Return 0, as this is normal.
+ */
+ if (rc == -ELINKCONG)
+ rc = 0;
+ }
+
+ return rc;
}
/**
@@ -202,25 +288,36 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,
* @net: the associated network namespace
* @dnode: destination node
* @capabilities: peer node's capabilities
+ *
+ * Return:
+ * * 0 - Success
+ * * -ENOBUFS - No buffer space is available
+ *
*/
-void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)
+int tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)
{
struct name_table *nt = tipc_name_table(net);
struct tipc_net *tn = tipc_net(net);
struct sk_buff_head head;
- u16 seqno;
+ int rc = 0;
__skb_queue_head_init(&head);
spin_lock_bh(&tn->nametbl_lock);
if (!(capabilities & TIPC_NAMED_BCAST))
nt->rc_dests++;
- seqno = nt->snd_nxt;
+
+ rc = __tipc_named_distribute(net, dnode, &head);
spin_unlock_bh(&tn->nametbl_lock);
+ if (!rc && !skb_queue_empty(&head)) {
+ rc = tipc_node_xmit(net, &head, dnode, 0);
+ /* The link is congested after the list is inserted into the
+ * link's send queue. Return 0, as this is normal.
+ */
+ if (rc == -ELINKCONG)
+ rc = 0;
+ }
- read_lock_bh(&nt->cluster_scope_lock);
- named_distribute(net, &head, dnode, &nt->cluster_scope, seqno);
- tipc_node_xmit(net, &head, dnode, 0);
- read_unlock_bh(&nt->cluster_scope_lock);
+ return rc;
}
/**
@@ -299,7 +396,7 @@ static bool tipc_update_nametbl(struct net *net, struct distr_item *i,
sk.node = node;
if (dtype == PUBLICATION) {
- p = tipc_nametbl_insert_publ(net, &ua, &sk, key);
+ p = tipc_nametbl_insert_publ(net, &ua, &sk, key, NULL);
if (p) {
tipc_node_subscribe(net, &p->binding_node, node);
return true;
@@ -416,5 +513,6 @@ void tipc_named_reinit(struct net *net)
list_for_each_entry_rcu(p, &nt->cluster_scope, binding_node)
p->sk.node = self;
nt->rc_dests = 0;
+ tn->nt_stop = false;
spin_unlock_bh(&tn->nametbl_lock);
}
diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h
index c677f6f082dfb..2043096ae967d 100644
--- a/net/tipc/name_distr.h
+++ b/net/tipc/name_distr.h
@@ -69,11 +69,12 @@ struct distr_item {
struct sk_buff *tipc_named_publish(struct net *net, struct publication *publ);
struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ);
-void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities);
+int tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities);
void tipc_named_rcv(struct net *net, struct sk_buff_head *namedq,
u16 *rcv_nxt, bool *open);
void tipc_named_reinit(struct net *net);
void tipc_publ_notify(struct net *net, struct list_head *nsub_list,
u32 addr, u16 capabilities);
+int tipc_named_distribute(struct net *net, u32 dnode);
#endif
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index 253c72d1366eb..beed40a21368a 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -329,7 +329,7 @@ static struct service_range *tipc_service_create_range(struct tipc_service *sc,
static bool tipc_service_insert_publ(struct net *net,
struct tipc_service *sc,
- struct publication *p)
+ struct publication *p, int *err)
{
struct tipc_subscription *sub, *tmp;
struct service_range *sr;
@@ -339,10 +339,12 @@ static bool tipc_service_insert_publ(struct net *net,
bool res = false;
u32 key = p->key;
- spin_lock_bh(&sc->lock);
sr = tipc_service_create_range(sc, p);
- if (!sr)
- goto exit;
+ if (!sr) {
+ if (err)
+ *err = -ENOBUFS;
+ goto exit;
+ }
first = list_empty(&sr->all_publ);
@@ -353,6 +355,8 @@ static bool tipc_service_insert_publ(struct net *net,
pr_debug("Failed to bind duplicate %u,%u,%u/%u:%u/%u\n",
p->sr.type, p->sr.lower, p->sr.upper,
node, p->sk.ref, key);
+ if (err)
+ *err = -EEXIST;
goto exit;
}
}
@@ -371,7 +375,6 @@ static bool tipc_service_insert_publ(struct net *net,
if (!res)
pr_warn("Failed to bind to %u,%u,%u\n",
p->sr.type, p->sr.lower, p->sr.upper);
- spin_unlock_bh(&sc->lock);
return res;
}
@@ -478,20 +481,33 @@ static struct tipc_service *tipc_service_find(struct net *net,
struct publication *tipc_nametbl_insert_publ(struct net *net,
struct tipc_uaddr *ua,
struct tipc_socket_addr *sk,
- u32 key)
+ u32 key, int *err)
{
struct tipc_service *sc;
struct publication *p;
p = tipc_publ_create(ua, sk, key);
- if (!p)
+ if (!p) {
+ if (err)
+ *err = -ENOBUFS;
return NULL;
+ }
sc = tipc_service_find(net, ua);
if (!sc)
sc = tipc_service_create(net, ua);
- if (sc && tipc_service_insert_publ(net, sc, p))
- return p;
+
+ if (sc) {
+ spin_lock_bh(&sc->lock);
+ if (tipc_service_insert_publ(net, sc, p, err)) {
+ spin_unlock_bh(&sc->lock);
+ return p;
+ }
+ spin_unlock_bh(&sc->lock);
+ } else if (err) {
+ *err = -ENOBUFS;
+ }
+
kfree(p);
return NULL;
}
@@ -760,26 +776,55 @@ void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,
/* tipc_nametbl_publish - add service binding to name table
*/
struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,
- struct tipc_socket_addr *sk, u32 key)
+ struct tipc_socket_addr *sk,
+ u32 key, int *err)
{
struct name_table *nt = tipc_name_table(net);
+ u32 max_user_pub = TIPC_MAX_PUBL - 1;
struct tipc_net *tn = tipc_net(net);
struct publication *p = NULL;
struct sk_buff *skb = NULL;
+ bool protocol_type = false;
+ int error = 0;
u32 rc_dests;
+ if (ua->sr.type == TIPC_NODE_STATE || ua->sr.type == TIPC_LINK_STATE ||
+ ua->sr.type == TIPC_TOP_SRV)
+ protocol_type = true;
+
spin_lock_bh(&tn->nametbl_lock);
+ if (protocol_type)
+ goto insert;
- if (nt->local_publ_count >= TIPC_MAX_PUBL) {
- pr_warn("Bind failed, max limit %u reached\n", TIPC_MAX_PUBL);
+ /* Reserve one entry for node state service type because it has cluster
+ * scope and it is distributed in bulk. So, the maximum number of user's
+ * publications is (TIPC_MAX_PUBL - 1).
+ */
+ if (nt->local_publ_count >= max_user_pub) {
+ pr_warn("Bind failed, max limit %u reached\n", max_user_pub);
goto exit;
}
- p = tipc_nametbl_insert_publ(net, ua, sk, key);
+insert:
+ p = tipc_nametbl_insert_publ(net, ua, sk, key, &error);
if (p) {
- nt->local_publ_count++;
+ /* Not count node state, link state and topology server types
+ * so that maximum nt->local_publ_count does not prevent
+ * protocol service types from being inserted into the name
+ * table.
+ */
+ if (!protocol_type)
+ nt->local_publ_count++;
skb = tipc_named_publish(net, p);
+ /* Local-scope publication is not published (skb is NULL), only
+ * cluster-cope one is.
+ */
+ if (!skb && p->scope == TIPC_CLUSTER_SCOPE && err)
+ *err = -ENOBUFS;
+ } else if ((error == -ENOBUFS) && err) {
+ *err = -ENOBUFS;
}
+
rc_dests = nt->rc_dests;
exit:
spin_unlock_bh(&tn->nametbl_lock);
@@ -787,7 +832,102 @@ struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,
if (skb)
tipc_node_broadcast(net, skb, rc_dests);
return p;
+}
+
+/**
+ * tipc_nametb_insert_self_node_pub - insert publication of node's self address
+ * @net: network namespace
+ *
+ * Return:
+ * * 0 - Success
+ * * -ENOBUFS - No buffer space is available
+ *
+ */
+int tipc_nametb_insert_self_node_pub(struct net *net)
+{
+ struct name_table *nt = tipc_name_table(net);
+ struct tipc_net *tn = tipc_net(net);
+ struct tipc_socket_addr sk;
+ struct service_range *sr;
+ struct tipc_service *sc;
+ bool sc_created = false;
+ struct publication *p;
+ struct tipc_uaddr ua;
+ int err = 0;
+
+ sk.ref = 0;
+ sk.node = tn->node_addr;
+ tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,
+ TIPC_NODE_STATE, tn->node_addr, tn->node_addr);
+ sc = tipc_service_find(net, &ua);
+ if (!sc) {
+ sc = tipc_service_create(net, &ua);
+ if (!sc)
+ return -ENOBUFS;
+ sc_created = true;
+ }
+ spin_lock_bh(&sc->lock);
+ /* Check whether a range exists in the name table with
+ * lower == tn->node_addr, upper == tn->node_addr, and type
+ * TIPC_NODE_STATE (0). If 'sr' is not NULL, this range exists
+ * due to a previous call to tipc_nametb_insert_self_node_pub()
+ * or tipc_net_finalize().
+ *
+ * Note that user applications can only insert types greater than
+ * or equal to 64 (TIPC_RESERVED_TYPES), as enforced by tipc_bind().
+ * Remote nodes also only send protocol publications with type
+ * TIPC_NODE_STATE (0), with both lower and upper set to the remote
+ * node's address. These ranges cannot be the same as this node's
+ * range because a remote node's address must differ from this
+ * node's address (tn->node_addr).
+ *
+ * Therefore, tipc_update_nametbl() cannot build and insert a remote
+ * publication with the same type (0) and range
+ * (lower == tn->node_addr, upper == tn->node_addr) as this node's
+ * self-address publication in the name table.
+ *
+ * Because the combination of type 0 and
+ * (lower == tn->node_addr, upper == tn->node_addr) is unique in the
+ * name table, it is not necessary to check sk.node, sk.ref, key, or
+ * cluster_scope membership.
+ */
+ sr = tipc_service_find_range(sc, &ua);
+ /* 1. tipc_net_finalize_work() is not scheduled because of namespace
+ * teardown.
+ * 2. Or tipc_net_finalize() ---> tipc_nametbl_publish() has failed
+ * to insert node self address publication into nt->cluster_scope
+ * due to memory allocation failure.
+ * 3. Or tipc_net_finalize() ---> tipc_nametbl_publish() has not
+ * executed yet.
+ */
+ if (!sr) {
+ p = tipc_publ_create(&ua, &sk, tn->node_addr);
+ if (!p)
+ goto error;
+
+ if (!tipc_service_insert_publ(net, sc, p, &err) &&
+ (err == -ENOBUFS)) {
+ kfree(p);
+ goto error;
+ }
+
+ list_add_tail(&p->binding_node, &nt->cluster_scope);
+ goto exit;
+error:
+ if (sc_created) {
+ hlist_del_init_rcu(&sc->service_list);
+ spin_unlock_bh(&sc->lock);
+ kfree_rcu(sc, rcu);
+ return -ENOBUFS;
+ }
+
+ spin_unlock_bh(&sc->lock);
+ return -ENOBUFS;
+ }
+exit:
+ spin_unlock_bh(&sc->lock);
+ return 0;
}
/**
@@ -810,7 +950,10 @@ void tipc_nametbl_withdraw(struct net *net, struct tipc_uaddr *ua,
p = tipc_nametbl_remove_publ(net, ua, sk, key);
if (p) {
- nt->local_publ_count--;
+ if (p->sr.type != TIPC_NODE_STATE &&
+ p->sr.type != TIPC_LINK_STATE &&
+ p->sr.type != TIPC_TOP_SRV)
+ nt->local_publ_count--;
skb = tipc_named_withdraw(net, p);
list_del_init(&p->binding_sock);
kfree_rcu(p, rcu);
@@ -899,7 +1042,6 @@ int tipc_nametbl_init(struct net *net)
INIT_LIST_HEAD(&nt->node_scope);
INIT_LIST_HEAD(&nt->cluster_scope);
- rwlock_init(&nt->cluster_scope_lock);
tn->nametbl = nt;
spin_lock_init(&tn->nametbl_lock);
return 0;
@@ -912,6 +1054,7 @@ int tipc_nametbl_init(struct net *net)
*/
static void tipc_service_delete(struct net *net, struct tipc_service *sc)
{
+ struct tipc_net *tn = tipc_net(net);
struct service_range *sr, *tmpr;
struct publication *p, *tmp;
@@ -919,6 +1062,15 @@ static void tipc_service_delete(struct net *net, struct tipc_service *sc)
rbtree_postorder_for_each_entry_safe(sr, tmpr, &sc->ranges, tree_node) {
list_for_each_entry_safe(p, tmp, &sr->all_publ, all_publ) {
tipc_service_remove_publ(sr, &p->sk, p->key);
+ /* tipc_nametbl_withdraw() does not delete
+ * 'p->binding_node' with type TIPC_NODE_STATE and
+ * range [tn->node_addr, tn->node_addr] from
+ * 'tn->cluster_scope'. So, delete it here.
+ */
+ if (p->sr.type == TIPC_NODE_STATE &&
+ p->sr.lower == tn->node_addr &&
+ p->sr.upper == tn->node_addr)
+ list_del(&p->binding_node);
kfree_rcu(p, rcu);
}
rb_erase_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks);
@@ -949,6 +1101,8 @@ void tipc_nametbl_stop(struct net *net)
tipc_service_delete(net, service);
}
}
+ tn->nt_stop = true;
+ tn->nt_self_node_exist = false;
spin_unlock_bh(&tn->nametbl_lock);
/* TODO: clear tn->nametbl, implement proper RCU rules ? */
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h
index 7ff6eeebaae64..4390e79a4660e 100644
--- a/net/tipc/name_table.h
+++ b/net/tipc/name_table.h
@@ -97,8 +97,7 @@ struct publication {
* @cluster_scope: all local publications with cluster scope
* - used by name_distr to send bulk updates to new nodes
* - used by name_distr during re-init of name table
- * @cluster_scope_lock: lock for accessing @cluster_scope
- * @local_publ_count: number of publications issued by this node
+ * @local_publ_count: the number of user's publications issued by this node
* @rc_dests: destination node counter
* @snd_nxt: next sequence number to be used
*/
@@ -107,7 +106,6 @@ struct name_table {
struct hlist_head services[TIPC_NAMETBL_SIZE];
struct list_head node_scope;
struct list_head cluster_scope;
- rwlock_t cluster_scope_lock;
u32 local_publ_count;
u32 rc_dests;
u32 snd_nxt;
@@ -126,13 +124,15 @@ bool tipc_nametbl_lookup_group(struct net *net, struct tipc_uaddr *ua,
void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,
struct tipc_uaddr *ua);
struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,
- struct tipc_socket_addr *sk, u32 key);
+ struct tipc_socket_addr *sk,
+ u32 key, int *err);
void tipc_nametbl_withdraw(struct net *net, struct tipc_uaddr *ua,
struct tipc_socket_addr *sk, u32 key);
struct publication *tipc_nametbl_insert_publ(struct net *net,
struct tipc_uaddr *ua,
struct tipc_socket_addr *sk,
- u32 key);
+ u32 key, int *err);
+int tipc_nametb_insert_self_node_pub(struct net *net);
struct publication *tipc_nametbl_remove_publ(struct net *net,
struct tipc_uaddr *ua,
struct tipc_socket_addr *sk,
diff --git a/net/tipc/net.c b/net/tipc/net.c
index 7e65d0b0c4a8d..7a2c1e67aca3d 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -110,11 +110,14 @@ static void tipc_net_finalize(struct net *net, u32 addr);
int tipc_net_init(struct net *net, u8 *node_id, u32 addr)
{
+ struct tipc_net *tn = tipc_net(net);
+
if (tipc_own_id(net)) {
pr_info("Cannot configure node identity twice\n");
return -1;
}
pr_info("Started in network mode\n");
+ atomic_set(&tn->node_addr_set, 0);
if (node_id)
tipc_set_node_id(net, node_id);
@@ -125,8 +128,8 @@ int tipc_net_init(struct net *net, u8 *node_id, u32 addr)
static void tipc_net_finalize(struct net *net, u32 addr)
{
- struct tipc_net *tn = tipc_net(net);
struct tipc_socket_addr sk = {0, addr};
+ struct tipc_net *tn = tipc_net(net);
struct tipc_uaddr ua;
tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,
@@ -138,7 +141,11 @@ static void tipc_net_finalize(struct net *net, u32 addr)
tipc_named_reinit(net);
tipc_sk_reinit(net);
tipc_mon_reinit_self(net);
- tipc_nametbl_publish(net, &ua, &sk, addr);
+ atomic_set(&tn->node_addr_set, 1);
+ /* Redistribute bulk of publications via node-up event or node's timer
+ * if tipc_nametbl_publish() fails.
+ */
+ tipc_nametbl_publish(net, &ua, &sk, addr, NULL);
}
void tipc_net_finalize_work(struct work_struct *work)
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 683a136e53efc..f1eee674a678e 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -111,6 +111,7 @@ struct tipc_bclink_entry {
* @peer_net: peer's net namespace
* @peer_hash_mix: hash for this peer (FIXME)
* @crypto_rx: RX crypto handler
+ * @dist_bulk: flag to redistribute cluster-scope publications
*/
struct tipc_node {
u32 addr;
@@ -145,6 +146,7 @@ struct tipc_node {
#ifdef CONFIG_TIPC_CRYPTO
struct tipc_crypto *crypto_rx;
#endif
+ atomic_t dist_bulk;
};
/* Node FSM states and events:
@@ -345,6 +347,17 @@ static struct tipc_node *tipc_node_find(struct net *net, u32 addr)
return node;
}
+void tipc_node_set_dist_bulk(struct net *net, u32 addr)
+{
+ struct tipc_node *node;
+
+ node = tipc_node_find(net, addr);
+ if (node) {
+ atomic_set(&node->dist_bulk, 1);
+ tipc_node_put(node);
+ }
+}
+
/* tipc_node_find_by_id - locate specified node object by its 128-bit id
* Note: this function is called only when a discovery request failed
* to find the node by its 32-bit id, and is not time critical
@@ -393,6 +406,14 @@ static void tipc_node_write_unlock_fast(struct tipc_node *n)
write_unlock_bh(&n->lock);
}
+static void tipc_node_down(struct tipc_node *n)
+{
+ int bearer_id;
+
+ for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++)
+ tipc_node_link_down(n, bearer_id, false);
+}
+
static void tipc_node_write_unlock(struct tipc_node *n)
__releases(n->lock)
{
@@ -402,6 +423,7 @@ static void tipc_node_write_unlock(struct tipc_node *n)
struct list_head *publ_list;
struct tipc_uaddr ua;
u32 bearer_id, node;
+ int rc = 0, err = 0;
if (likely(!flags)) {
write_unlock_bh(&n->lock);
@@ -425,16 +447,24 @@ static void tipc_node_write_unlock(struct tipc_node *n)
tipc_publ_notify(net, publ_list, node, n->capabilities);
if (flags & TIPC_NOTIFY_NODE_UP)
- tipc_named_node_up(net, node, n->capabilities);
+ rc = tipc_named_node_up(net, node, n->capabilities);
if (flags & TIPC_NOTIFY_LINK_UP) {
tipc_mon_peer_up(net, node, bearer_id);
- tipc_nametbl_publish(net, &ua, &sk, sk.ref);
+ tipc_nametbl_publish(net, &ua, &sk, sk.ref, &err);
}
if (flags & TIPC_NOTIFY_LINK_DOWN) {
tipc_mon_peer_down(net, node, bearer_id);
tipc_nametbl_withdraw(net, &ua, &sk, sk.ref);
}
+
+ /* Memory allocation has failed. Bring the node down to start over bulk
+ * distribution when the first link is up again.
+ */
+ if (rc < 0)
+ tipc_node_down(n);
+ else if (err == -ENOBUFS)
+ tipc_node_link_down(n, bearer_id, false);
}
static void tipc_node_assign_peer_net(struct tipc_node *n, u32 hash_mixes)
@@ -564,6 +594,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u8 *peer_id,
INIT_LIST_HEAD(&n->list);
INIT_LIST_HEAD(&n->publ_list);
INIT_LIST_HEAD(&n->conn_sks);
+ atomic_set(&n->dist_bulk, 0);
skb_queue_head_init(&n->bc_entry.namedq);
skb_queue_head_init(&n->bc_entry.inputq1);
__skb_queue_head_init(&n->bc_entry.arrvq);
@@ -803,7 +834,8 @@ static void tipc_node_timeout(struct timer_list *t)
struct tipc_node *n = timer_container_of(n, t, timer);
struct tipc_link_entry *le;
struct sk_buff_head xmitq;
- int remains = n->link_cnt;
+ int remains = 0;
+ int dist_rc = 0;
int bearer_id;
int rc = 0;
@@ -814,6 +846,9 @@ static void tipc_node_timeout(struct timer_list *t)
return;
}
+ if (atomic_xchg(&n->dist_bulk, 0))
+ dist_rc = tipc_named_distribute(n->net, n->addr);
+
#ifdef CONFIG_TIPC_CRYPTO
/* Take any crypto key related actions first */
tipc_crypto_timeout(n->crypto_rx);
@@ -825,6 +860,7 @@ static void tipc_node_timeout(struct timer_list *t)
*/
tipc_node_read_lock(n);
n->keepalive_intv = 10000;
+ remains = n->link_cnt;
tipc_node_read_unlock(n);
for (bearer_id = 0; remains && (bearer_id < MAX_BEARERS); bearer_id++) {
tipc_node_read_lock(n);
@@ -835,11 +871,13 @@ static void tipc_node_timeout(struct timer_list *t)
tipc_node_calculate_timer(n, le->link);
rc = tipc_link_timeout(le->link, &xmitq);
spin_unlock_bh(&le->lock);
- remains--;
+ if (dist_rc < 0)
+ remains--;
}
tipc_node_read_unlock(n);
tipc_bearer_xmit(n->net, bearer_id, &xmitq, &le->maddr, n);
- if (rc & TIPC_LINK_DOWN_EVT)
+ /* Force the node down in case the redistribution failed */
+ if ((rc & TIPC_LINK_DOWN_EVT) || dist_rc < 0)
tipc_node_link_down(n, bearer_id, false);
}
mod_timer(&n->timer, jiffies + msecs_to_jiffies(n->keepalive_intv));
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 154a5bbb0d29d..0f777cfe7c01e 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -128,4 +128,5 @@ int tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_node_flush_key(struct sk_buff *skb, struct genl_info *info);
#endif
void tipc_node_pre_cleanup_net(struct net *exit_net);
+void tipc_node_set_dist_bulk(struct net *net, u32 addr);
#endif
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index d5d70eb230b56..6b83bdfc439c3 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -2919,7 +2919,7 @@ static int tipc_sk_publish(struct tipc_sock *tsk, struct tipc_uaddr *ua)
return -EADDRINUSE;
skaddr.ref = tsk->portid;
skaddr.node = tipc_own_addr(net);
- p = tipc_nametbl_publish(net, ua, &skaddr, key);
+ p = tipc_nametbl_publish(net, ua, &skaddr, key, NULL);
if (unlikely(!p))
return -EINVAL;
|
| 3/2 | 2026/08/17 07:04 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 12741 output: 21 thoughts: 481 Thoughts: **Analyzing a TIPC Patch for Fuzzing Opportunities** Okay, so I'm looking at this patch for the TIPC subsystem in the Linux kernel. Seems like a non-trivial change, touching a good chunk of the core code: `net/tipc/core.c`, `.h`, `name_distr.c`, `.h`, `name_table.c`, `.h`, `net.c`, `node.c`, `.h`, and `socket.c`. Based on the file modifications, this patch focuses on improving name table distribution and addressing memory allocation issues that crop up during publication. From my understanding, the patch introduces some new fields to the `struct tipc_net` structure, specifically `nt_stop`, `nt_self_node_exist`, and `node_addr_set`, and it looks like a concerted effort to improve error handling throughout the name table distribution code. I see changes where functions that previously just silently failed are now returning error codes – `-ENOBUFS` in the case of `named_distribute`, for instance. There's some refactoring, with functions like `__tipc_named_distribute` and `tipc_named_distribute` being added, and changes to `tipc_named_node_up` and `tipc_nametbl_insert_publ` now explicitly returning errors. There are changes for bulk redistribution in `tipc_node_timeout`, as well as a new function `tipc_nametb_insert_self_node_pub`. This is a fundamental change to how TIPC operates, which is interesting because I know TIPC can be used in virtualized environments. Given these functional changes and the potential for memory allocation problems, I think this patch is definitely worth fuzzing. I'll flag it as `WorthFuzzing=true`. Now, the important part: identifying the key functions to target. Based on the changes, the obvious candidates for fuzzing are: * `tipc_named_distribute` * `tipc_named_node_up` * `tipc_nametbl_publish` * `tipc_nametb_insert_self_node_pub` * `tipc_node_timeout` * `tipc_sk_publish` Those seem like the main entry points where we could trigger these distribution/allocation issues. I'll double-check the Kconfig options; obviously, `CONFIG_TIPC` needs to be enabled for this code to even be compiled. Finally, I'll need to go back and verify the details of how the patch changes those functions, to inform the fuzzing strategy. |
| 4/2 | 2026/08/17 07:04 | tool | grepper |
0mArgs:{
"Expression": "tipc_named_distribute"
}Results: {
"Output": "net/tipc/name_distr.c=151=static int named_distribute(struct net *net, struct sk_buff_head *list,\n--\nnet/tipc/name_distr.c-204-/**\nnet/tipc/name_distr.c:205: * __tipc_named_distribute - build a list of publications need to be distributed\nnet/tipc/name_distr.c-206- * @net: the associated network namespace\n--\nnet/tipc/name_distr.c-214- */\nnet/tipc/name_distr.c:215:static int __tipc_named_distribute(struct net *net, u32 dnode,\nnet/tipc/name_distr.c-216-\t\t\t\t struct sk_buff_head *head)\n--\nnet/tipc/name_distr.c-254-/**\nnet/tipc/name_distr.c:255: * tipc_named_distribute - distribute all publications to specified node\nnet/tipc/name_distr.c-256- * @net: the associated network namespace\n--\nnet/tipc/name_distr.c-263- */\nnet/tipc/name_distr.c:264:int tipc_named_distribute(struct net *net, u32 dnode)\nnet/tipc/name_distr.c-265-{\n--\nnet/tipc/name_distr.c-271-\tspin_lock_bh(\u0026tn-\u003enametbl_lock);\nnet/tipc/name_distr.c:272:\trc = __tipc_named_distribute(net, dnode, \u0026head);\nnet/tipc/name_distr.c-273-\tspin_unlock_bh(\u0026tn-\u003enametbl_lock);\n--\nnet/tipc/name_distr.c=297=int tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)\n--\nnet/tipc/name_distr.c-308-\nnet/tipc/name_distr.c:309:\trc = __tipc_named_distribute(net, dnode, \u0026head);\nnet/tipc/name_distr.c-310-\tspin_unlock_bh(\u0026tn-\u003enametbl_lock);\n--\nnet/tipc/name_distr.h=76=void tipc_publ_notify(struct net *net, struct list_head *nsub_list,\nnet/tipc/name_distr.h-77-\t\t u32 addr, u16 capabilities);\nnet/tipc/name_distr.h:78:int tipc_named_distribute(struct net *net, u32 dnode);\nnet/tipc/name_distr.h-79-\n--\nnet/tipc/node.c=832=static void tipc_node_timeout(struct timer_list *t)\n--\nnet/tipc/node.c-849-\tif (atomic_xchg(\u0026n-\u003edist_bulk, 0))\nnet/tipc/node.c:850:\t\tdist_rc = tipc_named_distribute(n-\u003enet, n-\u003eaddr);\nnet/tipc/node.c-851-\n"
} |
| 5/2 | 2026/08/17 07:04 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14660 output: 28 thoughts: 20 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience and written in the first person: **Analyzing `tipc_nametb_insert_self_node_pub`** Okay, let's dive into this `tipc_nametb_insert_self_node_pub` function. My initial thought process involves a few key questions. First, what's its intended role within the TIPC (Transparent Inter-Process Communication) framework? From the name, I'm inferring it's related to inserting, likely a self-node or its public representation, into a name table. This suggests it’s a fundamental operation for publishing node information, probably for discovery and communication. Next, I'll be looking for where this function is called and where it's called from, to understand the broader context. Is it called during node initialization, registration, or perhaps dynamically when a node's capabilities change? Knowing the calling sequence is critical to grasping its significance within the overall TIPC architecture. I'll need to trace the execution path to confirm that understanding. Function internals are also crucial, of course. I'll pay close attention to the data structures involved: the name table itself, the format of the self-node representation being inserted, and any synchronization mechanisms used to ensure thread safety. Considering it's a "public" insertion, I'm expecting some level of visibility control or security considerations to be at play. How is the insertion process protected from race conditions or corruption? What locking mechanisms are employed? Are there any potential deadlocks I need to keep in mind? Furthermore, I'll be considering the error handling and potential failure modes. What happens if the name table is full, or if the provided node information is invalid? How are these scenarios handled, and what are the implications for the overall system's stability and reliability? Are there any error codes or logging messages of interest? Finally, if the underlying implementation is in a language like C, I'll pay close attention to memory management within this function. Are there any memory leaks, buffer overflows, or other vulnerabilities I should be aware of? I'll be looking for use of `kmalloc`, `kfree`, `memcpy`, and similar functions. Ultimately, I need to form a solid understanding of this function's purpose, implementation, and potential impact on the overall TIPC system. Only then can I determine if it is behaving as expected and identify any possible areas of concern. |
| 6/2 | 2026/08/17 07:04 | tool | grepper |
0mArgs:{
"Expression": "tipc_nametb_insert_self_node_pub"
}Results: {
"Output": "net/tipc/name_distr.c=215=static int __tipc_named_distribute(struct net *net, u32 dnode,\n--\nnet/tipc/name_distr.c-233-\nnet/tipc/name_distr.c:234:\t/* Previous call to tipc_nametb_insert_self_node_pub() was successful.\nnet/tipc/name_distr.c-235-\t * The node's self-address publication was added to 'nt-\u003ecluster_scope'.\n--\nnet/tipc/name_distr.c-240-\nnet/tipc/name_distr.c:241:\tif (tipc_nametb_insert_self_node_pub(net))\nnet/tipc/name_distr.c-242-\t\treturn -ENOBUFS;\n--\nnet/tipc/name_table.c=778=struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,\n--\nnet/tipc/name_table.c-837-/**\nnet/tipc/name_table.c:838: * tipc_nametb_insert_self_node_pub - insert publication of node's self address\nnet/tipc/name_table.c-839- * @net: network namespace\n--\nnet/tipc/name_table.c-845- */\nnet/tipc/name_table.c:846:int tipc_nametb_insert_self_node_pub(struct net *net)\nnet/tipc/name_table.c-847-{\n--\nnet/tipc/name_table.c-873-\t * TIPC_NODE_STATE (0). If 'sr' is not NULL, this range exists\nnet/tipc/name_table.c:874:\t * due to a previous call to tipc_nametb_insert_self_node_pub()\nnet/tipc/name_table.c-875-\t * or tipc_net_finalize().\n--\nnet/tipc/name_table.h=131=struct publication *tipc_nametbl_insert_publ(struct net *net,\n--\nnet/tipc/name_table.h-134-\t\t\t\t\t u32 key, int *err);\nnet/tipc/name_table.h:135:int tipc_nametb_insert_self_node_pub(struct net *net);\nnet/tipc/name_table.h-136-struct publication *tipc_nametbl_remove_publ(struct net *net,\n"
} |
| 7/2 | 2026/08/17 07:04 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15896 output: 22 thoughts: 14 Thoughts: Here's my take on those thoughts, from my perspective: **Debugging the `tipc_nametbl_publish` Function** Alright, time to dig into `tipc_nametbl_publish`. This function is critical, and I need to make sure it's behaving as expected. Let's see what's happening under the hood. I suspect there might be a subtle issue here that I need to pinpoint. Understanding the exact state of this function will be key to understanding the full system. |
| 8/2 | 2026/08/17 07:04 | tool | grepper |
0mArgs:{
"Expression": "tipc_nametbl_publish"
}Results: {
"Output": "net/tipc/name_table.c=748=void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,\n--\nnet/tipc/name_table.c-775-\nnet/tipc/name_table.c:776:/* tipc_nametbl_publish - add service binding to name table\nnet/tipc/name_table.c-777- */\nnet/tipc/name_table.c:778:struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,\nnet/tipc/name_table.c-779-\t\t\t\t\t struct tipc_socket_addr *sk,\n--\nnet/tipc/name_table.c=846=int tipc_nametb_insert_self_node_pub(struct net *net)\n--\nnet/tipc/name_table.c-897-\t * teardown.\nnet/tipc/name_table.c:898:\t * 2. Or tipc_net_finalize() ---\u003e tipc_nametbl_publish() has failed\nnet/tipc/name_table.c-899-\t * to insert node self address publication into nt-\u003ecluster_scope\nnet/tipc/name_table.c-900-\t * due to memory allocation failure.\nnet/tipc/name_table.c:901:\t * 3. Or tipc_net_finalize() ---\u003e tipc_nametbl_publish() has not\nnet/tipc/name_table.c-902-\t * executed yet.\n--\nnet/tipc/name_table.h=124=void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,\nnet/tipc/name_table.h-125-\t\t\t struct tipc_uaddr *ua);\nnet/tipc/name_table.h:126:struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,\nnet/tipc/name_table.h-127-\t\t\t\t\t struct tipc_socket_addr *sk,\n--\nnet/tipc/net.c=129=static void tipc_net_finalize(struct net *net, u32 addr)\n--\nnet/tipc/net.c-145-\t/* Redistribute bulk of publications via node-up event or node's timer\nnet/tipc/net.c:146:\t * if tipc_nametbl_publish() fails.\nnet/tipc/net.c-147-\t */\nnet/tipc/net.c:148:\ttipc_nametbl_publish(net, \u0026ua, \u0026sk, addr, NULL);\nnet/tipc/net.c-149-}\n--\nnet/tipc/node.c=417=static void tipc_node_write_unlock(struct tipc_node *n)\n--\nnet/tipc/node.c-453-\t\ttipc_mon_peer_up(net, node, bearer_id);\nnet/tipc/node.c:454:\t\ttipc_nametbl_publish(net, \u0026ua, \u0026sk, sk.ref, \u0026err);\nnet/tipc/node.c-455-\t}\n--\nnet/tipc/socket.c=2907=static int tipc_sk_publish(struct tipc_sock *tsk, struct tipc_uaddr *ua)\n--\nnet/tipc/socket.c-2921-\tskaddr.node = tipc_own_addr(net);\nnet/tipc/socket.c:2922:\tp = tipc_nametbl_publish(net, ua, \u0026skaddr, key, NULL);\nnet/tipc/socket.c-2923-\tif (unlikely(!p))\n"
} |
| 9/2 | 2026/08/17 07:04 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 17015 output: 22 thoughts: 14 Thoughts: Here's a summary of my thought process, as requested: **Checking `tipc_named_node_up`** Okay, let's dive into this. The task seems straightforward enough, but experience tells me it's always wise to be methodical, especially when dealing with something like `tipc_named_node_up`. I'm immediately thinking, "What context is this function being used in?" Is it part of the core TIPC implementation, or is it higher-level abstraction layered on top? Knowing that influences my expectations for things like error handling and the kinds of data structures it's interacting with. I'm assuming, based on the name, that it likely deals with bringing up a named node within the TIPC network. That implies some kind of registration or announcement to the network, and the potential need for some form of synchronization or locking to prevent race conditions during node startup or registration. I will be looking out for any potential race conditions and checking for adequate thread safety. I need to understand how the function handles errors. Does it return specific error codes, or does it rely on exceptions? How are these errors propagated up the call stack? This is crucial for debugging and robust system design. Also, what other functions does this function interact with? Are there any upstream dependencies that might impact its behavior or success? It’s also imperative to keep in mind, I need to check the function signature, to see what input it takes and what it returns. This will give me all the information I need, to understand the function. Finally, the documentation (if any) is a good place to start, I will also want to trace its usage in various code to determine how it is utilized. |
| 10/2 | 2026/08/17 07:04 | tool | grepper |
0mArgs:{
"Expression": "tipc_named_node_up"
}Results: {
"Output": "net/tipc/name_distr.c=264=int tipc_named_distribute(struct net *net, u32 dnode)\n--\nnet/tipc/name_distr.c-286-/**\nnet/tipc/name_distr.c:287: * tipc_named_node_up - tell specified node about all publications by this node\nnet/tipc/name_distr.c-288- * @net: the associated network namespace\n--\nnet/tipc/name_distr.c-296- */\nnet/tipc/name_distr.c:297:int tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)\nnet/tipc/name_distr.c-298-{\n--\nnet/tipc/name_distr.h=71=struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ);\nnet/tipc/name_distr.h:72:int tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities);\nnet/tipc/name_distr.h-73-void tipc_named_rcv(struct net *net, struct sk_buff_head *namedq,\n--\nnet/tipc/node.c=417=static void tipc_node_write_unlock(struct tipc_node *n)\n--\nnet/tipc/node.c-449-\tif (flags \u0026 TIPC_NOTIFY_NODE_UP)\nnet/tipc/node.c:450:\t\trc = tipc_named_node_up(net, node, n-\u003ecapabilities);\nnet/tipc/node.c-451-\n"
} |
| 11/2 | 2026/08/17 07:04 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 17851 output: 17 thoughts: 105 Thoughts: **Fuzzing Candidate Identification within TIPC Core** Okay, so this patch is digging into the heart of TIPC, specifically how it handles name table distribution and deals with those pesky memory allocation failures. That immediately flags a few key functions as ripe for fuzzing: `tipc_named_distribute`, `tipc_nametb_insert_self_node_pub`, `tipc_nametbl_publish`, and `tipc_named_node_up`. Those are the core distribution and publishing mechanisms, so they're naturally going to be potential weak points. And, given that `tipc_sk_publish` calls into `tipc_nametbl_publish`, that likely makes it a good fuzz target as well. I'll need to check the `Kconfig` for TIPC support to make sure it's enabled and what options are configured to properly craft a fuzzing campaign that covers the relevant configurations. |
| 12/2 | 2026/08/17 07:04 | tool | grepper |
0mArgs:{
"Expression": "config TIPC"
}Results: {
"Output": "net/tipc/Kconfig-5-\nnet/tipc/Kconfig:6:menuconfig TIPC\nnet/tipc/Kconfig-7-\ttristate \"The TIPC Protocol\"\n--\nnet/tipc/Kconfig-23-\nnet/tipc/Kconfig:24:config TIPC_MEDIA_IB\nnet/tipc/Kconfig-25-\tbool \"InfiniBand media type support\"\n--\nnet/tipc/Kconfig-29-\t IP-over-InfiniBand devices.\nnet/tipc/Kconfig:30:config TIPC_MEDIA_UDP\nnet/tipc/Kconfig-31-\tbool \"IP/UDP media type support\"\n--\nnet/tipc/Kconfig-37-\nnet/tipc/Kconfig:38:config TIPC_CRYPTO\nnet/tipc/Kconfig-39-\tbool \"TIPC encryption support\"\n--\nnet/tipc/Kconfig-52-\nnet/tipc/Kconfig:53:config TIPC_DIAG\nnet/tipc/Kconfig-54-\ttristate \"TIPC: socket monitoring interface\"\n"
} |
| 13/2 | 2026/08/17 07:04 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 18459 output: 33 thoughts: 23 Thoughts: Here's my summary, as though I'm thinking through this process: **Tackling the TIPC Configuration** Okay, so the task at hand is `TIPC`. Right, let's get down to brass tacks. My initial thought is to immediately dive into the dependencies. Before I even *think* about configuring TIPC, I need to know what it relies on. Gotta make sure everything's in place before I even start. I'll need to run a quick check for dependencies, ensuring all necessary components are installed and operational. Skipping this step would be a rookie mistake; I need to make sure I don't run into any unnecessary roadblocks down the line. It's the standard procedure. Dependencies first. Always. |
| 14/2 | 2026/08/17 07:04 | tool | read-file |
0mArgs:{
"File": "net/tipc/Kconfig",
"FirstLine": 1,
"LineCount": 20
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\t#\n 3:\t# TIPC configuration\n 4:\t#\n 5:\t\n 6:\tmenuconfig TIPC\n 7:\t\ttristate \"The TIPC Protocol\"\n 8:\t\tdepends on INET\n 9:\t\thelp\n 10:\t\t The Transparent Inter Process Communication (TIPC) protocol is\n 11:\t\t specially designed for intra cluster communication. This protocol\n 12:\t\t originates from Ericsson where it has been used in carrier grade\n 13:\t\t cluster applications for many years.\n 14:\t\n 15:\t\t For more information about TIPC, see http://tipc.sourceforge.net.\n 16:\t\n 17:\t\t This protocol support is also available as a module ( = code which\n 18:\t\t can be inserted in and removed from the running kernel whenever you\n 19:\t\t want). The module will be called tipc. If you want to compile it\n 20:\t\t as a module, say M here and read \u003cfile:Documentation/kbuild/modules.rst\u003e.\n"
} |
| 15/2 | 2026/08/17 07:04 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 18959 output: 20 thoughts: 102 Thoughts: **My Analysis of TIPC Configuration** Okay, so I'm dealing with configuring TIPC, and it's clear that it has a dependency on INET. That's straightforward, and I'll make sure to include `TIPC` within `EnableConfigs` to account for that. Now, I need to zoom in on specific symbols within the TIPC system. I've got my focus narrowed down to these: `tipc_named_distribute`, `tipc_nametb_insert_self_node_pub`, `tipc_nametbl_publish`, `tipc_named_node_up`, and `tipc_sk_publish`. These are critical for understanding how TIPC handles name distribution and socket publishing – core functionalities. Before I go any further, I should verify if `tipc_sk_publish` is declared as static. This will influence how its scope is determined. Let's start there. |
| 16/2 | 2026/08/17 07:04 | tool | grepper |
0mArgs:{
"Expression": "tipc_sk_publish"
}Results: {
"Output": "net/tipc/socket.c=150=static void tipc_sk_timeout(struct timer_list *t);\nnet/tipc/socket.c:151:static int tipc_sk_publish(struct tipc_sock *tsk, struct tipc_uaddr *ua);\nnet/tipc/socket.c-152-static int tipc_sk_withdraw(struct tipc_sock *tsk, struct tipc_uaddr *ua);\n--\nnet/tipc/socket.c=676=static int __tipc_bind(struct socket *sock, struct sockaddr *skaddr, int alen)\n--\nnet/tipc/socket.c-701-\t\treturn tipc_sk_withdraw(tsk, ua);\nnet/tipc/socket.c:702:\treturn tipc_sk_publish(tsk, ua);\nnet/tipc/socket.c-703-}\n--\nnet/tipc/socket.c=2870=static void tipc_sk_timeout(struct timer_list *t)\n--\nnet/tipc/socket.c-2906-\nnet/tipc/socket.c:2907:static int tipc_sk_publish(struct tipc_sock *tsk, struct tipc_uaddr *ua)\nnet/tipc/socket.c-2908-{\n--\nnet/tipc/socket.c=3072=static int tipc_sk_join(struct tipc_sock *tsk, struct tipc_group_req *mreq)\n--\nnet/tipc/socket.c-3097-\ttipc_nametbl_build_group(net, grp, \u0026ua);\nnet/tipc/socket.c:3098:\trc = tipc_sk_publish(tsk, \u0026ua);\nnet/tipc/socket.c-3099-\tif (rc) {\n"
} |
| 17/2 | 2026/08/17 07:04 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 19752 output: 18 thoughts: 46 Thoughts: Okay, here's my interpretation of those thoughts, summarized from my perspective as someone familiar with kernel internals and networking: **Focusing on the Right Symbol for the Job** Alright, I'm thinking about how to effectively identify the entry point for some TIPC (Transparent Inter-Process Communication) functionality. I see `tipc_sk_publish` and realize immediately that it's a static function. That means it's limited in scope, likely internal to a specific module or file. Therefore, it's not a useful symbol to zero in on if I'm trying to find the primary interface. `__tipc_bind` is also static, so I can toss that one aside too. Now, *`tipc_bind`*... ah, *that's* the likely candidate! It's the non-static one, the public-facing entry point I'm looking for. That's probably the function that's exposed and callable from other parts of the kernel or even from userspace, which is where I'd focus my attention. It's the key symbol I'll want to trace or analyze further. |
| 18/2 | 2026/08/17 07:05 | tool | grepper |
0mArgs:{
"Expression": "tipc_bind"
}Results: {
"Output": "net/tipc/name_table.c=846=int tipc_nametb_insert_self_node_pub(struct net *net)\n--\nnet/tipc/name_table.c-877-\t * Note that user applications can only insert types greater than\nnet/tipc/name_table.c:878:\t * or equal to 64 (TIPC_RESERVED_TYPES), as enforced by tipc_bind().\nnet/tipc/name_table.c-879-\t * Remote nodes also only send protocol publications with type\n--\nnet/tipc/socket.c=626=static int tipc_release(struct socket *sock)\n--\nnet/tipc/socket.c-661-/**\nnet/tipc/socket.c:662: * __tipc_bind - associate or disassociate TIPC name(s) with a socket\nnet/tipc/socket.c-663- * @sock: socket structure\n--\nnet/tipc/socket.c-675- */\nnet/tipc/socket.c:676:static int __tipc_bind(struct socket *sock, struct sockaddr *skaddr, int alen)\nnet/tipc/socket.c-677-{\n--\nnet/tipc/socket.c=705=int tipc_sk_bind(struct socket *sock, struct sockaddr *skaddr, int alen)\n--\nnet/tipc/socket.c-709-\tlock_sock(sock-\u003esk);\nnet/tipc/socket.c:710:\tres = __tipc_bind(sock, skaddr, alen);\nnet/tipc/socket.c-711-\trelease_sock(sock-\u003esk);\n--\nnet/tipc/socket.c-714-\nnet/tipc/socket.c:715:static int tipc_bind(struct socket *sock, struct sockaddr_unsized *skaddr, int alen)\nnet/tipc/socket.c-716-{\n--\nnet/tipc/socket.c=3359=static const struct proto_ops msg_ops = {\n--\nnet/tipc/socket.c-3362-\t.release\t= tipc_release,\nnet/tipc/socket.c:3363:\t.bind\t\t= tipc_bind,\nnet/tipc/socket.c-3364-\t.connect\t= tipc_connect,\n--\nnet/tipc/socket.c=3379=static const struct proto_ops packet_ops = {\n--\nnet/tipc/socket.c-3382-\t.release\t= tipc_release,\nnet/tipc/socket.c:3383:\t.bind\t\t= tipc_bind,\nnet/tipc/socket.c-3384-\t.connect\t= tipc_connect,\n--\nnet/tipc/socket.c=3399=static const struct proto_ops stream_ops = {\n--\nnet/tipc/socket.c-3402-\t.release\t= tipc_release,\nnet/tipc/socket.c:3403:\t.bind\t\t= tipc_bind,\nnet/tipc/socket.c-3404-\t.connect\t= tipc_connect,\n"
} |
| 19/2 | 2026/08/17 07:05 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 20870 output: 21 thoughts: 53 Thoughts: Here's my summary, as the expert: **Investigating TIPC Binding and Distribution Functions** Okay, so I'm looking at these TIPC functions. I noticed `tipc_bind` is declared as static, which is a bit unusual for an operation function. I'll need to remember that design decision for later analysis. Next, I should investigate `tipc_sk_bind`, which I *believe* is non-static. Let's confirm that. Finally, I'll need to examine `tipc_named_distribute` to see what is going on there. |
| 20/2 | 2026/08/17 07:05 | tool | grepper |
0mArgs:{
"Expression": "tipc_named_distribute"
}Results: {
"Output": "net/tipc/name_distr.c=151=static int named_distribute(struct net *net, struct sk_buff_head *list,\n--\nnet/tipc/name_distr.c-204-/**\nnet/tipc/name_distr.c:205: * __tipc_named_distribute - build a list of publications need to be distributed\nnet/tipc/name_distr.c-206- * @net: the associated network namespace\n--\nnet/tipc/name_distr.c-214- */\nnet/tipc/name_distr.c:215:static int __tipc_named_distribute(struct net *net, u32 dnode,\nnet/tipc/name_distr.c-216-\t\t\t\t struct sk_buff_head *head)\n--\nnet/tipc/name_distr.c-254-/**\nnet/tipc/name_distr.c:255: * tipc_named_distribute - distribute all publications to specified node\nnet/tipc/name_distr.c-256- * @net: the associated network namespace\n--\nnet/tipc/name_distr.c-263- */\nnet/tipc/name_distr.c:264:int tipc_named_distribute(struct net *net, u32 dnode)\nnet/tipc/name_distr.c-265-{\n--\nnet/tipc/name_distr.c-271-\tspin_lock_bh(\u0026tn-\u003enametbl_lock);\nnet/tipc/name_distr.c:272:\trc = __tipc_named_distribute(net, dnode, \u0026head);\nnet/tipc/name_distr.c-273-\tspin_unlock_bh(\u0026tn-\u003enametbl_lock);\n--\nnet/tipc/name_distr.c=297=int tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)\n--\nnet/tipc/name_distr.c-308-\nnet/tipc/name_distr.c:309:\trc = __tipc_named_distribute(net, dnode, \u0026head);\nnet/tipc/name_distr.c-310-\tspin_unlock_bh(\u0026tn-\u003enametbl_lock);\n--\nnet/tipc/name_distr.h=76=void tipc_publ_notify(struct net *net, struct list_head *nsub_list,\nnet/tipc/name_distr.h-77-\t\t u32 addr, u16 capabilities);\nnet/tipc/name_distr.h:78:int tipc_named_distribute(struct net *net, u32 dnode);\nnet/tipc/name_distr.h-79-\n--\nnet/tipc/node.c=832=static void tipc_node_timeout(struct timer_list *t)\n--\nnet/tipc/node.c-849-\tif (atomic_xchg(\u0026n-\u003edist_bulk, 0))\nnet/tipc/node.c:850:\t\tdist_rc = tipc_named_distribute(n-\u003enet, n-\u003eaddr);\nnet/tipc/node.c-851-\n"
} |
| 21/2 | 2026/08/17 07:05 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 21912 output: 185 thoughts: 238 Thoughts: **My Assessment of the TIPC Code Changes** Okay, so I'm looking at these function declarations, and the first thing that jumps out is that `tipc_named_distribute`, `tipc_nametb_insert_self_node_pub`, `tipc_nametbl_publish`, and `tipc_named_node_up` are *not* static. This immediately flags them as potential points of interaction and entry points for various operations within the TIPC system. These are definitely the functions I need to focus on. So my initial thought is, focus on these symbols: `tipc_named_distribute`, `tipc_nametb_insert_self_node_pub`, `tipc_nametbl_publish`, and `tipc_named_node_up`. The "EnableConfigs: TIPC" is a given, so I'm already looking at TIPC-related functionality. The description confirms what I suspected. The patch's core modification centers around handling memory allocation failures during name table distribution within the TIPC system. It looks like they've added error code returns to crucial functions like `tipc_nametbl_publish` and `tipc_named_node_up`, which strongly suggests that the previous code path did not reliably handle failures. New functions, namely `tipc_nametb_insert_self_node_pub` and `tipc_named_distribute`, have been introduced to deal with bulk redistribution of cluster-scope publications. Considering this is a modification to fundamental kernel logic within TIPC that’s also reachable, it's absolutely ripe for fuzzing. These changes are designed to improve robustness and resilience in the face of memory pressure, and that's exactly the kind of scenario fuzzing is designed to uncover. I'll need to develop fuzzing strategies that specifically target these new error paths and allocation scenarios. |
| 22/2 | 2026/08/17 07:05 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"TIPC"
],
"FocusSymbols": [
"tipc_named_distribute",
"tipc_nametb_insert_self_node_pub",
"tipc_nametbl_publish",
"tipc_named_node_up"
],
"Reasoning": "The patch modifies the core TIPC logic to handle memory allocation failures during name table distribution. It adds error code returns to functions like `tipc_nametbl_publish` and `tipc_named_node_up`, and introduces `tipc_nametb_insert_self_node_pub` and `tipc_named_distribute` to handle bulk redistribution of cluster-scope publications. These are functional changes to reachable core kernel logic, and should be fuzzed.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"TIPC"
],
"FocusSymbols": [
"tipc_named_distribute",
"tipc_nametb_insert_self_node_pub",
"tipc_nametbl_publish",
"tipc_named_node_up"
],
"Reasoning": "The patch modifies the core TIPC logic to handle memory allocation failures during name table distribution. It adds error code returns to functions like `tipc_nametbl_publish` and `tipc_named_node_up`, and introduces `tipc_nametb_insert_self_node_pub` and `tipc_named_distribute` to handle bulk redistribution of cluster-scope publications. These are functional changes to reachable core kernel logic, and should be fuzzed.",
"WorthFuzzing": true
} |
| 23/1 | 2026/08/17 07:05 | action | If |
9mArgs:{
"WorthFuzzing": true
}Results: null |
| 24/2 | 2026/08/17 07:05 | agent | kmsan-evaluator |
9mModel:best-expensive Args: null Results: {
"KMSANReasoning": "The patch modifies the TIPC subsystem to handle memory allocation failures (returning `-ENOBUFS`) during name table distribution. It adds error handling to functions like `tipc_named_distribute`, `tipc_named_node_up`, and `tipc_nametbl_publish`, and introduces flags to track the state of the name table and node address. All newly introduced variables and structures (e.g., `struct tipc_socket_addr sk`, `struct tipc_uaddr ua`) are fully initialized before use (e.g., via explicit assignment or the `tipc_uaddr()` helper). No new structures are copied to user space, and no complex data structures are allocated where uninitialized fields could be read later. The changes primarily affect control flow and error handling for memory allocation failures, which do not expose uninitialized memory risks. Standard KASAN and other bug detectors are sufficient to catch any potential out-of-bounds accesses or use-after-free bugs. Therefore, a dedicated KMSAN fuzzing session is not necessary.",
"NeedsKMSAN": false
}Instruction: You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.
CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
a comprehensive suite of debugging tools and sanitizers, including KASAN
(out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
(locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
or page allocations) and kernel-to-user memory info-leaks.
Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.
Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.
Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
attributes, ioctl output arguments, socket options, or BPF buffers) where fields
or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
uninitialized bytes of existing buffers.
Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
dereferences, locking deadlocks, or use-after-free bugs (these are already caught
by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.
Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
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 ea7c3d4b9b40a93d311459bcbe2bd66bd922d385
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Aug 17 07:03:58 2026 +0000
syz-cluster: applied patch under review
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 315975c3be818..0f1d3ddeae095 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -61,6 +61,9 @@ static int __net_init tipc_init_net(struct net *net)
tn->trial_addr = 0;
tn->addr_trial_end = 0;
tn->capabilities = TIPC_NODE_CAPABILITIES;
+ tn->nt_stop = false;
+ tn->nt_self_node_exist = false;
+ atomic_set(&tn->node_addr_set, 0);
INIT_WORK(&tn->work, tipc_net_finalize_work);
memset(tn->node_id, 0, sizeof(tn->node_id));
memset(tn->node_id_string, 0, sizeof(tn->node_id_string));
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 9ce5f9ff6cc03..975b1d48186e6 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -145,6 +145,12 @@ struct tipc_net {
struct work_struct work;
/* The numbers of work queues in schedule */
atomic_t wq_count;
+ /* Flag to indicate that the node's address is set */
+ atomic_t node_addr_set;
+ /* The name table has stopped working */
+ bool nt_stop;
+ /* Node's self address publication is available in the name table */
+ bool nt_self_node_exist;
};
static inline struct tipc_net *tipc_net(struct net *net)
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index ba4f4906e13b7..83e3ed8f2c512 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -95,9 +95,7 @@ struct sk_buff *tipc_named_publish(struct net *net, struct publication *p)
list_add_tail_rcu(&p->binding_node, &nt->node_scope);
return NULL;
}
- write_lock_bh(&nt->cluster_scope_lock);
list_add_tail(&p->binding_node, &nt->cluster_scope);
- write_unlock_bh(&nt->cluster_scope_lock);
skb = named_prepare_buf(net, PUBLICATION, ITEM_SIZE, 0);
if (!skb) {
pr_warn("Publication distribution failure\n");
@@ -121,9 +119,7 @@ struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *p)
struct distr_item *item;
struct sk_buff *skb;
- write_lock_bh(&nt->cluster_scope_lock);
list_del(&p->binding_node);
- write_unlock_bh(&nt->cluster_scope_lock);
if (p->scope == TIPC_NODE_SCOPE)
return NULL;
@@ -146,9 +142,14 @@ struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *p)
* @dnode: node to be updated
* @pls: linked list of publication items to be packed into buffer chain
* @seqno: sequence number for this message
+ *
+ * Return:
+ * * 0 - Success
+ * * -ENOBUFS - No buffer space is available
+ *
*/
-static void named_distribute(struct net *net, struct sk_buff_head *list,
- u32 dnode, struct list_head *pls, u16 seqno)
+static int named_distribute(struct net *net, struct sk_buff_head *list,
+ u32 dnode, struct list_head *pls, u16 seqno)
{
struct publication *publ;
struct sk_buff *skb = NULL;
@@ -164,8 +165,9 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,
skb = named_prepare_buf(net, PUBLICATION, msg_rem,
dnode);
if (!skb) {
+ __skb_queue_purge(list);
pr_warn("Bulk publication failure\n");
- return;
+ return -ENOBUFS;
}
hdr = buf_msg(skb);
msg_set_bc_ack_invalid(hdr, true);
@@ -195,6 +197,90 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,
hdr = buf_msg(skb_peek_tail(list));
msg_set_last_bulk(hdr);
msg_set_named_seqno(hdr, seqno);
+
+ return 0;
+}
+
+/**
+ * __tipc_named_distribute - build a list of publications need to be distributed
+ * @net: the associated network namespace
+ * @dnode: destination node
+ * @head: list of publications
+ *
+ * Return:
+ * * 0 - Success
+ * * -ENOBUFS - No buffer space is available
+ *
+ */
+static int __tipc_named_distribute(struct net *net, u32 dnode,
+ struct sk_buff_head *head)
+{
+ struct name_table *nt = tipc_name_table(net);
+ struct tipc_net *tn = tipc_net(net);
+
+ /* Name table has been deleted after namespace teardown or
+ * TIPC module exit.
+ */
+ if (unlikely(tn->nt_stop))
+ return 0;
+
+ /* Node's self-address is not set yet */
+ if (!atomic_read(&tn->node_addr_set)) {
+ /* Defer the distribution to node's timer */
+ tipc_node_set_dist_bulk(net, dnode);
+ return 0;
+ }
+
+ /* Previous call to tipc_nametb_insert_self_node_pub() was successful.
+ * The node's self-address publication was added to 'nt->cluster_scope'.
+ * So, 'nt->cluster_scope' is not empty now. Go to distribution.
+ */
+ if (tn->nt_self_node_exist)
+ goto distribute;
+
+ if (tipc_nametb_insert_self_node_pub(net))
+ return -ENOBUFS;
+
+ tn->nt_self_node_exist = true;
+
+distribute:
+ if (named_distribute(net, head, dnode,
+ &nt->cluster_scope, nt->snd_nxt) == -ENOBUFS)
+ return -ENOBUFS;
+
+ return 0;
+}
+
+/**
+ * tipc_named_distribute - distribute all publications to specified node
+ * @net: the associated network namespace
+ * @dnode: destination node
+ *
+ * Return:
+ * * 0 - Success
+ * * -ENOBUFS - No buffer space is available
+ *
+ */
+int tipc_named_distribute(struct net *net, u32 dnode)
+{
+ struct tipc_net *tn = tipc_net(net);
+ struct sk_buff_head head;
+ int rc = 0;
+
+ __skb_queue_head_init(&head);
+ spin_lock_bh(&tn->nametbl_lock);
+ rc = __tipc_named_distribute(net, dnode, &head);
+ spin_unlock_bh(&tn->nametbl_lock);
+ if (!rc && !skb_queue_empty(&head)) {
+ rc = tipc_node_xmit(net, &head, dnode, 0);
+ /* The link is congested after the list is inserted into the
+ * link's send queue. Return 0, as this is normal.
+ */
+ if (rc == -ELINKCONG)
+ rc = 0;
+ }
+
+ return rc;
}
/**
@@ -202,25 +288,36 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,
* @net: the associated network namespace
* @dnode: destination node
* @capabilities: peer node's capabilities
+ *
+ * Return:
+ * * 0 - Success
+ * * -ENOBUFS - No buffer space is available
+ *
*/
-void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)
+int tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)
{
struct name_table *nt = tipc_name_table(net);
struct tipc_net *tn = tipc_net(net);
struct sk_buff_head head;
- u16 seqno;
+ int rc = 0;
__skb_queue_head_init(&head);
spin_lock_bh(&tn->nametbl_lock);
if (!(capabilities & TIPC_NAMED_BCAST))
nt->rc_dests++;
- seqno = nt->snd_nxt;
+
+ rc = __tipc_named_distribute(net, dnode, &head);
spin_unlock_bh(&tn->nametbl_lock);
+ if (!rc && !skb_queue_empty(&head)) {
+ rc = tipc_node_xmit(net, &head, dnode, 0);
+ /* The link is congested after the list is inserted into the
+ * link's send queue. Return 0, as this is normal.
+ */
+ if (rc == -ELINKCONG)
+ rc = 0;
+ }
- read_lock_bh(&nt->cluster_scope_lock);
- named_distribute(net, &head, dnode, &nt->cluster_scope, seqno);
- tipc_node_xmit(net, &head, dnode, 0);
- read_unlock_bh(&nt->cluster_scope_lock);
+ return rc;
}
/**
@@ -299,7 +396,7 @@ static bool tipc_update_nametbl(struct net *net, struct distr_item *i,
sk.node = node;
if (dtype == PUBLICATION) {
- p = tipc_nametbl_insert_publ(net, &ua, &sk, key);
+ p = tipc_nametbl_insert_publ(net, &ua, &sk, key, NULL);
if (p) {
tipc_node_subscribe(net, &p->binding_node, node);
return true;
@@ -416,5 +513,6 @@ void tipc_named_reinit(struct net *net)
list_for_each_entry_rcu(p, &nt->cluster_scope, binding_node)
p->sk.node = self;
nt->rc_dests = 0;
+ tn->nt_stop = false;
spin_unlock_bh(&tn->nametbl_lock);
}
diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h
index c677f6f082dfb..2043096ae967d 100644
--- a/net/tipc/name_distr.h
+++ b/net/tipc/name_distr.h
@@ -69,11 +69,12 @@ struct distr_item {
struct sk_buff *tipc_named_publish(struct net *net, struct publication *publ);
struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ);
-void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities);
+int tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities);
void tipc_named_rcv(struct net *net, struct sk_buff_head *namedq,
u16 *rcv_nxt, bool *open);
void tipc_named_reinit(struct net *net);
void tipc_publ_notify(struct net *net, struct list_head *nsub_list,
u32 addr, u16 capabilities);
+int tipc_named_distribute(struct net *net, u32 dnode);
#endif
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index 253c72d1366eb..beed40a21368a 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -329,7 +329,7 @@ static struct service_range *tipc_service_create_range(struct tipc_service *sc,
static bool tipc_service_insert_publ(struct net *net,
struct tipc_service *sc,
- struct publication *p)
+ struct publication *p, int *err)
{
struct tipc_subscription *sub, *tmp;
struct service_range *sr;
@@ -339,10 +339,12 @@ static bool tipc_service_insert_publ(struct net *net,
bool res = false;
u32 key = p->key;
- spin_lock_bh(&sc->lock);
sr = tipc_service_create_range(sc, p);
- if (!sr)
- goto exit;
+ if (!sr) {
+ if (err)
+ *err = -ENOBUFS;
+ goto exit;
+ }
first = list_empty(&sr->all_publ);
@@ -353,6 +355,8 @@ static bool tipc_service_insert_publ(struct net *net,
pr_debug("Failed to bind duplicate %u,%u,%u/%u:%u/%u\n",
p->sr.type, p->sr.lower, p->sr.upper,
node, p->sk.ref, key);
+ if (err)
+ *err = -EEXIST;
goto exit;
}
}
@@ -371,7 +375,6 @@ static bool tipc_service_insert_publ(struct net *net,
if (!res)
pr_warn("Failed to bind to %u,%u,%u\n",
p->sr.type, p->sr.lower, p->sr.upper);
- spin_unlock_bh(&sc->lock);
return res;
}
@@ -478,20 +481,33 @@ static struct tipc_service *tipc_service_find(struct net *net,
struct publication *tipc_nametbl_insert_publ(struct net *net,
struct tipc_uaddr *ua,
struct tipc_socket_addr *sk,
- u32 key)
+ u32 key, int *err)
{
struct tipc_service *sc;
struct publication *p;
p = tipc_publ_create(ua, sk, key);
- if (!p)
+ if (!p) {
+ if (err)
+ *err = -ENOBUFS;
return NULL;
+ }
sc = tipc_service_find(net, ua);
if (!sc)
sc = tipc_service_create(net, ua);
- if (sc && tipc_service_insert_publ(net, sc, p))
- return p;
+
+ if (sc) {
+ spin_lock_bh(&sc->lock);
+ if (tipc_service_insert_publ(net, sc, p, err)) {
+ spin_unlock_bh(&sc->lock);
+ return p;
+ }
+ spin_unlock_bh(&sc->lock);
+ } else if (err) {
+ *err = -ENOBUFS;
+ }
+
kfree(p);
return NULL;
}
@@ -760,26 +776,55 @@ void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,
/* tipc_nametbl_publish - add service binding to name table
*/
struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,
- struct tipc_socket_addr *sk, u32 key)
+ struct tipc_socket_addr *sk,
+ u32 key, int *err)
{
struct name_table *nt = tipc_name_table(net);
+ u32 max_user_pub = TIPC_MAX_PUBL - 1;
struct tipc_net *tn = tipc_net(net);
struct publication *p = NULL;
struct sk_buff *skb = NULL;
+ bool protocol_type = false;
+ int error = 0;
u32 rc_dests;
+ if (ua->sr.type == TIPC_NODE_STATE || ua->sr.type == TIPC_LINK_STATE ||
+ ua->sr.type == TIPC_TOP_SRV)
+ protocol_type = true;
+
spin_lock_bh(&tn->nametbl_lock);
+ if (protocol_type)
+ goto insert;
- if (nt->local_publ_count >= TIPC_MAX_PUBL) {
- pr_warn("Bind failed, max limit %u reached\n", TIPC_MAX_PUBL);
+ /* Reserve one entry for node state service type because it has cluster
+ * scope and it is distributed in bulk. So, the maximum number of user's
+ * publications is (TIPC_MAX_PUBL - 1).
+ */
+ if (nt->local_publ_count >= max_user_pub) {
+ pr_warn("Bind failed, max limit %u reached\n", max_user_pub);
goto exit;
}
- p = tipc_nametbl_insert_publ(net, ua, sk, key);
+insert:
+ p = tipc_nametbl_insert_publ(net, ua, sk, key, &error);
if (p) {
- nt->local_publ_count++;
+ /* Not count node state, link state and topology server types
+ * so that maximum nt->local_publ_count does not prevent
+ * protocol service types from being inserted into the name
+ * table.
+ */
+ if (!protocol_type)
+ nt->local_publ_count++;
skb = tipc_named_publish(net, p);
+ /* Local-scope publication is not published (skb is NULL), only
+ * cluster-cope one is.
+ */
+ if (!skb && p->scope == TIPC_CLUSTER_SCOPE && err)
+ *err = -ENOBUFS;
+ } else if ((error == -ENOBUFS) && err) {
+ *err = -ENOBUFS;
}
+
rc_dests = nt->rc_dests;
exit:
spin_unlock_bh(&tn->nametbl_lock);
@@ -787,7 +832,102 @@ struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,
if (skb)
tipc_node_broadcast(net, skb, rc_dests);
return p;
+}
+
+/**
+ * tipc_nametb_insert_self_node_pub - insert publication of node's self address
+ * @net: network namespace
+ *
+ * Return:
+ * * 0 - Success
+ * * -ENOBUFS - No buffer space is available
+ *
+ */
+int tipc_nametb_insert_self_node_pub(struct net *net)
+{
+ struct name_table *nt = tipc_name_table(net);
+ struct tipc_net *tn = tipc_net(net);
+ struct tipc_socket_addr sk;
+ struct service_range *sr;
+ struct tipc_service *sc;
+ bool sc_created = false;
+ struct publication *p;
+ struct tipc_uaddr ua;
+ int err = 0;
+
+ sk.ref = 0;
+ sk.node = tn->node_addr;
+ tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,
+ TIPC_NODE_STATE, tn->node_addr, tn->node_addr);
+ sc = tipc_service_find(net, &ua);
+ if (!sc) {
+ sc = tipc_service_create(net, &ua);
+ if (!sc)
+ return -ENOBUFS;
+ sc_created = true;
+ }
+ spin_lock_bh(&sc->lock);
+ /* Check whether a range exists in the name table with
+ * lower == tn->node_addr, upper == tn->node_addr, and type
+ * TIPC_NODE_STATE (0). If 'sr' is not NULL, this range exists
+ * due to a previous call to tipc_nametb_insert_self_node_pub()
+ * or tipc_net_finalize().
+ *
+ * Note that user applications can only insert types greater than
+ * or equal to 64 (TIPC_RESERVED_TYPES), as enforced by tipc_bind().
+ * Remote nodes also only send protocol publications with type
+ * TIPC_NODE_STATE (0), with both lower and upper set to the remote
+ * node's address. These ranges cannot be the same as this node's
+ * range because a remote node's address must differ from this
+ * node's address (tn->node_addr).
+ *
+ * Therefore, tipc_update_nametbl() cannot build and insert a remote
+ * publication with the same type (0) and range
+ * (lower == tn->node_addr, upper == tn->node_addr) as this node's
+ * self-address publication in the name table.
+ *
+ * Because the combination of type 0 and
+ * (lower == tn->node_addr, upper == tn->node_addr) is unique in the
+ * name table, it is not necessary to check sk.node, sk.ref, key, or
+ * cluster_scope membership.
+ */
+ sr = tipc_service_find_range(sc, &ua);
+ /* 1. tipc_net_finalize_work() is not scheduled because of namespace
+ * teardown.
+ * 2. Or tipc_net_finalize() ---> tipc_nametbl_publish() has failed
+ * to insert node self address publication into nt->cluster_scope
+ * due to memory allocation failure.
+ * 3. Or tipc_net_finalize() ---> tipc_nametbl_publish() has not
+ * executed yet.
+ */
+ if (!sr) {
+ p = tipc_publ_create(&ua, &sk, tn->node_addr);
+ if (!p)
+ goto error;
+
+ if (!tipc_service_insert_publ(net, sc, p, &err) &&
+ (err == -ENOBUFS)) {
+ kfree(p);
+ goto error;
+ }
+
+ list_add_tail(&p->binding_node, &nt->cluster_scope);
+ goto exit;
+error:
+ if (sc_created) {
+ hlist_del_init_rcu(&sc->service_list);
+ spin_unlock_bh(&sc->lock);
+ kfree_rcu(sc, rcu);
+ return -ENOBUFS;
+ }
+
+ spin_unlock_bh(&sc->lock);
+ return -ENOBUFS;
+ }
+exit:
+ spin_unlock_bh(&sc->lock);
+ return 0;
}
/**
@@ -810,7 +950,10 @@ void tipc_nametbl_withdraw(struct net *net, struct tipc_uaddr *ua,
p = tipc_nametbl_remove_publ(net, ua, sk, key);
if (p) {
- nt->local_publ_count--;
+ if (p->sr.type != TIPC_NODE_STATE &&
+ p->sr.type != TIPC_LINK_STATE &&
+ p->sr.type != TIPC_TOP_SRV)
+ nt->local_publ_count--;
skb = tipc_named_withdraw(net, p);
list_del_init(&p->binding_sock);
kfree_rcu(p, rcu);
@@ -899,7 +1042,6 @@ int tipc_nametbl_init(struct net *net)
INIT_LIST_HEAD(&nt->node_scope);
INIT_LIST_HEAD(&nt->cluster_scope);
- rwlock_init(&nt->cluster_scope_lock);
tn->nametbl = nt;
spin_lock_init(&tn->nametbl_lock);
return 0;
@@ -912,6 +1054,7 @@ int tipc_nametbl_init(struct net *net)
*/
static void tipc_service_delete(struct net *net, struct tipc_service *sc)
{
+ struct tipc_net *tn = tipc_net(net);
struct service_range *sr, *tmpr;
struct publication *p, *tmp;
@@ -919,6 +1062,15 @@ static void tipc_service_delete(struct net *net, struct tipc_service *sc)
rbtree_postorder_for_each_entry_safe(sr, tmpr, &sc->ranges, tree_node) {
list_for_each_entry_safe(p, tmp, &sr->all_publ, all_publ) {
tipc_service_remove_publ(sr, &p->sk, p->key);
+ /* tipc_nametbl_withdraw() does not delete
+ * 'p->binding_node' with type TIPC_NODE_STATE and
+ * range [tn->node_addr, tn->node_addr] from
+ * 'tn->cluster_scope'. So, delete it here.
+ */
+ if (p->sr.type == TIPC_NODE_STATE &&
+ p->sr.lower == tn->node_addr &&
+ p->sr.upper == tn->node_addr)
+ list_del(&p->binding_node);
kfree_rcu(p, rcu);
}
rb_erase_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks);
@@ -949,6 +1101,8 @@ void tipc_nametbl_stop(struct net *net)
tipc_service_delete(net, service);
}
}
+ tn->nt_stop = true;
+ tn->nt_self_node_exist = false;
spin_unlock_bh(&tn->nametbl_lock);
/* TODO: clear tn->nametbl, implement proper RCU rules ? */
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h
index 7ff6eeebaae64..4390e79a4660e 100644
--- a/net/tipc/name_table.h
+++ b/net/tipc/name_table.h
@@ -97,8 +97,7 @@ struct publication {
* @cluster_scope: all local publications with cluster scope
* - used by name_distr to send bulk updates to new nodes
* - used by name_distr during re-init of name table
- * @cluster_scope_lock: lock for accessing @cluster_scope
- * @local_publ_count: number of publications issued by this node
+ * @local_publ_count: the number of user's publications issued by this node
* @rc_dests: destination node counter
* @snd_nxt: next sequence number to be used
*/
@@ -107,7 +106,6 @@ struct name_table {
struct hlist_head services[TIPC_NAMETBL_SIZE];
struct list_head node_scope;
struct list_head cluster_scope;
- rwlock_t cluster_scope_lock;
u32 local_publ_count;
u32 rc_dests;
u32 snd_nxt;
@@ -126,13 +124,15 @@ bool tipc_nametbl_lookup_group(struct net *net, struct tipc_uaddr *ua,
void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,
struct tipc_uaddr *ua);
struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,
- struct tipc_socket_addr *sk, u32 key);
+ struct tipc_socket_addr *sk,
+ u32 key, int *err);
void tipc_nametbl_withdraw(struct net *net, struct tipc_uaddr *ua,
struct tipc_socket_addr *sk, u32 key);
struct publication *tipc_nametbl_insert_publ(struct net *net,
struct tipc_uaddr *ua,
struct tipc_socket_addr *sk,
- u32 key);
+ u32 key, int *err);
+int tipc_nametb_insert_self_node_pub(struct net *net);
struct publication *tipc_nametbl_remove_publ(struct net *net,
struct tipc_uaddr *ua,
struct tipc_socket_addr *sk,
diff --git a/net/tipc/net.c b/net/tipc/net.c
index 7e65d0b0c4a8d..7a2c1e67aca3d 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -110,11 +110,14 @@ static void tipc_net_finalize(struct net *net, u32 addr);
int tipc_net_init(struct net *net, u8 *node_id, u32 addr)
{
+ struct tipc_net *tn = tipc_net(net);
+
if (tipc_own_id(net)) {
pr_info("Cannot configure node identity twice\n");
return -1;
}
pr_info("Started in network mode\n");
+ atomic_set(&tn->node_addr_set, 0);
if (node_id)
tipc_set_node_id(net, node_id);
@@ -125,8 +128,8 @@ int tipc_net_init(struct net *net, u8 *node_id, u32 addr)
static void tipc_net_finalize(struct net *net, u32 addr)
{
- struct tipc_net *tn = tipc_net(net);
struct tipc_socket_addr sk = {0, addr};
+ struct tipc_net *tn = tipc_net(net);
struct tipc_uaddr ua;
tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,
@@ -138,7 +141,11 @@ static void tipc_net_finalize(struct net *net, u32 addr)
tipc_named_reinit(net);
tipc_sk_reinit(net);
tipc_mon_reinit_self(net);
- tipc_nametbl_publish(net, &ua, &sk, addr);
+ atomic_set(&tn->node_addr_set, 1);
+ /* Redistribute bulk of publications via node-up event or node's timer
+ * if tipc_nametbl_publish() fails.
+ */
+ tipc_nametbl_publish(net, &ua, &sk, addr, NULL);
}
void tipc_net_finalize_work(struct work_struct *work)
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 683a136e53efc..f1eee674a678e 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -111,6 +111,7 @@ struct tipc_bclink_entry {
* @peer_net: peer's net namespace
* @peer_hash_mix: hash for this peer (FIXME)
* @crypto_rx: RX crypto handler
+ * @dist_bulk: flag to redistribute cluster-scope publications
*/
struct tipc_node {
u32 addr;
@@ -145,6 +146,7 @@ struct tipc_node {
#ifdef CONFIG_TIPC_CRYPTO
struct tipc_crypto *crypto_rx;
#endif
+ atomic_t dist_bulk;
};
/* Node FSM states and events:
@@ -345,6 +347,17 @@ static struct tipc_node *tipc_node_find(struct net *net, u32 addr)
return node;
}
+void tipc_node_set_dist_bulk(struct net *net, u32 addr)
+{
+ struct tipc_node *node;
+
+ node = tipc_node_find(net, addr);
+ if (node) {
+ atomic_set(&node->dist_bulk, 1);
+ tipc_node_put(node);
+ }
+}
+
/* tipc_node_find_by_id - locate specified node object by its 128-bit id
* Note: this function is called only when a discovery request failed
* to find the node by its 32-bit id, and is not time critical
@@ -393,6 +406,14 @@ static void tipc_node_write_unlock_fast(struct tipc_node *n)
write_unlock_bh(&n->lock);
}
+static void tipc_node_down(struct tipc_node *n)
+{
+ int bearer_id;
+
+ for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++)
+ tipc_node_link_down(n, bearer_id, false);
+}
+
static void tipc_node_write_unlock(struct tipc_node *n)
__releases(n->lock)
{
@@ -402,6 +423,7 @@ static void tipc_node_write_unlock(struct tipc_node *n)
struct list_head *publ_list;
struct tipc_uaddr ua;
u32 bearer_id, node;
+ int rc = 0, err = 0;
if (likely(!flags)) {
write_unlock_bh(&n->lock);
@@ -425,16 +447,24 @@ static void tipc_node_write_unlock(struct tipc_node *n)
tipc_publ_notify(net, publ_list, node, n->capabilities);
if (flags & TIPC_NOTIFY_NODE_UP)
- tipc_named_node_up(net, node, n->capabilities);
+ rc = tipc_named_node_up(net, node, n->capabilities);
if (flags & TIPC_NOTIFY_LINK_UP) {
tipc_mon_peer_up(net, node, bearer_id);
- tipc_nametbl_publish(net, &ua, &sk, sk.ref);
+ tipc_nametbl_publish(net, &ua, &sk, sk.ref, &err);
}
if (flags & TIPC_NOTIFY_LINK_DOWN) {
tipc_mon_peer_down(net, node, bearer_id);
tipc_nametbl_withdraw(net, &ua, &sk, sk.ref);
}
+
+ /* Memory allocation has failed. Bring the node down to start over bulk
+ * distribution when the first link is up again.
+ */
+ if (rc < 0)
+ tipc_node_down(n);
+ else if (err == -ENOBUFS)
+ tipc_node_link_down(n, bearer_id, false);
}
static void tipc_node_assign_peer_net(struct tipc_node *n, u32 hash_mixes)
@@ -564,6 +594,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u8 *peer_id,
INIT_LIST_HEAD(&n->list);
INIT_LIST_HEAD(&n->publ_list);
INIT_LIST_HEAD(&n->conn_sks);
+ atomic_set(&n->dist_bulk, 0);
skb_queue_head_init(&n->bc_entry.namedq);
skb_queue_head_init(&n->bc_entry.inputq1);
__skb_queue_head_init(&n->bc_entry.arrvq);
@@ -803,7 +834,8 @@ static void tipc_node_timeout(struct timer_list *t)
struct tipc_node *n = timer_container_of(n, t, timer);
struct tipc_link_entry *le;
struct sk_buff_head xmitq;
- int remains = n->link_cnt;
+ int remains = 0;
+ int dist_rc = 0;
int bearer_id;
int rc = 0;
@@ -814,6 +846,9 @@ static void tipc_node_timeout(struct timer_list *t)
return;
}
+ if (atomic_xchg(&n->dist_bulk, 0))
+ dist_rc = tipc_named_distribute(n->net, n->addr);
+
#ifdef CONFIG_TIPC_CRYPTO
/* Take any crypto key related actions first */
tipc_crypto_timeout(n->crypto_rx);
@@ -825,6 +860,7 @@ static void tipc_node_timeout(struct timer_list *t)
*/
tipc_node_read_lock(n);
n->keepalive_intv = 10000;
+ remains = n->link_cnt;
tipc_node_read_unlock(n);
for (bearer_id = 0; remains && (bearer_id < MAX_BEARERS); bearer_id++) {
tipc_node_read_lock(n);
@@ -835,11 +871,13 @@ static void tipc_node_timeout(struct timer_list *t)
tipc_node_calculate_timer(n, le->link);
rc = tipc_link_timeout(le->link, &xmitq);
spin_unlock_bh(&le->lock);
- remains--;
+ if (dist_rc < 0)
+ remains--;
}
tipc_node_read_unlock(n);
tipc_bearer_xmit(n->net, bearer_id, &xmitq, &le->maddr, n);
- if (rc & TIPC_LINK_DOWN_EVT)
+ /* Force the node down in case the redistribution failed */
+ if ((rc & TIPC_LINK_DOWN_EVT) || dist_rc < 0)
tipc_node_link_down(n, bearer_id, false);
}
mod_timer(&n->timer, jiffies + msecs_to_jiffies(n->keepalive_intv));
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 154a5bbb0d29d..0f777cfe7c01e 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -128,4 +128,5 @@ int tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_node_flush_key(struct sk_buff *skb, struct genl_info *info);
#endif
void tipc_node_pre_cleanup_net(struct net *exit_net);
+void tipc_node_set_dist_bulk(struct net *net, u32 addr);
#endif
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index d5d70eb230b56..6b83bdfc439c3 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -2919,7 +2919,7 @@ static int tipc_sk_publish(struct tipc_sock *tsk, struct tipc_uaddr *ua)
return -EADDRINUSE;
skaddr.ref = tsk->portid;
skaddr.node = tipc_own_addr(net);
- p = tipc_nametbl_publish(net, ua, &skaddr, key);
+ p = tipc_nametbl_publish(net, ua, &skaddr, key, NULL);
if (unlikely(!p))
return -EINVAL;
|
| 25/3 | 2026/08/17 07:05 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 12738 output: 20 thoughts: 526 Thoughts: **Analyzing the TIPC Name Table Distribution Patch**
Okay, so this patch is digging into the TIPC subsystem within the Linux kernel, specifically the name table publication and distribution mechanisms. My initial assessment is focused on understanding the scope of the changes and identifying any potential risks. It looks like the main thrust is around improving error handling, particularly when memory allocation fails during the distribution process – good, that's definitely a point to address, rather than silently failing or crashing. They're explicitly adding handling for `-ENOBUFS` which is the right way to do it.
From the description, they’re touching quite a few functions: `tipc_named_distribute`, `tipc_named_node_up`, `tipc_nametbl_publish`, `tipc_nametbl_insert_publ`, etc. This means it's pretty involved. And, it looks like they're also introducing new flags within `struct tipc_net` (`nt_stop`, `nt_self_node_exist`, `node_addr_set`) and adding a new `dist_bulk` field to `struct tipc_node`. That's important to note, state tracking and new control flow can lead to unintended side effects.
My immediate concern, as always, is memory safety. Are there any uninitialized memory risks? The description suggests the changes are primarily control flow and error handling. No new structures are *directly* being copied to user space, which is a big relief. No complex new data structures are being allocated where unititialized fields could be read. The core idea seems to be gracefully handling memory allocation failures in the TIPC name distribution process. That should be a good thing.
Now, let's drill down into a specific code snippet, specifically `tipc_nametb_insert_self_node_pub`:
```c
+int tipc_nametb_insert_self_node_pub(struct net *net)
+{
...
+ sk.ref = 0;
+ sk.node = tn->node_addr;
+ tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,
+ TIPC_NODE_STATE, tn->node_addr, tn->node_addr);
...
```
Right, `sk` here is a `struct tipc_socket_addr`, and it *appears* to be fully initialized: `sk.ref` is set to `0`, and `sk.node` is populated from `tn->node_addr`. That’s good. `ua` is a `struct tipc_uaddr`. Now, `tipc_uaddr` is being called, which initializes it. It's a function or a macro. I should double-check the implementation of `tipc_uaddr`, in `net/tipc/core.h` or somewhere similar to be absolutely sure that it initializes all the fields of the struct to the correct values. It's a quick sanity check at this point. Gotta be thorough.
|
| 26/3 | 2026/08/17 07:05 | tool | grepper |
0mArgs:{
"Expression": "tipc_uaddr\\("
}Results: {
"Output": "net/tipc/addr.h=50=struct tipc_uaddr {\n--\nnet/tipc/addr.h-63-\nnet/tipc/addr.h:64:static inline void tipc_uaddr(struct tipc_uaddr *ua, u32 atype, u32 scope,\nnet/tipc/addr.h-65-\t\t\t u32 type, u32 lower, u32 upper)\n--\nnet/tipc/msg.c=713=bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, int *err)\n--\nnet/tipc/msg.c-733-\t\treturn false;\nnet/tipc/msg.c:734:\ttipc_uaddr(\u0026ua, TIPC_SERVICE_RANGE, scope,\nnet/tipc/msg.c-735-\t\t msg_nametype(msg), inst, inst);\n--\nnet/tipc/name_distr.c=332=static void tipc_publ_purge(struct net *net, struct publication *p, u32 addr)\n--\nnet/tipc/name_distr.c-337-\nnet/tipc/name_distr.c:338:\ttipc_uaddr(\u0026ua, TIPC_SERVICE_RANGE, p-\u003escope, p-\u003esr.type,\nnet/tipc/name_distr.c-339-\t\t p-\u003esr.lower, p-\u003esr.upper);\n--\nnet/tipc/name_distr.c=376=static bool tipc_update_nametbl(struct net *net, struct distr_item *i,\n--\nnet/tipc/name_distr.c-392-\nnet/tipc/name_distr.c:393:\ttipc_uaddr(\u0026ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,\nnet/tipc/name_distr.c-394-\t\t ntohl(i-\u003etype), lower, upper);\n--\nnet/tipc/name_table.c=846=int tipc_nametb_insert_self_node_pub(struct net *net)\n--\nnet/tipc/name_table.c-859-\tsk.node = tn-\u003enode_addr;\nnet/tipc/name_table.c:860:\ttipc_uaddr(\u0026ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,\nnet/tipc/name_table.c-861-\t\t TIPC_NODE_STATE, tn-\u003enode_addr, tn-\u003enode_addr);\n--\nnet/tipc/name_table.c=972=bool tipc_nametbl_subscribe(struct tipc_subscription *sub)\n--\nnet/tipc/name_table.c-979-\nnet/tipc/name_table.c:980:\ttipc_uaddr(\u0026ua, TIPC_SERVICE_RANGE, TIPC_NODE_SCOPE, type,\nnet/tipc/name_table.c-981-\t\t sub-\u003es.seq.lower, sub-\u003es.seq.upper);\n--\nnet/tipc/name_table.c=1003=void tipc_nametbl_unsubscribe(struct tipc_subscription *sub)\n--\nnet/tipc/name_table.c-1008-\nnet/tipc/name_table.c:1009:\ttipc_uaddr(\u0026ua, TIPC_SERVICE_RANGE, TIPC_NODE_SCOPE,\nnet/tipc/name_table.c-1010-\t\t sub-\u003es.seq.type, sub-\u003es.seq.lower, sub-\u003es.seq.upper);\n--\nnet/tipc/name_table.c=1206=static int tipc_nl_service_list(struct net *net, struct tipc_nl_msg *msg,\n--\nnet/tipc/name_table.c-1225-\t\t (!i \u0026\u0026 *last_key \u0026\u0026 (*last_lower == *last_key))) {\nnet/tipc/name_table.c:1226:\t\t\ttipc_uaddr(\u0026ua, TIPC_SERVICE_RANGE, TIPC_NODE_SCOPE,\nnet/tipc/name_table.c-1227-\t\t\t\t *last_type, *last_lower, *last_lower);\n--\nnet/tipc/net.c=129=static void tipc_net_finalize(struct net *net, u32 addr)\n--\nnet/tipc/net.c-134-\nnet/tipc/net.c:135:\ttipc_uaddr(\u0026ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,\nnet/tipc/net.c-136-\t\t TIPC_NODE_STATE, addr, addr);\n--\nnet/tipc/node.c=417=static void tipc_node_write_unlock(struct tipc_node *n)\n--\nnet/tipc/node.c-432-\nnet/tipc/node.c:433:\ttipc_uaddr(\u0026ua, TIPC_SERVICE_RANGE, TIPC_NODE_SCOPE,\nnet/tipc/node.c-434-\t\t TIPC_LINK_STATE, n-\u003eaddr, n-\u003eaddr);\n--\nnet/tipc/socket.c=2932=static int tipc_sk_withdraw(struct tipc_sock *tsk, struct tipc_uaddr *ua)\n--\nnet/tipc/socket.c-2940-\t\tif (!ua) {\nnet/tipc/socket.c:2941:\t\t\ttipc_uaddr(\u0026_ua, TIPC_SERVICE_RANGE, p-\u003escope,\nnet/tipc/socket.c-2942-\t\t\t\t p-\u003esr.type, p-\u003esr.lower, p-\u003esr.upper);\n--\nnet/tipc/socket.c=3072=static int tipc_sk_join(struct tipc_sock *tsk, struct tipc_group_req *mreq)\n--\nnet/tipc/socket.c-3094-\tmsg_set_dest_droppable(hdr, true);\nnet/tipc/socket.c:3095:\ttipc_uaddr(\u0026ua, TIPC_SERVICE_RANGE, mreq-\u003escope,\nnet/tipc/socket.c-3096-\t\t mreq-\u003etype, mreq-\u003einstance, mreq-\u003einstance);\n"
} |
| 27/3 | 2026/08/17 07:05 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15534 output: 22 thoughts: 13 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Diving into `tipc_uaddr` Implementation** Okay, time to dig into the `tipc_uaddr` implementation. I need to refresh my memory on how this is structured and ensure it's behaving as expected. I'll likely start by tracing its use cases within the TIPC framework to see where it comes into play. Key areas will be address lookups, routing decisions, and the overall management of user-space addresses. I'll probably pay close attention to any potential race conditions or locking mechanisms involved, especially if there are shared data structures being accessed concurrently. I'm also going to see if any of the recent code changes, particularly those that touched the network or socket layer, might have introduced any regressions related to `tipc_uaddr`. Finally, I'll need to think about how this affects the overall security posture - are there any potential vulnerabilities related to address spoofing or manipulation that need to be addressed? Time to get the debugger fired up and the code open! |
| 28/3 | 2026/08/17 07:06 | tool | grepper |
0mArgs:{
"Expression": "static inline void tipc_uaddr"
}Results: {
"Output": "net/tipc/addr.h=50=struct tipc_uaddr {\n--\nnet/tipc/addr.h-63-\nnet/tipc/addr.h:64:static inline void tipc_uaddr(struct tipc_uaddr *ua, u32 atype, u32 scope,\nnet/tipc/addr.h-65-\t\t\t u32 type, u32 lower, u32 upper)\n"
} |
| 29/3 | 2026/08/17 07:06 | llm | kmsan-evaluator |
1mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15915 output: 35 thoughts: 22 Thoughts: Here's my take on those lines from `net/tipc/addr.h`: **Analyzing `net/tipc/addr.h` (Lines 50-75)** Okay, let's dive into lines 50-75 of `net/tipc/addr.h`. This is where the core address structure and associated macros probably lie – it’s the heart of how TIPC addresses are defined, and I need to refresh my understanding of their specifics. I'm expecting to find the key data structures and any bitfield manipulations that define the address fields themselves, and if there are clever bit-twiddling macros, I need to understand them. I'm especially interested in the size of each component: node, cluster, and service. I’m hoping to see clear delineations between the different parts of the address – it makes debugging far easier. I’m also looking for any hint of how the address family is handled; this might be a central point of the code. Any bit fields or packed structs are worth looking at closely, as they could be points of optimization. |
| 30/3 | 2026/08/17 07:08 | tool | read-file |
0mArgs:{
"File": "net/tipc/addr.h",
"FirstLine": 50,
"LineCount": 25
}Results: {
"Contents": " 50:\tstruct tipc_uaddr {\n 51:\t\tunsigned short family;\n 52:\t\tunsigned char addrtype;\n 53:\t\tsigned char scope;\n 54:\t\tunion {\n 55:\t\t\tstruct {\n 56:\t\t\t\tstruct tipc_service_addr sa;\n 57:\t\t\t\tu32 lookup_node;\n 58:\t\t\t};\n 59:\t\t\tstruct tipc_service_range sr;\n 60:\t\t\tstruct tipc_socket_addr sk;\n 61:\t\t};\n 62:\t};\n 63:\t\n 64:\tstatic inline void tipc_uaddr(struct tipc_uaddr *ua, u32 atype, u32 scope,\n 65:\t\t\t\t u32 type, u32 lower, u32 upper)\n 66:\t{\n 67:\t\tua-\u003efamily = AF_TIPC;\n 68:\t\tua-\u003eaddrtype = atype;\n 69:\t\tua-\u003escope = scope;\n 70:\t\tua-\u003esr.type = type;\n 71:\t\tua-\u003esr.lower = lower;\n 72:\t\tua-\u003esr.upper = upper;\n 73:\t}\n 74:\t\n"
} |
| 31/3 | 2026/08/17 07:08 | llm | kmsan-evaluator |
3mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 16523 output: 21 thoughts: 374 Thoughts: **Analyzing the `tipc_uaddr` Structure and its Usage** Okay, so I'm looking at how this `tipc_uaddr` is used, specifically how it initializes various fields and how that data is used. I see that `tipc_uaddr` is responsible for setting the `family`, `addrtype`, `scope`, and crucially, the `sr.type`, `sr.lower`, and `sr.upper` fields, which pertain to a `struct tipc_service_range`. Now, digging into the `struct tipc_uaddr` definition, it uses a union with `tipc_service_range sr`, among other types. It looks like it could represent a service address, a range of service addresses, or a socket address. I need to make sure I understand the memory layout here because of the union. Let's see... `struct tipc_uaddr` starts with the header fields: `family` (2 bytes), `addrtype` (1 byte), and `scope` (1 byte). Then, there's the union which holds either the `tipc_service_range sr` (12 bytes), `tipc_service_addr sa` and `lookup_node` (also 12 bytes), or `tipc_socket_addr sk` (8 bytes). Given that layout, and the size of each member of the union, the total size of `tipc_uaddr` is 2 + 1 + 1 + 12 = 16 bytes. There's no padding between the header fields and the union. That's good. Now, a function called `tipc_nametb_insert_self_node_pub` allocates a `struct publication *p` using `tipc_publ_create(&ua, &sk, tn->node_addr);`. This suggests that `tipc_uaddr` is used in the creation of a publication. I need to check how `tipc_publ_create` actually utilizes the information in the `tipc_uaddr` structure. I need to examine how the parameters are passed to `tipc_publ_create` and how the members of the struct are used to determine what is published. |
| 32/3 | 2026/08/17 07:11 | tool | grepper |
0mArgs:{
"Expression": "tipc_publ_create"
}Results: {
"Output": "net/tipc/name_table.c=218=static int hash(int x)\n--\nnet/tipc/name_table.c-223-/**\nnet/tipc/name_table.c:224: * tipc_publ_create - create a publication structure\nnet/tipc/name_table.c-225- * @ua: the service range the user is binding to\n--\nnet/tipc/name_table.c-228- */\nnet/tipc/name_table.c:229:static struct publication *tipc_publ_create(struct tipc_uaddr *ua,\nnet/tipc/name_table.c-230-\t\t\t\t\t struct tipc_socket_addr *sk,\n--\nnet/tipc/name_table.c=481=struct publication *tipc_nametbl_insert_publ(struct net *net,\n--\nnet/tipc/name_table.c-488-\nnet/tipc/name_table.c:489:\tp = tipc_publ_create(ua, sk, key);\nnet/tipc/name_table.c-490-\tif (!p) {\n--\nnet/tipc/name_table.c=846=int tipc_nametb_insert_self_node_pub(struct net *net)\n--\nnet/tipc/name_table.c-904-\tif (!sr) {\nnet/tipc/name_table.c:905:\t\tp = tipc_publ_create(\u0026ua, \u0026sk, tn-\u003enode_addr);\nnet/tipc/name_table.c-906-\t\tif (!p)\n"
} |
| 33/3 | 2026/08/17 07:11 | llm | kmsan-evaluator |
2mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 17830 output: 38 thoughts: 13 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience, and written as if they were my own: **Analyzing the Function `tipc_publ_create`** Alright, let's dive into `tipc_publ_create`. Knowing this codebase, and considering the name, I'm already anticipating this is where the magic happens for creating a new TIPC publication endpoint, likely for a name or service registration, right? I'm immediately thinking about the underlying data structures – the publication table, the potential for hash collisions if they're using a hash-based lookup, and the locking mechanisms to ensure concurrency safety. I need to confirm if it handles error cases such as insufficient resources (memory), invalid arguments, or name conflicts appropriately. And does it handle the registration of the same service multiple times? If so, is there a mechanism to handle that? I want to see how they're managing the lifecycle of the endpoint; is there associated cleanup on destruction or un-registration? Are they implementing any kind of timeout or lease mechanism? Also, I need to see how the metadata associated with the publication (like attributes, service types, etc.) are handled. That's usually where the subtle bugs hide. I'm especially interested in how the address binding is handled. Does it automatically pick a port, or is it user-configurable? And if configurable, how are collisions avoided when the user chooses a port? And are they properly handling the interaction with any underlying networking layer - especially if this function is related to publishing the service/name across multiple nodes. |
| 34/3 | 2026/08/17 07:13 | tool | read-file |
0mArgs:{
"File": "net/tipc/name_table.c",
"FirstLine": 229,
"LineCount": 25
}Results: {
"Contents": " 229:\tstatic struct publication *tipc_publ_create(struct tipc_uaddr *ua,\n 230:\t\t\t\t\t\t struct tipc_socket_addr *sk,\n 231:\t\t\t\t\t\t u32 key)\n 232:\t{\n 233:\t\tstruct publication *p = kzalloc_obj(*p, GFP_ATOMIC);\n 234:\t\n 235:\t\tif (!p)\n 236:\t\t\treturn NULL;\n 237:\t\n 238:\t\tp-\u003esr = ua-\u003esr;\n 239:\t\tp-\u003esk = *sk;\n 240:\t\tp-\u003escope = ua-\u003escope;\n 241:\t\tp-\u003ekey = key;\n 242:\t\tINIT_LIST_HEAD(\u0026p-\u003ebinding_sock);\n 243:\t\tINIT_LIST_HEAD(\u0026p-\u003ebinding_node);\n 244:\t\tINIT_LIST_HEAD(\u0026p-\u003elocal_publ);\n 245:\t\tINIT_LIST_HEAD(\u0026p-\u003eall_publ);\n 246:\t\tINIT_LIST_HEAD(\u0026p-\u003elist);\n 247:\t\treturn p;\n 248:\t}\n 249:\t\n 250:\t/**\n 251:\t * tipc_service_create - create a service structure for the specified 'type'\n 252:\t * @net: network namespace\n 253:\t * @ua: address representing the service to be bound\n"
} |
| 35/3 | 2026/08/17 07:13 | llm | kmsan-evaluator |
1mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 18591 output: 245 thoughts: 2816 Thoughts: **Analysis of TIPC Name Distribution Patch: No Uninitialized Memory Risk** Okay, so I've gone through this patch, line by line, focusing specifically on the potential for introducing uninitialized memory reads. My conclusion: this patch is solely about *handling* memory allocation failures during the TIPC name distribution process, *not* about introducing vulnerabilities related to uninitialized memory. The core of the patch involves adding and propagating `-ENOBUFS` (out-of-memory) errors throughout the name distribution code. It ensures that when memory allocation fails, the failure is correctly reported and handled, leading to node/link down actions for retries. I've checked every spot where new variables or structures are introduced. Each new variable, such as `sk`, `ua`, or `err` are *always* explicitly initialized before they're used. The `sk_buff_head` is always initialized using `__skb_queue_head_init()`. The `tipc_uaddr` struct is always initialized by a helper function. No uninitialized memory is being read or written. No data is being passed to user space. I've carefully examined the `tipc_nametbl_publish`, `tipc_named_distribute`, `tipc_named_node_up` and several other functions. The code adds checks and error returns, rather than introducing new data structures or logic that would rely on uninitialized values. This patch *improves* the robustness of the error handling, rather than weakening it. In other words, the patch's purpose is to *prevent* memory allocation failures from being silently ignored or causing potentially incorrect behaviour; it's not introducing any new risks. Given the nature of these changes, standard kernel debugging tools like KASAN and lockdep will be sufficient to detect any bugs that might be introduced during this work. Specifically, the risk of uninitialized memory usage isn't present, and thus a KMSAN session isn't required. |
| 36/3 | 2026/08/17 07:14 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch modifies the TIPC subsystem to handle memory allocation failures (returning `-ENOBUFS`) during name table distribution. It adds error handling to functions like `tipc_named_distribute`, `tipc_named_node_up`, and `tipc_nametbl_publish`, and introduces flags to track the state of the name table and node address. All newly introduced variables and structures (e.g., `struct tipc_socket_addr sk`, `struct tipc_uaddr ua`) are fully initialized before use (e.g., via explicit assignment or the `tipc_uaddr()` helper). No new structures are copied to user space, and no complex data structures are allocated where uninitialized fields could be read later. The changes primarily affect control flow and error handling for memory allocation failures, which do not expose uninitialized memory risks. Standard KASAN and other bug detectors are sufficient to catch any potential out-of-bounds accesses or use-after-free bugs. Therefore, a dedicated KMSAN fuzzing session is not necessary.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch modifies the TIPC subsystem to handle memory allocation failures (returning `-ENOBUFS`) during name table distribution. It adds error handling to functions like `tipc_named_distribute`, `tipc_named_node_up`, and `tipc_nametbl_publish`, and introduces flags to track the state of the name table and node address. All newly introduced variables and structures (e.g., `struct tipc_socket_addr sk`, `struct tipc_uaddr ua`) are fully initialized before use (e.g., via explicit assignment or the `tipc_uaddr()` helper). No new structures are copied to user space, and no complex data structures are allocated where uninitialized fields could be read later. The changes primarily affect control flow and error handling for memory allocation failures, which do not expose uninitialized memory risks. Standard KASAN and other bug detectors are sufficient to catch any potential out-of-bounds accesses or use-after-free bugs. Therefore, a dedicated KMSAN fuzzing session is not necessary.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|