| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/02 16:00 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"NETCONSOLE",
"NETCONSOLE_DYNAMIC"
],
"FocusSymbols": [
"netconsole_skb_pool_init",
"netconsole_skb_pool_flush",
"refill_skbs",
"netcons_skb_pop",
"find_skb",
"netpoll_send_udp",
"enabled_store",
"drop_netconsole_target",
"alloc_param_target",
"free_param_target",
"netconsole_parser_cmdline",
"__netpoll_setup",
"netpoll_setup",
"__netpoll_cleanup"
],
"Reasoning": "The patch moves the SKB pool and target configuration (ports, MAC) from `struct netpoll` to `struct netconsole_target`. It modifies how netconsole initializes and flushes the SKB pool, and updates the netpoll setup/cleanup paths. This is a functional change to the netconsole driver and netpoll core, which can be reached via configfs or module parameters.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/02 16:00 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 7d6bf840bf748bb4e2c1bec9420e063265d84e09\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Thu Jul 2 16:00:54 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c\nindex c1812a98365b78..e36b0998c81096 100644\n--- a/drivers/net/netconsole.c\n+++ b/drivers/net/netconsole.c\n@@ -61,6 +61,19 @@ MODULE_IMPORT_NS(\"NETDEV_INTERNAL\");\n #define MAX_USERDATA_ITEMS\t\t256\n #define MAX_PRINT_CHUNK\t\t\t1000\n \n+/*\n+ * Sizing for the per-target fallback skb pool consulted by find_skb()\n+ * when its GFP_ATOMIC allocation fails so messages still get out under\n+ * memory pressure.\n+ */\n+#define MAX_UDP_CHUNK\t\t\t1460\n+#define MAX_SKBS\t\t\t32\n+#define MAX_SKB_SIZE\t\t\t\t\t\t\t\\\n+\t(sizeof(struct ethhdr) +\t\t\t\t\t\\\n+\t sizeof(struct iphdr) +\t\t\t\t\t\t\\\n+\t sizeof(struct udphdr) +\t\t\t\t\t\\\n+\t MAX_UDP_CHUNK)\n+\n static char config[MAX_PARAM_LENGTH];\n module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);\n MODULE_PARM_DESC(netconsole, \" netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@\u003ctgt-ip\u003e/[tgt-macaddr]\");\n@@ -162,14 +175,19 @@ enum target_state {\n * @np:\t\tThe netpoll structure for this target.\n *\t\tContains the other userspace visible parameters:\n *\t\tdev_name\t(read-write)\n- *\t\tlocal_port\t(read-write)\n- *\t\tremote_port\t(read-write)\n *\t\tlocal_ip\t(read-write)\n *\t\tremote_ip\t(read-write)\n *\t\tlocal_mac\t(read-only)\n- *\t\tremote_mac\t(read-write)\n+ * @local_port:\tSource UDP port of the target (read-write).\n+ * @remote_port: Destination UDP port of the target (read-write).\n+ * @remote_mac:\tDestination ethernet address of the target (read-write).\n * @buf:\tThe buffer used to send the full msg to the network stack\n * @resume_wq:\tWorkqueue to resume deactivated target\n+ * @skb_pool:\tPer-target fallback skb pool consulted by find_skb() when\n+ *\t\tits GFP_ATOMIC allocation fails. Lifetime brackets a\n+ *\t\tsuccessful netpoll_setup() / netpoll_cleanup() pair on @np.\n+ * @refill_wq:\tWork item that asynchronously tops @skb_pool back up to\n+ *\t\tMAX_SKBS after find_skb() drains an entry.\n */\n struct netconsole_target {\n \tstruct list_head\tlist;\n@@ -190,11 +208,15 @@ struct netconsole_target {\n \tbool\t\t\textended;\n \tbool\t\t\trelease;\n \tstruct netpoll\t\tnp;\n+\tu16\t\t\tlocal_port, remote_port;\n+\tu8\t\t\tremote_mac[ETH_ALEN];\n \t/* protected by target_list_lock; +1 gives scnprintf() room for its\n \t * NUL terminator so a full MAX_PRINT_CHUNK payload is not truncated\n \t */\n \tchar\t\t\tbuf[MAX_PRINT_CHUNK + 1];\n \tstruct work_struct\tresume_wq;\n+\tstruct sk_buff_head\tskb_pool;\n+\tstruct work_struct\trefill_wq;\n };\n \n #ifdef\tCONFIG_NETCONSOLE_DYNAMIC\n@@ -292,11 +314,58 @@ static void netcons_release_dev(struct netconsole_target *nt)\n \t\tmemset(\u0026nt-\u003enp.dev_name, 0, IFNAMSIZ);\n }\n \n+static void refill_skbs(struct netconsole_target *nt)\n+{\n+\tstruct sk_buff_head *skb_pool = \u0026nt-\u003eskb_pool;\n+\tstruct sk_buff *skb;\n+\n+\twhile (READ_ONCE(skb_pool-\u003eqlen) \u003c MAX_SKBS) {\n+\t\tskb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC | __GFP_NOWARN);\n+\t\tif (!skb)\n+\t\t\tbreak;\n+\n+\t\tskb_queue_tail(skb_pool, skb);\n+\t}\n+}\n+\n+static void refill_skbs_work_handler(struct work_struct *work)\n+{\n+\tstruct netconsole_target *nt =\n+\t\tcontainer_of(work, struct netconsole_target, refill_wq);\n+\n+\trefill_skbs(nt);\n+}\n+\n+/* Initialise the per-target skb pool that find_skb() falls back to and\n+ * seed it. Pair with netconsole_skb_pool_flush() at the matching\n+ * netpoll teardown.\n+ */\n+static void netconsole_skb_pool_init(struct netconsole_target *nt)\n+{\n+\tskb_queue_head_init(\u0026nt-\u003eskb_pool);\n+\tINIT_WORK(\u0026nt-\u003erefill_wq, refill_skbs_work_handler);\n+\trefill_skbs(nt);\n+}\n+\n+static void netconsole_skb_pool_flush(struct netconsole_target *nt)\n+{\n+\tcancel_work_sync(\u0026nt-\u003erefill_wq);\n+\tskb_queue_purge_reason(\u0026nt-\u003eskb_pool, SKB_CONSUMED);\n+}\n+\n /* Attempts to resume logging to a deactivated target. */\n static void resume_target(struct netconsole_target *nt)\n {\n+\t/* Initialise the skb pool before netpoll_setup() makes nt-\u003enp.dev\n+\t * visible to target_list walkers (e.g. netconsole_netdev_event),\n+\t * which otherwise may move the target to the cleanup list and\n+\t * call netconsole_skb_pool_flush() on uninitialised state.\n+\t */\n+\tnetconsole_skb_pool_init(nt);\n+\n \tif (netpoll_setup(\u0026nt-\u003enp)) {\n \t\t/* netpoll fails setup once, do not try again. */\n+\t\tnetconsole_skb_pool_flush(nt);\n \t\tnt-\u003estate = STATE_DISABLED;\n \t\treturn;\n \t}\n@@ -358,6 +427,7 @@ static void process_resume_target(struct work_struct *work)\n \trtnl_lock();\n \tif (nt-\u003estate == STATE_ENABLED \u0026\u0026 nt-\u003enp.dev \u0026\u0026\n \t nt-\u003enp.dev-\u003ereg_state != NETREG_REGISTERED) {\n+\t\tnetconsole_skb_pool_flush(nt);\n \t\tnetcons_release_dev(nt);\n \t\tnt-\u003estate = STATE_DISABLED;\n \t}\n@@ -393,9 +463,9 @@ static struct netconsole_target *alloc_and_init(void)\n \n \tnt-\u003enp.name = \"netconsole\";\n \tstrscpy(nt-\u003enp.dev_name, \"eth0\", IFNAMSIZ);\n-\tnt-\u003enp.local_port = 6665;\n-\tnt-\u003enp.remote_port = 6666;\n-\teth_broadcast_addr(nt-\u003enp.remote_mac);\n+\tnt-\u003elocal_port = 6665;\n+\tnt-\u003eremote_port = 6666;\n+\teth_broadcast_addr(nt-\u003eremote_mac);\n \tnt-\u003estate = STATE_DISABLED;\n \tINIT_WORK(\u0026nt-\u003eresume_wq, process_resume_target);\n \n@@ -417,6 +487,7 @@ static void netconsole_process_cleanups_core(void)\n \tlist_for_each_entry_safe(nt, tmp, \u0026target_cleanup_list, list) {\n \t\t/* all entries in the cleanup_list needs to be disabled */\n \t\tWARN_ON_ONCE(nt-\u003estate == STATE_ENABLED);\n+\t\tnetconsole_skb_pool_flush(nt);\n \t\tnetcons_release_dev(nt);\n \t\t/* moved the cleaned target to target_list. Need to hold both\n \t\t * locks\n@@ -429,21 +500,23 @@ static void netconsole_process_cleanups_core(void)\n \tmutex_unlock(\u0026target_cleanup_list_lock);\n }\n \n-static void netconsole_print_banner(struct netpoll *np)\n+static void netconsole_print_banner(struct netconsole_target *nt)\n {\n-\tnp_info(np, \"local port %d\\n\", np-\u003elocal_port);\n+\tstruct netpoll *np = \u0026nt-\u003enp;\n+\n+\tnp_info(np, \"local port %d\\n\", nt-\u003elocal_port);\n \tif (np-\u003eipv6)\n \t\tnp_info(np, \"local IPv6 address %pI6c\\n\", \u0026np-\u003elocal_ip.in6);\n \telse\n \t\tnp_info(np, \"local IPv4 address %pI4\\n\", \u0026np-\u003elocal_ip.ip);\n \tnp_info(np, \"interface name '%s'\\n\", np-\u003edev_name);\n \tnp_info(np, \"local ethernet address '%pM'\\n\", np-\u003edev_mac);\n-\tnp_info(np, \"remote port %d\\n\", np-\u003eremote_port);\n+\tnp_info(np, \"remote port %d\\n\", nt-\u003eremote_port);\n \tif (np-\u003eipv6)\n \t\tnp_info(np, \"remote IPv6 address %pI6c\\n\", \u0026np-\u003eremote_ip.in6);\n \telse\n \t\tnp_info(np, \"remote IPv4 address %pI4\\n\", \u0026np-\u003eremote_ip.ip);\n-\tnp_info(np, \"remote ethernet address %pM\\n\", np-\u003eremote_mac);\n+\tnp_info(np, \"remote ethernet address %pM\\n\", nt-\u003eremote_mac);\n }\n \n /* Parse the string and populate the `inet_addr` union. Return 0 if IPv4 is\n@@ -561,12 +634,12 @@ static ssize_t dev_name_show(struct config_item *item, char *buf)\n \n static ssize_t local_port_show(struct config_item *item, char *buf)\n {\n-\treturn sysfs_emit(buf, \"%d\\n\", to_target(item)-\u003enp.local_port);\n+\treturn sysfs_emit(buf, \"%d\\n\", to_target(item)-\u003elocal_port);\n }\n \n static ssize_t remote_port_show(struct config_item *item, char *buf)\n {\n-\treturn sysfs_emit(buf, \"%d\\n\", to_target(item)-\u003enp.remote_port);\n+\treturn sysfs_emit(buf, \"%d\\n\", to_target(item)-\u003eremote_port);\n }\n \n static ssize_t local_ip_show(struct config_item *item, char *buf)\n@@ -599,7 +672,7 @@ static ssize_t local_mac_show(struct config_item *item, char *buf)\n \n static ssize_t remote_mac_show(struct config_item *item, char *buf)\n {\n-\treturn sysfs_emit(buf, \"%pM\\n\", to_target(item)-\u003enp.remote_mac);\n+\treturn sysfs_emit(buf, \"%pM\\n\", to_target(item)-\u003eremote_mac);\n }\n \n static ssize_t transmit_errors_show(struct config_item *item, char *buf)\n@@ -756,11 +829,21 @@ static ssize_t enabled_store(struct config_item *item,\n \t\t * Skip netconsole_parser_cmdline() -- all the attributes are\n \t\t * already configured via configfs. Just print them out.\n \t\t */\n-\t\tnetconsole_print_banner(\u0026nt-\u003enp);\n+\t\tnetconsole_print_banner(nt);\n+\n+\t\t/* Initialise the skb pool before netpoll_setup() so the pool\n+\t\t * is valid as soon as nt-\u003enp.dev becomes visible to\n+\t\t * target_list walkers (netconsole_netdev_event), which would\n+\t\t * otherwise call netconsole_skb_pool_flush() on uninitialised\n+\t\t * state.\n+\t\t */\n+\t\tnetconsole_skb_pool_init(nt);\n \n \t\tret = netpoll_setup(\u0026nt-\u003enp);\n-\t\tif (ret)\n+\t\tif (ret) {\n+\t\t\tnetconsole_skb_pool_flush(nt);\n \t\t\tgoto out_unlock;\n+\t\t}\n \n \t\tnt-\u003estate = STATE_ENABLED;\n \t\tpr_info(\"network logging started\\n\");\n@@ -885,7 +968,7 @@ static ssize_t local_port_store(struct config_item *item, const char *buf,\n \t\tgoto out_unlock;\n \t}\n \n-\tret = kstrtou16(buf, 10, \u0026nt-\u003enp.local_port);\n+\tret = kstrtou16(buf, 10, \u0026nt-\u003elocal_port);\n \tif (ret \u003c 0)\n \t\tgoto out_unlock;\n \tret = count;\n@@ -907,7 +990,7 @@ static ssize_t remote_port_store(struct config_item *item,\n \t\tgoto out_unlock;\n \t}\n \n-\tret = kstrtou16(buf, 10, \u0026nt-\u003enp.remote_port);\n+\tret = kstrtou16(buf, 10, \u0026nt-\u003eremote_port);\n \tif (ret \u003c 0)\n \t\tgoto out_unlock;\n \tret = count;\n@@ -994,7 +1077,7 @@ static ssize_t remote_mac_store(struct config_item *item, const char *buf,\n \t\tgoto out_unlock;\n \tif (buf[MAC_ADDR_STR_LEN] \u0026\u0026 buf[MAC_ADDR_STR_LEN] != '\\n')\n \t\tgoto out_unlock;\n-\tmemcpy(nt-\u003enp.remote_mac, remote_mac, ETH_ALEN);\n+\tmemcpy(nt-\u003eremote_mac, remote_mac, ETH_ALEN);\n \n \tret = count;\n out_unlock:\n@@ -1514,8 +1597,10 @@ static void drop_netconsole_target(struct config_group *group,\n \t * netpoll_cleanup() is idempotent (it skips when np-\u003edev is NULL), so\n \t * it is safe even if the cleanup worker already tore the netpoll down.\n \t */\n-\tif (needs_cleanup)\n+\tif (needs_cleanup) {\n+\t\tnetconsole_skb_pool_flush(nt);\n \t\tnetpoll_cleanup(\u0026nt-\u003enp);\n+\t}\n \n \tconfig_item_put(\u0026nt-\u003egroup.cg_item);\n }\n@@ -1706,7 +1791,7 @@ static struct notifier_block netconsole_netdev_notifier = {\n * pool locks and is therefore not NMI-safe. Skip the refill when called\n * from NMI context; the next non-NMI caller will top the pool back up.\n */\n-static struct sk_buff *netcons_skb_pop(struct netpoll *np, int len)\n+static struct sk_buff *netcons_skb_pop(struct netconsole_target *nt, int len)\n {\n \tstruct sk_buff *skb;\n \n@@ -1718,19 +1803,21 @@ static struct sk_buff *netcons_skb_pop(struct netpoll *np, int len)\n \t\tif (!in_nmi())\n \t\t\tnet_warn_ratelimited(\"netconsole: dropping message, requested skb len %d exceeds pool buffer size %zu on %s\\n\",\n \t\t\t\t\t len, (size_t)MAX_SKB_SIZE,\n-\t\t\t\t\t np-\u003edev-\u003ename);\n+\t\t\t\t\t nt-\u003enp.dev-\u003ename);\n \t\treturn NULL;\n \t}\n \n-\tskb = skb_dequeue(\u0026np-\u003eskb_pool);\n+\tskb = skb_dequeue(\u0026nt-\u003eskb_pool);\n \tif (!in_nmi())\n-\t\tschedule_work(\u0026np-\u003erefill_wq);\n+\t\tschedule_work(\u0026nt-\u003erefill_wq);\n \n \treturn skb;\n }\n \n-static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)\n+static struct sk_buff *find_skb(struct netconsole_target *nt, int len,\n+\t\t\t\tint reserve)\n {\n+\tstruct netpoll *np = \u0026nt-\u003enp;\n \tint count = 0;\n \tstruct sk_buff *skb;\n \n@@ -1739,7 +1826,7 @@ static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)\n \n \tskb = alloc_skb(len, GFP_ATOMIC | __GFP_NOWARN);\n \tif (!skb)\n-\t\tskb = netcons_skb_pop(np, len);\n+\t\tskb = netcons_skb_pop(nt, len);\n \n \tif (!skb) {\n \t\tif (++count \u003c 10) {\n@@ -1779,8 +1866,9 @@ static void netpoll_udp_checksum(struct netpoll *np, struct sk_buff *skb,\n \t\tudph-\u003echeck = CSUM_MANGLED_0;\n }\n \n-static void push_udp(struct netpoll *np, struct sk_buff *skb, int len)\n+static void push_udp(struct netconsole_target *nt, struct sk_buff *skb, int len)\n {\n+\tstruct netpoll *np = \u0026nt-\u003enp;\n \tstruct udphdr *udph;\n \tint udp_len;\n \n@@ -1790,21 +1878,22 @@ static void push_udp(struct netpoll *np, struct sk_buff *skb, int len)\n \tskb_reset_transport_header(skb);\n \n \tudph = udp_hdr(skb);\n-\tudph-\u003esource = htons(np-\u003elocal_port);\n-\tudph-\u003edest = htons(np-\u003eremote_port);\n+\tudph-\u003esource = htons(nt-\u003elocal_port);\n+\tudph-\u003edest = htons(nt-\u003eremote_port);\n \tudph-\u003elen = htons(udp_len);\n \n \tnetpoll_udp_checksum(np, skb, len);\n }\n \n-static void push_eth(struct netpoll *np, struct sk_buff *skb)\n+static void push_eth(struct netconsole_target *nt, struct sk_buff *skb)\n {\n+\tstruct netpoll *np = \u0026nt-\u003enp;\n \tstruct ethhdr *eth;\n \n \teth = skb_push(skb, ETH_HLEN);\n \tskb_reset_mac_header(skb);\n \tether_addr_copy(eth-\u003eh_source, np-\u003edev-\u003edev_addr);\n-\tether_addr_copy(eth-\u003eh_dest, np-\u003eremote_mac);\n+\tether_addr_copy(eth-\u003eh_dest, nt-\u003eremote_mac);\n \tif (np-\u003eipv6)\n \t\teth-\u003eh_proto = htons(ETH_P_IPV6);\n \telse\n@@ -1861,8 +1950,10 @@ static void push_ipv6(struct netpoll *np, struct sk_buff *skb, int len)\n \tskb-\u003eprotocol = htons(ETH_P_IPV6);\n }\n \n-static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)\n+static int netpoll_send_udp(struct netconsole_target *nt, const char *msg,\n+\t\t\t int len)\n {\n+\tstruct netpoll *np = \u0026nt-\u003enp;\n \tint total_len, ip_len, udp_len;\n \tstruct sk_buff *skb;\n \n@@ -1877,7 +1968,7 @@ static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)\n \n \ttotal_len = ip_len + LL_RESERVED_SPACE(np-\u003edev);\n \n-\tskb = find_skb(np, total_len + np-\u003edev-\u003eneeded_tailroom,\n+\tskb = find_skb(nt, total_len + np-\u003edev-\u003eneeded_tailroom,\n \t\t total_len - len);\n \tif (!skb)\n \t\treturn -ENOMEM;\n@@ -1885,12 +1976,12 @@ static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)\n \tskb_copy_to_linear_data(skb, msg, len);\n \tskb_put(skb, len);\n \n-\tpush_udp(np, skb, len);\n+\tpush_udp(nt, skb, len);\n \tif (np-\u003eipv6)\n \t\tpush_ipv6(np, skb, len);\n \telse\n \t\tpush_ipv4(np, skb, len);\n-\tpush_eth(np, skb);\n+\tpush_eth(nt, skb);\n \tskb-\u003edev = np-\u003edev;\n \n \treturn (int)netpoll_send_skb(np, skb);\n@@ -1908,7 +1999,7 @@ static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)\n */\n static void send_udp(struct netconsole_target *nt, const char *msg, int len)\n {\n-\tint result = netpoll_send_udp(\u0026nt-\u003enp, msg, len);\n+\tint result = netpoll_send_udp(nt, msg, len);\n \n \tif (IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC)) {\n \t\tif (result == NET_XMIT_DROP) {\n@@ -2203,8 +2294,9 @@ __releases(\u0026target_list_lock)\n \tspin_unlock_irqrestore(\u0026target_list_lock, flags);\n }\n \n-static int netconsole_parser_cmdline(struct netpoll *np, char *opt)\n+static int netconsole_parser_cmdline(struct netconsole_target *nt, char *opt)\n {\n+\tstruct netpoll *np = \u0026nt-\u003enp;\n \tbool ipversion_set = false;\n \tchar *cur = opt;\n \tchar *delim;\n@@ -2215,7 +2307,7 @@ static int netconsole_parser_cmdline(struct netpoll *np, char *opt)\n \t\tif (!delim)\n \t\t\tgoto parse_failed;\n \t\t*delim = 0;\n-\t\tif (kstrtou16(cur, 10, \u0026np-\u003elocal_port))\n+\t\tif (kstrtou16(cur, 10, \u0026nt-\u003elocal_port))\n \t\t\tgoto parse_failed;\n \t\tcur = delim;\n \t}\n@@ -2262,7 +2354,7 @@ static int netconsole_parser_cmdline(struct netpoll *np, char *opt)\n \t\t*delim = 0;\n \t\tif (*cur == ' ' || *cur == '\\t')\n \t\t\tnp_info(np, \"warning: whitespace is not allowed\\n\");\n-\t\tif (kstrtou16(cur, 10, \u0026np-\u003eremote_port))\n+\t\tif (kstrtou16(cur, 10, \u0026nt-\u003eremote_port))\n \t\t\tgoto parse_failed;\n \t\tcur = delim;\n \t}\n@@ -2284,11 +2376,11 @@ static int netconsole_parser_cmdline(struct netpoll *np, char *opt)\n \n \tif (*cur != 0) {\n \t\t/* MAC address */\n-\t\tif (!mac_pton(cur, np-\u003eremote_mac))\n+\t\tif (!mac_pton(cur, nt-\u003eremote_mac))\n \t\t\tgoto parse_failed;\n \t}\n \n-\tnetconsole_print_banner(np);\n+\tnetconsole_print_banner(nt);\n \n \treturn 0;\n \n@@ -2326,14 +2418,22 @@ static struct netconsole_target *alloc_param_target(char *target_config,\n \t}\n \n \t/* Parse parameters and setup netpoll */\n-\terr = netconsole_parser_cmdline(\u0026nt-\u003enp, target_config);\n+\terr = netconsole_parser_cmdline(nt, target_config);\n \tif (err)\n \t\tgoto fail;\n \n+\t/* Initialise the skb pool before netpoll_setup() so the pool is\n+\t * valid as soon as nt-\u003enp.dev becomes visible. The target is not\n+\t * yet on target_list, so a netdev event cannot reach it here, but\n+\t * mirror the configfs path for symmetry.\n+\t */\n+\tnetconsole_skb_pool_init(nt);\n+\n \terr = netpoll_setup(\u0026nt-\u003enp);\n \tif (err) {\n \t\tpr_err(\"Not enabling netconsole for %s%d. Netpoll setup failed\\n\",\n \t\t NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count);\n+\t\tnetconsole_skb_pool_flush(nt);\n \t\tif (!IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC))\n \t\t\t/* only fail if dynamic reconfiguration is set,\n \t\t\t * otherwise, keep the target in the list, but disabled.\n@@ -2355,6 +2455,8 @@ static struct netconsole_target *alloc_param_target(char *target_config,\n static void free_param_target(struct netconsole_target *nt)\n {\n \tcancel_work_sync(\u0026nt-\u003eresume_wq);\n+\tif (nt-\u003estate == STATE_ENABLED)\n+\t\tnetconsole_skb_pool_flush(nt);\n \tnetpoll_cleanup(\u0026nt-\u003enp);\n #ifdef\tCONFIG_NETCONSOLE_DYNAMIC\n \tkfree(nt-\u003euserdata);\ndiff --git a/include/linux/netpoll.h b/include/linux/netpoll.h\nindex 88f7daa8560e58..79315461a7b1e0 100644\n--- a/include/linux/netpoll.h\n+++ b/include/linux/netpoll.h\n@@ -21,20 +21,6 @@ union inet_addr {\n \tstruct in6_addr\tin6;\n };\n \n-/*\n- * Maximum payload netpoll's preallocated skb pool can carry. Keep this in\n- * sync with the buffer size used by refill_skbs() in net/core/netpoll.c;\n- * callers (e.g. netconsole) use it to detect requests the pool can never\n- * satisfy and avoid dequeuing a pooled skb that would later trip\n- * skb_over_panic() in skb_put().\n- */\n-#define MAX_UDP_CHUNK\t1460\n-#define MAX_SKB_SIZE\t\t\t\t\t\t\\\n-\t(sizeof(struct ethhdr) +\t\t\t\t\\\n-\t sizeof(struct iphdr) +\t\t\t\t\t\\\n-\t sizeof(struct udphdr) +\t\t\t\t\\\n-\t MAX_UDP_CHUNK)\n-\n struct netpoll {\n \tstruct net_device *dev;\n \tnetdevice_tracker dev_tracker;\n@@ -49,10 +35,6 @@ struct netpoll {\n \n \tunion inet_addr local_ip, remote_ip;\n \tbool ipv6;\n-\tu16 local_port, remote_port;\n-\tu8 remote_mac[ETH_ALEN];\n-\tstruct sk_buff_head skb_pool;\n-\tstruct work_struct refill_wq;\n };\n \n #define np_info(np, fmt, ...)\t\t\t\t\\\ndiff --git a/net/core/netpoll.c b/net/core/netpoll.c\nindex 85aa5135088117..10b6063251a5bc 100644\n--- a/net/core/netpoll.c\n+++ b/net/core/netpoll.c\n@@ -36,12 +36,6 @@\n #include \u003ctrace/events/napi.h\u003e\n #include \u003clinux/kconfig.h\u003e\n \n-/*\n- * We maintain a small pool of fully-sized skbs, to make sure the\n- * message gets out even in extreme OOM situations.\n- */\n-\n-#define MAX_SKBS 32\n #define USEC_PER_POLL\t50\n \n static unsigned int carrier_timeout = 4;\n@@ -213,22 +207,6 @@ void netpoll_poll_enable(struct net_device *dev)\n \t\tup(\u0026ni-\u003edev_lock);\n }\n \n-static void refill_skbs(struct netpoll *np)\n-{\n-\tstruct sk_buff_head *skb_pool;\n-\tstruct sk_buff *skb;\n-\n-\tskb_pool = \u0026np-\u003eskb_pool;\n-\n-\twhile (READ_ONCE(skb_pool-\u003eqlen) \u003c MAX_SKBS) {\n-\t\tskb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC | __GFP_NOWARN);\n-\t\tif (!skb)\n-\t\t\tbreak;\n-\n-\t\tskb_queue_tail(skb_pool, skb);\n-\t}\n-}\n-\n void netpoll_zap_completion_queue(void)\n {\n \tunsigned long flags;\n@@ -351,32 +329,12 @@ netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)\n }\n EXPORT_SYMBOL(netpoll_send_skb);\n \n-static void skb_pool_flush(struct netpoll *np)\n-{\n-\tstruct sk_buff_head *skb_pool;\n-\n-\tcancel_work_sync(\u0026np-\u003erefill_wq);\n-\tskb_pool = \u0026np-\u003eskb_pool;\n-\tskb_queue_purge_reason(skb_pool, SKB_CONSUMED);\n-}\n-\n-static void refill_skbs_work_handler(struct work_struct *work)\n-{\n-\tstruct netpoll *np =\n-\t\tcontainer_of(work, struct netpoll, refill_wq);\n-\n-\trefill_skbs(np);\n-}\n-\n int __netpoll_setup(struct netpoll *np, struct net_device *ndev)\n {\n \tstruct netpoll_info *npinfo;\n \tconst struct net_device_ops *ops;\n \tint err;\n \n-\tskb_queue_head_init(\u0026np-\u003eskb_pool);\n-\tINIT_WORK(\u0026np-\u003erefill_wq, refill_skbs_work_handler);\n-\n \tif (ndev-\u003epriv_flags \u0026 IFF_DISABLE_NETPOLL) {\n \t\tnp_err(np, \"%s doesn't support polling, aborting\\n\",\n \t\t ndev-\u003ename);\n@@ -411,9 +369,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)\n \tnp-\u003edev = ndev;\n \tstrscpy(np-\u003edev_name, ndev-\u003ename, IFNAMSIZ);\n \n-\t/* fill up the skb queue */\n-\trefill_skbs(np);\n-\n \t/* last thing to do is link it to the net device structure */\n \trcu_assign_pointer(ndev-\u003enpinfo, npinfo);\n \n@@ -603,7 +558,7 @@ int netpoll_setup(struct netpoll *np)\n \n \terr = __netpoll_setup(np, ndev);\n \tif (err)\n-\t\tgoto flush;\n+\t\tgoto put;\n \trtnl_unlock();\n \n \t/* Make sure all NAPI polls which started before dev-\u003enpinfo\n@@ -614,8 +569,6 @@ int netpoll_setup(struct netpoll *np)\n \n \treturn 0;\n \n-flush:\n-\tskb_pool_flush(np);\n put:\n \tDEBUG_NET_WARN_ON_ONCE(np-\u003edev);\n \tif (ip_overwritten)\n@@ -666,8 +619,6 @@ static void __netpoll_cleanup(struct netpoll *np)\n \t\tRCU_INIT_POINTER(np-\u003edev-\u003enpinfo, NULL);\n \t\tcall_rcu(\u0026npinfo-\u003ercu, rcu_cleanup_netpoll_info);\n \t}\n-\n-\tskb_pool_flush(np);\n }\n \n void __netpoll_free(struct netpoll *np)\n"
} |
| 2/1 | 2026/07/02 16:00 | agent | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"NETCONSOLE",
"NETCONSOLE_DYNAMIC"
],
"FocusSymbols": [
"netconsole_skb_pool_init",
"netconsole_skb_pool_flush",
"refill_skbs",
"netcons_skb_pop",
"find_skb",
"netpoll_send_udp",
"enabled_store",
"drop_netconsole_target",
"alloc_param_target",
"free_param_target",
"netconsole_parser_cmdline",
"__netpoll_setup",
"netpoll_setup",
"__netpoll_cleanup"
],
"Reasoning": "The patch moves the SKB pool and target configuration (ports, MAC) from `struct netpoll` to `struct netconsole_target`. It modifies how netconsole initializes and flushes the SKB pool, and updates the netpoll setup/cleanup paths. This is a functional change to the netconsole driver and netpoll core, which can be reached via configfs or module parameters.",
"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). 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. 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. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. 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 7d6bf840bf748bb4e2c1bec9420e063265d84e09
Author: syz-cluster <triage@syzkaller.com>
Date: Thu Jul 2 16:00:54 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index c1812a98365b78..e36b0998c81096 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -61,6 +61,19 @@ MODULE_IMPORT_NS("NETDEV_INTERNAL");
#define MAX_USERDATA_ITEMS 256
#define MAX_PRINT_CHUNK 1000
+/*
+ * Sizing for the per-target fallback skb pool consulted by find_skb()
+ * when its GFP_ATOMIC allocation fails so messages still get out under
+ * memory pressure.
+ */
+#define MAX_UDP_CHUNK 1460
+#define MAX_SKBS 32
+#define MAX_SKB_SIZE \
+ (sizeof(struct ethhdr) + \
+ sizeof(struct iphdr) + \
+ sizeof(struct udphdr) + \
+ MAX_UDP_CHUNK)
+
static char config[MAX_PARAM_LENGTH];
module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);
MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]");
@@ -162,14 +175,19 @@ enum target_state {
* @np: The netpoll structure for this target.
* Contains the other userspace visible parameters:
* dev_name (read-write)
- * local_port (read-write)
- * remote_port (read-write)
* local_ip (read-write)
* remote_ip (read-write)
* local_mac (read-only)
- * remote_mac (read-write)
+ * @local_port: Source UDP port of the target (read-write).
+ * @remote_port: Destination UDP port of the target (read-write).
+ * @remote_mac: Destination ethernet address of the target (read-write).
* @buf: The buffer used to send the full msg to the network stack
* @resume_wq: Workqueue to resume deactivated target
+ * @skb_pool: Per-target fallback skb pool consulted by find_skb() when
+ * its GFP_ATOMIC allocation fails. Lifetime brackets a
+ * successful netpoll_setup() / netpoll_cleanup() pair on @np.
+ * @refill_wq: Work item that asynchronously tops @skb_pool back up to
+ * MAX_SKBS after find_skb() drains an entry.
*/
struct netconsole_target {
struct list_head list;
@@ -190,11 +208,15 @@ struct netconsole_target {
bool extended;
bool release;
struct netpoll np;
+ u16 local_port, remote_port;
+ u8 remote_mac[ETH_ALEN];
/* protected by target_list_lock; +1 gives scnprintf() room for its
* NUL terminator so a full MAX_PRINT_CHUNK payload is not truncated
*/
char buf[MAX_PRINT_CHUNK + 1];
struct work_struct resume_wq;
+ struct sk_buff_head skb_pool;
+ struct work_struct refill_wq;
};
#ifdef CONFIG_NETCONSOLE_DYNAMIC
@@ -292,11 +314,58 @@ static void netcons_release_dev(struct netconsole_target *nt)
memset(&nt->np.dev_name, 0, IFNAMSIZ);
}
+static void refill_skbs(struct netconsole_target *nt)
+{
+ struct sk_buff_head *skb_pool = &nt->skb_pool;
+ struct sk_buff *skb;
+
+ while (READ_ONCE(skb_pool->qlen) < MAX_SKBS) {
+ skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC | __GFP_NOWARN);
+ if (!skb)
+ break;
+
+ skb_queue_tail(skb_pool, skb);
+ }
+}
+
+static void refill_skbs_work_handler(struct work_struct *work)
+{
+ struct netconsole_target *nt =
+ container_of(work, struct netconsole_target, refill_wq);
+
+ refill_skbs(nt);
+}
+
+/* Initialise the per-target skb pool that find_skb() falls back to and
+ * seed it. Pair with netconsole_skb_pool_flush() at the matching
+ * netpoll teardown.
+ */
+static void netconsole_skb_pool_init(struct netconsole_target *nt)
+{
+ skb_queue_head_init(&nt->skb_pool);
+ INIT_WORK(&nt->refill_wq, refill_skbs_work_handler);
+ refill_skbs(nt);
+}
+
+static void netconsole_skb_pool_flush(struct netconsole_target *nt)
+{
+ cancel_work_sync(&nt->refill_wq);
+ skb_queue_purge_reason(&nt->skb_pool, SKB_CONSUMED);
+}
+
/* Attempts to resume logging to a deactivated target. */
static void resume_target(struct netconsole_target *nt)
{
+ /* Initialise the skb pool before netpoll_setup() makes nt->np.dev
+ * visible to target_list walkers (e.g. netconsole_netdev_event),
+ * which otherwise may move the target to the cleanup list and
+ * call netconsole_skb_pool_flush() on uninitialised state.
+ */
+ netconsole_skb_pool_init(nt);
+
if (netpoll_setup(&nt->np)) {
/* netpoll fails setup once, do not try again. */
+ netconsole_skb_pool_flush(nt);
nt->state = STATE_DISABLED;
return;
}
@@ -358,6 +427,7 @@ static void process_resume_target(struct work_struct *work)
rtnl_lock();
if (nt->state == STATE_ENABLED && nt->np.dev &&
nt->np.dev->reg_state != NETREG_REGISTERED) {
+ netconsole_skb_pool_flush(nt);
netcons_release_dev(nt);
nt->state = STATE_DISABLED;
}
@@ -393,9 +463,9 @@ static struct netconsole_target *alloc_and_init(void)
nt->np.name = "netconsole";
strscpy(nt->np.dev_name, "eth0", IFNAMSIZ);
- nt->np.local_port = 6665;
- nt->np.remote_port = 6666;
- eth_broadcast_addr(nt->np.remote_mac);
+ nt->local_port = 6665;
+ nt->remote_port = 6666;
+ eth_broadcast_addr(nt->remote_mac);
nt->state = STATE_DISABLED;
INIT_WORK(&nt->resume_wq, process_resume_target);
@@ -417,6 +487,7 @@ static void netconsole_process_cleanups_core(void)
list_for_each_entry_safe(nt, tmp, &target_cleanup_list, list) {
/* all entries in the cleanup_list needs to be disabled */
WARN_ON_ONCE(nt->state == STATE_ENABLED);
+ netconsole_skb_pool_flush(nt);
netcons_release_dev(nt);
/* moved the cleaned target to target_list. Need to hold both
* locks
@@ -429,21 +500,23 @@ static void netconsole_process_cleanups_core(void)
mutex_unlock(&target_cleanup_list_lock);
}
-static void netconsole_print_banner(struct netpoll *np)
+static void netconsole_print_banner(struct netconsole_target *nt)
{
- np_info(np, "local port %d\n", np->local_port);
+ struct netpoll *np = &nt->np;
+
+ np_info(np, "local port %d\n", nt->local_port);
if (np->ipv6)
np_info(np, "local IPv6 address %pI6c\n", &np->local_ip.in6);
else
np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip);
np_info(np, "interface name '%s'\n", np->dev_name);
np_info(np, "local ethernet address '%pM'\n", np->dev_mac);
- np_info(np, "remote port %d\n", np->remote_port);
+ np_info(np, "remote port %d\n", nt->remote_port);
if (np->ipv6)
np_info(np, "remote IPv6 address %pI6c\n", &np->remote_ip.in6);
else
np_info(np, "remote IPv4 address %pI4\n", &np->remote_ip.ip);
- np_info(np, "remote ethernet address %pM\n", np->remote_mac);
+ np_info(np, "remote ethernet address %pM\n", nt->remote_mac);
}
/* Parse the string and populate the `inet_addr` union. Return 0 if IPv4 is
@@ -561,12 +634,12 @@ static ssize_t dev_name_show(struct config_item *item, char *buf)
static ssize_t local_port_show(struct config_item *item, char *buf)
{
- return sysfs_emit(buf, "%d\n", to_target(item)->np.local_port);
+ return sysfs_emit(buf, "%d\n", to_target(item)->local_port);
}
static ssize_t remote_port_show(struct config_item *item, char *buf)
{
- return sysfs_emit(buf, "%d\n", to_target(item)->np.remote_port);
+ return sysfs_emit(buf, "%d\n", to_target(item)->remote_port);
}
static ssize_t local_ip_show(struct config_item *item, char *buf)
@@ -599,7 +672,7 @@ static ssize_t local_mac_show(struct config_item *item, char *buf)
static ssize_t remote_mac_show(struct config_item *item, char *buf)
{
- return sysfs_emit(buf, "%pM\n", to_target(item)->np.remote_mac);
+ return sysfs_emit(buf, "%pM\n", to_target(item)->remote_mac);
}
static ssize_t transmit_errors_show(struct config_item *item, char *buf)
@@ -756,11 +829,21 @@ static ssize_t enabled_store(struct config_item *item,
* Skip netconsole_parser_cmdline() -- all the attributes are
* already configured via configfs. Just print them out.
*/
- netconsole_print_banner(&nt->np);
+ netconsole_print_banner(nt);
+
+ /* Initialise the skb pool before netpoll_setup() so the pool
+ * is valid as soon as nt->np.dev becomes visible to
+ * target_list walkers (netconsole_netdev_event), which would
+ * otherwise call netconsole_skb_pool_flush() on uninitialised
+ * state.
+ */
+ netconsole_skb_pool_init(nt);
ret = netpoll_setup(&nt->np);
- if (ret)
+ if (ret) {
+ netconsole_skb_pool_flush(nt);
goto out_unlock;
+ }
nt->state = STATE_ENABLED;
pr_info("network logging started\n");
@@ -885,7 +968,7 @@ static ssize_t local_port_store(struct config_item *item, const char *buf,
goto out_unlock;
}
- ret = kstrtou16(buf, 10, &nt->np.local_port);
+ ret = kstrtou16(buf, 10, &nt->local_port);
if (ret < 0)
goto out_unlock;
ret = count;
@@ -907,7 +990,7 @@ static ssize_t remote_port_store(struct config_item *item,
goto out_unlock;
}
- ret = kstrtou16(buf, 10, &nt->np.remote_port);
+ ret = kstrtou16(buf, 10, &nt->remote_port);
if (ret < 0)
goto out_unlock;
ret = count;
@@ -994,7 +1077,7 @@ static ssize_t remote_mac_store(struct config_item *item, const char *buf,
goto out_unlock;
if (buf[MAC_ADDR_STR_LEN] && buf[MAC_ADDR_STR_LEN] != '\n')
goto out_unlock;
- memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
+ memcpy(nt->remote_mac, remote_mac, ETH_ALEN);
ret = count;
out_unlock:
@@ -1514,8 +1597,10 @@ static void drop_netconsole_target(struct config_group *group,
* netpoll_cleanup() is idempotent (it skips when np->dev is NULL), so
* it is safe even if the cleanup worker already tore the netpoll down.
*/
- if (needs_cleanup)
+ if (needs_cleanup) {
+ netconsole_skb_pool_flush(nt);
netpoll_cleanup(&nt->np);
+ }
config_item_put(&nt->group.cg_item);
}
@@ -1706,7 +1791,7 @@ static struct notifier_block netconsole_netdev_notifier = {
* pool locks and is therefore not NMI-safe. Skip the refill when called
* from NMI context; the next non-NMI caller will top the pool back up.
*/
-static struct sk_buff *netcons_skb_pop(struct netpoll *np, int len)
+static struct sk_buff *netcons_skb_pop(struct netconsole_target *nt, int len)
{
struct sk_buff *skb;
@@ -1718,19 +1803,21 @@ static struct sk_buff *netcons_skb_pop(struct netpoll *np, int len)
if (!in_nmi())
net_warn_ratelimited("netconsole: dropping message, requested skb len %d exceeds pool buffer size %zu on %s\n",
len, (size_t)MAX_SKB_SIZE,
- np->dev->name);
+ nt->np.dev->name);
return NULL;
}
- skb = skb_dequeue(&np->skb_pool);
+ skb = skb_dequeue(&nt->skb_pool);
if (!in_nmi())
- schedule_work(&np->refill_wq);
+ schedule_work(&nt->refill_wq);
return skb;
}
-static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
+static struct sk_buff *find_skb(struct netconsole_target *nt, int len,
+ int reserve)
{
+ struct netpoll *np = &nt->np;
int count = 0;
struct sk_buff *skb;
@@ -1739,7 +1826,7 @@ static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
skb = alloc_skb(len, GFP_ATOMIC | __GFP_NOWARN);
if (!skb)
- skb = netcons_skb_pop(np, len);
+ skb = netcons_skb_pop(nt, len);
if (!skb) {
if (++count < 10) {
@@ -1779,8 +1866,9 @@ static void netpoll_udp_checksum(struct netpoll *np, struct sk_buff *skb,
udph->check = CSUM_MANGLED_0;
}
-static void push_udp(struct netpoll *np, struct sk_buff *skb, int len)
+static void push_udp(struct netconsole_target *nt, struct sk_buff *skb, int len)
{
+ struct netpoll *np = &nt->np;
struct udphdr *udph;
int udp_len;
@@ -1790,21 +1878,22 @@ static void push_udp(struct netpoll *np, struct sk_buff *skb, int len)
skb_reset_transport_header(skb);
udph = udp_hdr(skb);
- udph->source = htons(np->local_port);
- udph->dest = htons(np->remote_port);
+ udph->source = htons(nt->local_port);
+ udph->dest = htons(nt->remote_port);
udph->len = htons(udp_len);
netpoll_udp_checksum(np, skb, len);
}
-static void push_eth(struct netpoll *np, struct sk_buff *skb)
+static void push_eth(struct netconsole_target *nt, struct sk_buff *skb)
{
+ struct netpoll *np = &nt->np;
struct ethhdr *eth;
eth = skb_push(skb, ETH_HLEN);
skb_reset_mac_header(skb);
ether_addr_copy(eth->h_source, np->dev->dev_addr);
- ether_addr_copy(eth->h_dest, np->remote_mac);
+ ether_addr_copy(eth->h_dest, nt->remote_mac);
if (np->ipv6)
eth->h_proto = htons(ETH_P_IPV6);
else
@@ -1861,8 +1950,10 @@ static void push_ipv6(struct netpoll *np, struct sk_buff *skb, int len)
skb->protocol = htons(ETH_P_IPV6);
}
-static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)
+static int netpoll_send_udp(struct netconsole_target *nt, const char *msg,
+ int len)
{
+ struct netpoll *np = &nt->np;
int total_len, ip_len, udp_len;
struct sk_buff *skb;
@@ -1877,7 +1968,7 @@ static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)
total_len = ip_len + LL_RESERVED_SPACE(np->dev);
- skb = find_skb(np, total_len + np->dev->needed_tailroom,
+ skb = find_skb(nt, total_len + np->dev->needed_tailroom,
total_len - len);
if (!skb)
return -ENOMEM;
@@ -1885,12 +1976,12 @@ static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)
skb_copy_to_linear_data(skb, msg, len);
skb_put(skb, len);
- push_udp(np, skb, len);
+ push_udp(nt, skb, len);
if (np->ipv6)
push_ipv6(np, skb, len);
else
push_ipv4(np, skb, len);
- push_eth(np, skb);
+ push_eth(nt, skb);
skb->dev = np->dev;
return (int)netpoll_send_skb(np, skb);
@@ -1908,7 +1999,7 @@ static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)
*/
static void send_udp(struct netconsole_target *nt, const char *msg, int len)
{
- int result = netpoll_send_udp(&nt->np, msg, len);
+ int result = netpoll_send_udp(nt, msg, len);
if (IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC)) {
if (result == NET_XMIT_DROP) {
@@ -2203,8 +2294,9 @@ __releases(&target_list_lock)
spin_unlock_irqrestore(&target_list_lock, flags);
}
-static int netconsole_parser_cmdline(struct netpoll *np, char *opt)
+static int netconsole_parser_cmdline(struct netconsole_target *nt, char *opt)
{
+ struct netpoll *np = &nt->np;
bool ipversion_set = false;
char *cur = opt;
char *delim;
@@ -2215,7 +2307,7 @@ static int netconsole_parser_cmdline(struct netpoll *np, char *opt)
if (!delim)
goto parse_failed;
*delim = 0;
- if (kstrtou16(cur, 10, &np->local_port))
+ if (kstrtou16(cur, 10, &nt->local_port))
goto parse_failed;
cur = delim;
}
@@ -2262,7 +2354,7 @@ static int netconsole_parser_cmdline(struct netpoll *np, char *opt)
*delim = 0;
if (*cur == ' ' || *cur == '\t')
np_info(np, "warning: whitespace is not allowed\n");
- if (kstrtou16(cur, 10, &np->remote_port))
+ if (kstrtou16(cur, 10, &nt->remote_port))
goto parse_failed;
cur = delim;
}
@@ -2284,11 +2376,11 @@ static int netconsole_parser_cmdline(struct netpoll *np, char *opt)
if (*cur != 0) {
/* MAC address */
- if (!mac_pton(cur, np->remote_mac))
+ if (!mac_pton(cur, nt->remote_mac))
goto parse_failed;
}
- netconsole_print_banner(np);
+ netconsole_print_banner(nt);
return 0;
@@ -2326,14 +2418,22 @@ static struct netconsole_target *alloc_param_target(char *target_config,
}
/* Parse parameters and setup netpoll */
- err = netconsole_parser_cmdline(&nt->np, target_config);
+ err = netconsole_parser_cmdline(nt, target_config);
if (err)
goto fail;
+ /* Initialise the skb pool before netpoll_setup() so the pool is
+ * valid as soon as nt->np.dev becomes visible. The target is not
+ * yet on target_list, so a netdev event cannot reach it here, but
+ * mirror the configfs path for symmetry.
+ */
+ netconsole_skb_pool_init(nt);
+
err = netpoll_setup(&nt->np);
if (err) {
pr_err("Not enabling netconsole for %s%d. Netpoll setup failed\n",
NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count);
+ netconsole_skb_pool_flush(nt);
if (!IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC))
/* only fail if dynamic reconfiguration is set,
* otherwise, keep the target in the list, but disabled.
@@ -2355,6 +2455,8 @@ static struct netconsole_target *alloc_param_target(char *target_config,
static void free_param_target(struct netconsole_target *nt)
{
cancel_work_sync(&nt->resume_wq);
+ if (nt->state == STATE_ENABLED)
+ netconsole_skb_pool_flush(nt);
netpoll_cleanup(&nt->np);
#ifdef CONFIG_NETCONSOLE_DYNAMIC
kfree(nt->userdata);
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 88f7daa8560e58..79315461a7b1e0 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -21,20 +21,6 @@ union inet_addr {
struct in6_addr in6;
};
-/*
- * Maximum payload netpoll's preallocated skb pool can carry. Keep this in
- * sync with the buffer size used by refill_skbs() in net/core/netpoll.c;
- * callers (e.g. netconsole) use it to detect requests the pool can never
- * satisfy and avoid dequeuing a pooled skb that would later trip
- * skb_over_panic() in skb_put().
- */
-#define MAX_UDP_CHUNK 1460
-#define MAX_SKB_SIZE \
- (sizeof(struct ethhdr) + \
- sizeof(struct iphdr) + \
- sizeof(struct udphdr) + \
- MAX_UDP_CHUNK)
-
struct netpoll {
struct net_device *dev;
netdevice_tracker dev_tracker;
@@ -49,10 +35,6 @@ struct netpoll {
union inet_addr local_ip, remote_ip;
bool ipv6;
- u16 local_port, remote_port;
- u8 remote_mac[ETH_ALEN];
- struct sk_buff_head skb_pool;
- struct work_struct refill_wq;
};
#define np_info(np, fmt, ...) \
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 85aa5135088117..10b6063251a5bc 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -36,12 +36,6 @@
#include <trace/events/napi.h>
#include <linux/kconfig.h>
-/*
- * We maintain a small pool of fully-sized skbs, to make sure the
- * message gets out even in extreme OOM situations.
- */
-
-#define MAX_SKBS 32
#define USEC_PER_POLL 50
static unsigned int carrier_timeout = 4;
@@ -213,22 +207,6 @@ void netpoll_poll_enable(struct net_device *dev)
up(&ni->dev_lock);
}
-static void refill_skbs(struct netpoll *np)
-{
- struct sk_buff_head *skb_pool;
- struct sk_buff *skb;
-
- skb_pool = &np->skb_pool;
-
- while (READ_ONCE(skb_pool->qlen) < MAX_SKBS) {
- skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC | __GFP_NOWARN);
- if (!skb)
- break;
-
- skb_queue_tail(skb_pool, skb);
- }
-}
-
void netpoll_zap_completion_queue(void)
{
unsigned long flags;
@@ -351,32 +329,12 @@ netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
}
EXPORT_SYMBOL(netpoll_send_skb);
-static void skb_pool_flush(struct netpoll *np)
-{
- struct sk_buff_head *skb_pool;
-
- cancel_work_sync(&np->refill_wq);
- skb_pool = &np->skb_pool;
- skb_queue_purge_reason(skb_pool, SKB_CONSUMED);
-}
-
-static void refill_skbs_work_handler(struct work_struct *work)
-{
- struct netpoll *np =
- container_of(work, struct netpoll, refill_wq);
-
- refill_skbs(np);
-}
-
int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
{
struct netpoll_info *npinfo;
const struct net_device_ops *ops;
int err;
- skb_queue_head_init(&np->skb_pool);
- INIT_WORK(&np->refill_wq, refill_skbs_work_handler);
-
if (ndev->priv_flags & IFF_DISABLE_NETPOLL) {
np_err(np, "%s doesn't support polling, aborting\n",
ndev->name);
@@ -411,9 +369,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
np->dev = ndev;
strscpy(np->dev_name, ndev->name, IFNAMSIZ);
- /* fill up the skb queue */
- refill_skbs(np);
-
/* last thing to do is link it to the net device structure */
rcu_assign_pointer(ndev->npinfo, npinfo);
@@ -603,7 +558,7 @@ int netpoll_setup(struct netpoll *np)
err = __netpoll_setup(np, ndev);
if (err)
- goto flush;
+ goto put;
rtnl_unlock();
/* Make sure all NAPI polls which started before dev->npinfo
@@ -614,8 +569,6 @@ int netpoll_setup(struct netpoll *np)
return 0;
-flush:
- skb_pool_flush(np);
put:
DEBUG_NET_WARN_ON_ONCE(np->dev);
if (ip_overwritten)
@@ -666,8 +619,6 @@ static void __netpoll_cleanup(struct netpoll *np)
RCU_INIT_POINTER(np->dev->npinfo, NULL);
call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info);
}
-
- skb_pool_flush(np);
}
void __netpoll_free(struct netpoll *np)
|
| 3/2 | 2026/07/02 16:00 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 9752 output: 23 thoughts: 291 Thoughts: **Analyzing the Netconsole Patch for Fuzzing Potential** Okay, so I'm looking at this patch and my initial thought is: does this introduce functional changes significant enough to warrant fuzzing? It seems like it does. The patch is moving some key structures – `skb_pool`, `refill_wq`, `local_port`, `remote_port`, and `remote_mac` – from the `netpoll` structure to the `netconsole_target` structure. And it's updating the `netconsole.c` and `netpoll.c` files to reflect these changes. That's definitely a modification to how the netconsole driver, specifically its SKB management and core configuration, operates. The next thing I need to think about is reachability and testability. Netconsole, as I recall, is a driver designed for sending kernel log messages over UDP. It has configuration options through module parameters and, more interestingly, configfs. The files touched by the patch are `drivers/net/netconsole.c` and `net/core/netpoll.c`. Given that the patch modifies fundamental SKB allocation and UDP transmission logic in both the netconsole and netpoll components, it certainly *seems* worth fuzzing. I can imagine fuzzing the netconsole configuration through configfs or module parameters and then triggering kernel logs to exercise the changes. Wait a second… I think Syzkaller can actually interact with configfs, can't it? If that's the case, then this patch just jumped up in priority. Now I just need to double-check which kernel configs are relevant here. I'm pretty sure `CONFIG_NETCONSOLE` and `CONFIG_NETCONSOLE_DYNAMIC` are the keys, but let's quickly search the code to be absolutely sure. |
| 4/2 | 2026/07/02 16:01 | tool | grepper |
0mArgs:{
"Expression": "config NETCONSOLE",
"PathPrefix": ""
}Results: {
"Output": "drivers/net/Kconfig=318=config MACSEC\n--\ndrivers/net/Kconfig-326-\ndrivers/net/Kconfig:327:config NETCONSOLE\ndrivers/net/Kconfig-328-\ttristate \"Network console logging support\"\n--\ndrivers/net/Kconfig-333-\ndrivers/net/Kconfig:334:config NETCONSOLE_DYNAMIC\ndrivers/net/Kconfig-335-\tbool \"Dynamic reconfiguration of logging targets\"\n--\ndrivers/net/Kconfig-344-\ndrivers/net/Kconfig:345:config NETCONSOLE_EXTENDED_LOG\ndrivers/net/Kconfig-346-\tbool \"Set kernel extended message by default\"\n--\ndrivers/net/Kconfig-354-\ndrivers/net/Kconfig:355:config NETCONSOLE_PREPEND_RELEASE\ndrivers/net/Kconfig-356-\tbool \"Prepend kernel release version in the message by default\"\n"
} |
| 5/2 | 2026/07/02 16:01 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 10688 output: 24 thoughts: 871 Thoughts: **Analyzing the Netconsole Patch** Okay, so I'm looking at this patch and immediately I see the core configs in play are `NETCONSOLE` and `NETCONSOLE_DYNAMIC`. This is the first thing I'd check when auditing something like this. My initial thought is to identify which functions are being modified, and this is where I'd start digging. I've noted that the bulk of the changes appear within `drivers/net/netconsole.c`. I've listed out the modified functions, and a similar list for `net/core/netpoll.c`. I quickly see that we're talking about a significant refactoring - moving key functions like `refill_skbs`, `netconsole_skb_pool_flush` and `refill_skbs_work_handler` from the `netpoll` subsystem to `netconsole`. I'd expect some changes to `netpoll_setup` and `__netpoll_cleanup` too, and indeed there are. So, I've got a preliminary list of functions to focus on: those involved in buffer management (`netconsole_skb_pool_init`, `netconsole_skb_pool_flush`, `refill_skbs`, `netcons_skb_pop`, `find_skb`), the actual data transmission (`push_udp`, `push_eth`, `netpoll_send_udp`), the target configuration (`alloc_param_target`, `free_param_target`, `enabled_store`, `drop_netconsole_target`), and command-line parsing (`netconsole_parser_cmdline`). Next, I'll need to confirm that `netconsole` is reachable. Ah, right, through configfs. Given this functional shift of state from `netpoll` to `netconsole_target`, fuzzing this area seems worthwhile. I'd definitely want to explore the edge cases introduced by this move. Now, I'll refine my symbol list. It seems like a very good target list. Wait, I'm just noticing that most of these functions are static within `netconsole.c`. That is key information. This limits their direct external exposure. I'll need to see how they're used internally. Finally, I'll also want to consider what else depends on `netpoll` to make sure there are no unforeseen knock-on effects. I need to make sure I've identified all the modified functions. And while I see changes within `net/core/netpoll.c`, are there other callers? I need to check the entire `netpoll` subsystem. |
| 6/2 | 2026/07/02 16:01 | tool | grepper |
0mArgs:{
"Expression": "netpoll_setup",
"PathPrefix": ""
}Results: {
"Output": "drivers/net/bonding/bond_main.c=1392=static inline int slave_enable_netpoll(struct slave *slave)\n--\ndrivers/net/bonding/bond_main.c-1401-\ndrivers/net/bonding/bond_main.c:1402:\terr = __netpoll_setup(np, slave-\u003edev);\ndrivers/net/bonding/bond_main.c-1403-\tif (err) {\n--\ndrivers/net/bonding/bond_main.c=1451=static void bond_netpoll_cleanup(struct net_device *bond_dev)\n--\ndrivers/net/bonding/bond_main.c-1461-\ndrivers/net/bonding/bond_main.c:1462:static int bond_netpoll_setup(struct net_device *dev)\ndrivers/net/bonding/bond_main.c-1463-{\n--\ndrivers/net/bonding/bond_main.c=5949=static const struct net_device_ops bond_netdev_ops = {\n--\ndrivers/net/bonding/bond_main.c-5967-#ifdef CONFIG_NET_POLL_CONTROLLER\ndrivers/net/bonding/bond_main.c:5968:\t.ndo_netpoll_setup\t= bond_netpoll_setup,\ndrivers/net/bonding/bond_main.c-5969-\t.ndo_netpoll_cleanup\t= bond_netpoll_cleanup,\n--\ndrivers/net/macvlan.c=1130=static void macvlan_dev_poll_controller(struct net_device *dev)\n--\ndrivers/net/macvlan.c-1134-\ndrivers/net/macvlan.c:1135:static int macvlan_dev_netpoll_setup(struct net_device *dev)\ndrivers/net/macvlan.c-1136-{\n--\ndrivers/net/macvlan.c-1146-\ndrivers/net/macvlan.c:1147:\terr = __netpoll_setup(netpoll, real_dev);\ndrivers/net/macvlan.c-1148-\tif (err) {\n--\ndrivers/net/macvlan.c=1187=static const struct net_device_ops macvlan_netdev_ops = {\n--\ndrivers/net/macvlan.c-1206-\t.ndo_poll_controller\t= macvlan_dev_poll_controller,\ndrivers/net/macvlan.c:1207:\t.ndo_netpoll_setup\t= macvlan_dev_netpoll_setup,\ndrivers/net/macvlan.c-1208-\t.ndo_netpoll_cleanup\t= macvlan_dev_netpoll_cleanup,\n--\ndrivers/net/netconsole.c=145=enum target_state {\n--\ndrivers/net/netconsole.c-187- *\t\tits GFP_ATOMIC allocation fails. Lifetime brackets a\ndrivers/net/netconsole.c:188: *\t\tsuccessful netpoll_setup() / netpoll_cleanup() pair on @np.\ndrivers/net/netconsole.c-189- * @refill_wq:\tWork item that asynchronously tops @skb_pool back up to\n--\ndrivers/net/netconsole.c=357=static void resume_target(struct netconsole_target *nt)\ndrivers/net/netconsole.c-358-{\ndrivers/net/netconsole.c:359:\t/* Initialise the skb pool before netpoll_setup() makes nt-\u003enp.dev\ndrivers/net/netconsole.c-360-\t * visible to target_list walkers (e.g. netconsole_netdev_event),\n--\ndrivers/net/netconsole.c-365-\ndrivers/net/netconsole.c:366:\tif (netpoll_setup(\u0026nt-\u003enp)) {\ndrivers/net/netconsole.c-367-\t\t/* netpoll fails setup once, do not try again. */\n--\ndrivers/net/netconsole.c=390=static void process_resume_target(struct work_struct *work)\n--\ndrivers/net/netconsole.c-415-\ndrivers/net/netconsole.c:416:\t/* netpoll_setup() took a net_device reference and dropped the RTNL\ndrivers/net/netconsole.c-417-\t * before returning, all while this target was off target_list and\n--\ndrivers/net/netconsole.c=780=static ssize_t enabled_store(struct config_item *item,\n--\ndrivers/net/netconsole.c-833-\ndrivers/net/netconsole.c:834:\t\t/* Initialise the skb pool before netpoll_setup() so the pool\ndrivers/net/netconsole.c-835-\t\t * is valid as soon as nt-\u003enp.dev becomes visible to\n--\ndrivers/net/netconsole.c-841-\ndrivers/net/netconsole.c:842:\t\tret = netpoll_setup(\u0026nt-\u003enp);\ndrivers/net/netconsole.c-843-\t\tif (ret) {\n--\ndrivers/net/netconsole.c=2393=static struct netconsole_target *alloc_param_target(char *target_config,\n--\ndrivers/net/netconsole.c-2424-\ndrivers/net/netconsole.c:2425:\t/* Initialise the skb pool before netpoll_setup() so the pool is\ndrivers/net/netconsole.c-2426-\t * valid as soon as nt-\u003enp.dev becomes visible. The target is not\n--\ndrivers/net/netconsole.c-2431-\ndrivers/net/netconsole.c:2432:\terr = netpoll_setup(\u0026nt-\u003enp);\ndrivers/net/netconsole.c-2433-\tif (err) {\n--\ndrivers/net/team/team_core.c=1140=static int __team_port_enable_netpoll(struct team_port *port)\n--\ndrivers/net/team/team_core.c-1148-\ndrivers/net/team/team_core.c:1149:\terr = __netpoll_setup(np, port-\u003edev);\ndrivers/net/team/team_core.c-1150-\tif (err) {\n--\ndrivers/net/team/team_core.c=2078=static void team_netpoll_cleanup(struct net_device *dev)\n--\ndrivers/net/team/team_core.c-2086-\ndrivers/net/team/team_core.c:2087:static int team_netpoll_setup(struct net_device *dev)\ndrivers/net/team/team_core.c-2088-{\n--\ndrivers/net/team/team_core.c=2170=static const struct net_device_ops team_netdev_ops = {\n--\ndrivers/net/team/team_core.c-2185-\t.ndo_poll_controller\t= team_poll_controller,\ndrivers/net/team/team_core.c:2186:\t.ndo_netpoll_setup\t= team_netpoll_setup,\ndrivers/net/team/team_core.c-2187-\t.ndo_netpoll_cleanup\t= team_netpoll_cleanup,\n--\ninclude/linux/netdevice.h=1446=struct net_device_ops {\n--\ninclude/linux/netdevice.h-1504-\tvoid (*ndo_poll_controller)(struct net_device *dev);\ninclude/linux/netdevice.h:1505:\tint\t\t\t(*ndo_netpoll_setup)(struct net_device *dev);\ninclude/linux/netdevice.h-1506-\tvoid\t\t\t(*ndo_netpoll_cleanup)(struct net_device *dev);\n--\ninclude/linux/netpoll.h=65=static inline void netpoll_poll_enable(struct net_device *dev) { return; }\n--\ninclude/linux/netpoll.h-67-\ninclude/linux/netpoll.h:68:int __netpoll_setup(struct netpoll *np, struct net_device *ndev);\ninclude/linux/netpoll.h:69:int netpoll_setup(struct netpoll *np);\ninclude/linux/netpoll.h-70-void __netpoll_free(struct netpoll *np);\n--\nnet/8021q/vlan_dev.c=714=static void vlan_dev_poll_controller(struct net_device *dev)\n--\nnet/8021q/vlan_dev.c-718-\nnet/8021q/vlan_dev.c:719:static int vlan_dev_netpoll_setup(struct net_device *dev)\nnet/8021q/vlan_dev.c-720-{\n--\nnet/8021q/vlan_dev.c-730-\nnet/8021q/vlan_dev.c:731:\terr = __netpoll_setup(netpoll, real_dev);\nnet/8021q/vlan_dev.c-732-\tif (err) {\n--\nnet/8021q/vlan_dev.c=1078=static const struct net_device_ops vlan_netdev_ops = {\n--\nnet/8021q/vlan_dev.c-1104-\t.ndo_poll_controller\t= vlan_dev_poll_controller,\nnet/8021q/vlan_dev.c:1105:\t.ndo_netpoll_setup\t= vlan_dev_netpoll_setup,\nnet/8021q/vlan_dev.c-1106-\t.ndo_netpoll_cleanup\t= vlan_dev_netpoll_cleanup,\n--\nnet/bridge/br_device.c=306=static int __br_netpoll_enable(struct net_bridge_port *p)\n--\nnet/bridge/br_device.c-314-\nnet/bridge/br_device.c:315:\terr = __netpoll_setup(np, p-\u003edev);\nnet/bridge/br_device.c-316-\tif (err) {\n--\nnet/bridge/br_device.c=325=int br_netpoll_enable(struct net_bridge_port *p)\n--\nnet/bridge/br_device.c-332-\nnet/bridge/br_device.c:333:static int br_netpoll_setup(struct net_device *dev)\nnet/bridge/br_device.c-334-{\n--\nnet/bridge/br_device.c=439=static const struct net_device_ops br_netdev_ops = {\n--\nnet/bridge/br_device.c-451-#ifdef CONFIG_NET_POLL_CONTROLLER\nnet/bridge/br_device.c:452:\t.ndo_netpoll_setup\t = br_netpoll_setup,\nnet/bridge/br_device.c-453-\t.ndo_netpoll_cleanup\t = br_netpoll_cleanup,\n--\nnet/core/netpoll.c=330=EXPORT_SYMBOL(netpoll_send_skb);\nnet/core/netpoll.c-331-\nnet/core/netpoll.c:332:int __netpoll_setup(struct netpoll *np, struct net_device *ndev)\nnet/core/netpoll.c-333-{\n--\nnet/core/netpoll.c-359-\t\tops = ndev-\u003enetdev_ops;\nnet/core/netpoll.c:360:\t\tif (ops-\u003endo_netpoll_setup) {\nnet/core/netpoll.c:361:\t\t\terr = ops-\u003endo_netpoll_setup(ndev);\nnet/core/netpoll.c-362-\t\t\tif (err)\n--\nnet/core/netpoll.c-381-}\nnet/core/netpoll.c:382:EXPORT_SYMBOL_GPL(__netpoll_setup);\nnet/core/netpoll.c-383-\n--\nnet/core/netpoll.c=459=static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev)\n--\nnet/core/netpoll.c-486- * Test whether the caller left np-\u003elocal_ip unset, so that\nnet/core/netpoll.c:487: * netpoll_setup() should auto-populate it from the egress device.\nnet/core/netpoll.c-488- *\n--\nnet/core/netpoll.c=495=static bool netpoll_local_ip_unset(const struct netpoll *np)\n--\nnet/core/netpoll.c-501-\nnet/core/netpoll.c:502:int netpoll_setup(struct netpoll *np)\nnet/core/netpoll.c-503-{\n--\nnet/core/netpoll.c-558-\nnet/core/netpoll.c:559:\terr = __netpoll_setup(np, ndev);\nnet/core/netpoll.c-560-\tif (err)\n--\nnet/core/netpoll.c-580-}\nnet/core/netpoll.c:581:EXPORT_SYMBOL(netpoll_setup);\nnet/core/netpoll.c-582-\n--\nnet/dsa/user.c=1305=static int dsa_user_set_pauseparam(struct net_device *dev,\n--\nnet/dsa/user.c-1313-#ifdef CONFIG_NET_POLL_CONTROLLER\nnet/dsa/user.c:1314:static int dsa_user_netpoll_setup(struct net_device *dev)\nnet/dsa/user.c-1315-{\n--\nnet/dsa/user.c-1324-\nnet/dsa/user.c:1325:\terr = __netpoll_setup(netpoll, conduit);\nnet/dsa/user.c-1326-\tif (err) {\n--\nnet/dsa/user.c=2587=static const struct net_device_ops dsa_user_netdev_ops = {\n--\nnet/dsa/user.c-2597-#ifdef CONFIG_NET_POLL_CONTROLLER\nnet/dsa/user.c:2598:\t.ndo_netpoll_setup\t= dsa_user_netpoll_setup,\nnet/dsa/user.c-2599-\t.ndo_netpoll_cleanup\t= dsa_user_netpoll_cleanup,\n"
} |
| 7/2 | 2026/07/02 16:01 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15792 output: 26 thoughts: 189 Thoughts: **Analyzing the Implications of the Network Console Patch** Okay, so this patch is specifically targeting `netconsole` and `netpoll`. The `netpoll` modifications are the core of my concern. Specifically, they're removing the `skb_pool` and `refill_wq` from the `struct netpoll` and then ripping out the associated `refill_skbs` and `skb_pool_flush` calls from `netpoll_setup` and `__netpoll_cleanup`, respectively. The immediate consequence that jumps out is the impact on all *other* users of `netpoll`. I mean, think about it: `bond_main.c`, `macvlan.c`, `team_core.c`, `vlan_dev.c`, `br_device.c`, and even `dsa/user.c` – they're all relying on some form of `netpoll` structure. And now, they're *not* going to have an `skb_pool` available to them in their `netpoll` instances. That's a significant architectural shift, a bit unsettling. Hmm, this raises a crucial question. Are these other users of `netpoll` even utilizing `netpoll_send_udp`? If they aren't, then maybe this isn't such a big deal. The absence of the `skb_pool` might not have an immediate functional impact. But the implications of a shared resource removed cannot be ignored and, in this case, needs immediate investigation. Let's see where that function is actually used. Need to double-check that this doesn't introduce unintended consequences. |
| 8/2 | 2026/07/02 16:01 | tool | grepper |
0mArgs:{
"Expression": "netpoll_send_udp",
"PathPrefix": ""
}Results: {
"Output": "drivers/net/netconsole.c=1930=static void push_ipv6(struct netpoll *np, struct sk_buff *skb, int len)\n--\ndrivers/net/netconsole.c-1952-\ndrivers/net/netconsole.c:1953:static int netpoll_send_udp(struct netconsole_target *nt, const char *msg,\ndrivers/net/netconsole.c-1954-\t\t\t int len)\n--\ndrivers/net/netconsole.c-1990-/**\ndrivers/net/netconsole.c:1991: * send_udp - Wrapper for netpoll_send_udp that counts errors\ndrivers/net/netconsole.c-1992- * @nt: target to send message to\n--\ndrivers/net/netconsole.c-1995- *\ndrivers/net/netconsole.c:1996: * Calls netpoll_send_udp and classifies the return value. If an error\ndrivers/net/netconsole.c-1997- * occurred it increments statistics in nt-\u003estats accordingly.\ndrivers/net/netconsole.c:1998: * Only calls netpoll_send_udp if CONFIG_NETCONSOLE_DYNAMIC is disabled.\ndrivers/net/netconsole.c-1999- */\ndrivers/net/netconsole.c=2000=static void send_udp(struct netconsole_target *nt, const char *msg, int len)\ndrivers/net/netconsole.c-2001-{\ndrivers/net/netconsole.c:2002:\tint result = netpoll_send_udp(nt, msg, len);\ndrivers/net/netconsole.c-2003-\n"
} |
| 9/2 | 2026/07/02 16:01 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 16781 output: 27 thoughts: 70 Thoughts: Here's my thought process, as requested: **Investigating Netconsole UDP Transmission** Okay, so I'm looking at how `netconsole` handles UDP transmission. My initial observation is that `netpoll_send_udp` is statically declared within `drivers/net/netconsole.c`. That's interesting, suggesting it's tightly bound to that specific module. Then I remember that `netpoll_send_skb` is, in fact, exported from `net/core/netpoll.c`. That's the more general networking component, and I'd expect that the more general send function `netpoll_send_skb` may have broader applicability than the static netconsole function. Now, I need to understand if `netpoll_send_skb` is responsible for allocating or interacting with `skb_pool`. That will be an important indicator of memory allocation, efficiency, and overall architecture. I need to dig deeper into the call graph there. |
| 10/2 | 2026/07/02 16:01 | tool | grepper |
0mArgs:{
"Expression": "netpoll_send_skb",
"PathPrefix": ""
}Results: {
"Output": "drivers/net/bonding/bond_main.c=297=netdev_tx_t bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,\n--\ndrivers/net/bonding/bond_main.c-306-\tif (unlikely(netpoll_tx_running(bond-\u003edev)))\ndrivers/net/bonding/bond_main.c:307:\t\treturn bond_netpoll_send_skb(bond_get_slave_by_dev(bond, slave_dev), skb);\ndrivers/net/bonding/bond_main.c-308-\n--\ndrivers/net/macvlan.c=545=static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)\n--\ndrivers/net/macvlan.c-574-\ndrivers/net/macvlan.c:575:static inline netdev_tx_t macvlan_netpoll_send_skb(struct macvlan_dev *vlan, struct sk_buff *skb)\ndrivers/net/macvlan.c-576-{\ndrivers/net/macvlan.c-577-#ifdef CONFIG_NET_POLL_CONTROLLER\ndrivers/net/macvlan.c:578:\treturn netpoll_send_skb(vlan-\u003enetpoll, skb);\ndrivers/net/macvlan.c-579-#else\n--\ndrivers/net/macvlan.c=585=static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,\n--\ndrivers/net/macvlan.c-592-\tif (unlikely(netpoll_tx_running(dev)))\ndrivers/net/macvlan.c:593:\t\treturn macvlan_netpoll_send_skb(vlan, skb);\ndrivers/net/macvlan.c-594-\n--\ndrivers/net/netconsole.c=1953=static int netpoll_send_udp(struct netconsole_target *nt, const char *msg,\n--\ndrivers/net/netconsole.c-1986-\ndrivers/net/netconsole.c:1987:\treturn (int)netpoll_send_skb(np, skb);\ndrivers/net/netconsole.c-1988-}\n--\ninclude/linux/if_team.h=99=static inline bool team_port_dev_txable(const struct net_device *port_dev)\n--\ninclude/linux/if_team.h-112-#ifdef CONFIG_NET_POLL_CONTROLLER\ninclude/linux/if_team.h:113:static inline void team_netpoll_send_skb(struct team_port *port,\ninclude/linux/if_team.h-114-\t\t\t\t\t struct sk_buff *skb)\ninclude/linux/if_team.h-115-{\ninclude/linux/if_team.h:116:\tnetpoll_send_skb(port-\u003enp, skb);\ninclude/linux/if_team.h-117-}\ninclude/linux/if_team.h-118-#else\ninclude/linux/if_team.h:119:static inline void team_netpoll_send_skb(struct team_port *port,\ninclude/linux/if_team.h-120-\t\t\t\t\t struct sk_buff *skb)\n--\ninclude/linux/if_team.h=237=static inline int team_dev_queue_xmit(struct team *team, struct team_port *port,\n--\ninclude/linux/if_team.h-245-\tif (unlikely(netpoll_tx_running(netdev_from_priv(team)))) {\ninclude/linux/if_team.h:246:\t\tteam_netpoll_send_skb(port, skb);\ninclude/linux/if_team.h-247-\t\treturn 0;\n--\ninclude/linux/netpoll.h=72=void do_netpoll_cleanup(struct netpoll *np);\ninclude/linux/netpoll.h:73:netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);\ninclude/linux/netpoll.h-74-void netpoll_zap_completion_queue(void);\n--\ninclude/net/bonding.h=548=static inline unsigned long slave_last_tx(struct slave *slave)\n--\ninclude/net/bonding.h-553-#ifdef CONFIG_NET_POLL_CONTROLLER\ninclude/net/bonding.h:554:static inline netdev_tx_t bond_netpoll_send_skb(const struct slave *slave,\ninclude/net/bonding.h-555-\t\t\t\t\t struct sk_buff *skb)\ninclude/net/bonding.h-556-{\ninclude/net/bonding.h:557:\treturn netpoll_send_skb(slave-\u003enp, skb);\ninclude/net/bonding.h-558-}\ninclude/net/bonding.h-559-#else\ninclude/net/bonding.h:560:static inline netdev_tx_t bond_netpoll_send_skb(const struct slave *slave,\ninclude/net/bonding.h-561-\t\t\t\t\t struct sk_buff *skb)\n--\nnet/8021q/vlan_dev.c=46=static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,\n--\nnet/8021q/vlan_dev.c-89-\nnet/8021q/vlan_dev.c:90:static inline netdev_tx_t vlan_netpoll_send_skb(struct vlan_dev_priv *vlan, struct sk_buff *skb)\nnet/8021q/vlan_dev.c-91-{\nnet/8021q/vlan_dev.c-92-#ifdef CONFIG_NET_POLL_CONTROLLER\nnet/8021q/vlan_dev.c:93:\treturn netpoll_send_skb(vlan-\u003enetpoll, skb);\nnet/8021q/vlan_dev.c-94-#else\n--\nnet/8021q/vlan_dev.c=100=static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,\n--\nnet/8021q/vlan_dev.c-123-\tif (unlikely(netpoll_tx_running(dev)))\nnet/8021q/vlan_dev.c:124:\t\treturn vlan_netpoll_send_skb(vlan, skb);\nnet/8021q/vlan_dev.c-125-\n--\nnet/bridge/br_forward.c=73=static void __br_forward(const struct net_bridge_port *to,\n--\nnet/bridge/br_forward.c-106-\t\t\telse\nnet/bridge/br_forward.c:107:\t\t\t\tbr_netpoll_send_skb(to, skb);\nnet/bridge/br_forward.c-108-\t\t\treturn;\n--\nnet/bridge/br_private.h=809=netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev);\nnet/bridge/br_private.h-810-#ifdef CONFIG_NET_POLL_CONTROLLER\nnet/bridge/br_private.h:811:static inline void br_netpoll_send_skb(const struct net_bridge_port *p,\nnet/bridge/br_private.h-812-\t\t\t\t struct sk_buff *skb)\nnet/bridge/br_private.h-813-{\nnet/bridge/br_private.h:814:\tnetpoll_send_skb(p-\u003enp, skb);\nnet/bridge/br_private.h-815-}\n--\nnet/bridge/br_private.h=818=void br_netpoll_disable(struct net_bridge_port *p);\nnet/bridge/br_private.h-819-#else\nnet/bridge/br_private.h:820:static inline void br_netpoll_send_skb(const struct net_bridge_port *p,\nnet/bridge/br_private.h-821-\t\t\t\t struct sk_buff *skb)\n--\nnet/core/netpoll.c=239=static int netpoll_owner_active(struct net_device *dev)\n--\nnet/core/netpoll.c-250-/* call with IRQ disabled */\nnet/core/netpoll.c:251:static netdev_tx_t __netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)\nnet/core/netpoll.c-252-{\n--\nnet/core/netpoll.c-299-\t\tWARN_ONCE(!irqs_disabled(),\nnet/core/netpoll.c:300:\t\t\t\"netpoll_send_skb_on_dev(): %s enabled interrupts in poll (%pS)\\n\",\nnet/core/netpoll.c-301-\t\t\tdev-\u003ename, dev-\u003enetdev_ops-\u003endo_start_xmit);\n--\nnet/core/netpoll.c-314-\nnet/core/netpoll.c:315:netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)\nnet/core/netpoll.c-316-{\n--\nnet/core/netpoll.c-324-\t\tlocal_irq_save(flags);\nnet/core/netpoll.c:325:\t\tret = __netpoll_send_skb(np, skb);\nnet/core/netpoll.c-326-\t\tlocal_irq_restore(flags);\n--\nnet/core/netpoll.c-329-}\nnet/core/netpoll.c:330:EXPORT_SYMBOL(netpoll_send_skb);\nnet/core/netpoll.c-331-\n--\nnet/dsa/user.c=819=static int dsa_user_port_obj_del(struct net_device *dev, const void *ctx,\n--\nnet/dsa/user.c-867-\nnet/dsa/user.c:868:static netdev_tx_t dsa_user_netpoll_send_skb(struct net_device *dev,\nnet/dsa/user.c-869-\t\t\t\t\t struct sk_buff *skb)\n--\nnet/dsa/user.c-873-\nnet/dsa/user.c:874:\treturn netpoll_send_skb(p-\u003enetpoll, skb);\nnet/dsa/user.c-875-#else\n--\nnet/dsa/user.c=895=netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev)\n--\nnet/dsa/user.c-900-\tif (unlikely(netpoll_tx_running(dev)))\nnet/dsa/user.c:901:\t\treturn dsa_user_netpoll_send_skb(dev, skb);\nnet/dsa/user.c-902-\n"
} |
| 11/2 | 2026/07/02 16:01 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 19918 output: 242 thoughts: 1185 Thoughts: **Analysis of Netconsole and Netpoll Patch for Fuzzing** Okay, so I'm looking at this patch and immediately, the implications for fuzzing jump out. My initial thought was that `netpoll_send_skb` looked like a central point, considering its use by various drivers. However, upon closer inspection, I see that it's *not* the primary function handling SKB allocation or pool management. It's just a transmitter. The key lies in `netpoll_send_udp`, which, as the diff clearly shows, was already static and is now moved into the `netconsole_target` struct, along with the `skb_pool` and associated functions like `find_skb` and `netcons_skb_pop`. This is important because it shifts the resource management specifically to `netconsole.c`. Effectively, the patch is reorganizing the data structures, moving the SKB pool and related functions from the general `netpoll` context to a more specific `netconsole_target` context. This makes perfect sense; the SKB pool is *only* used by `netconsole`. This is a functional change, not just a cosmetic one. Given this, I believe this is definitely worth fuzzing, particularly focusing on the `netconsole` configuration and usage. The most relevant symbols to target are the ones related to SKB pool management, sending the UDP datagrams, target setup/cleanup, and configuration parsing. My initial list of focus symbols includes a comprehensive range of potential entry points and relevant functions: * `netconsole_skb_pool_init` * `netconsole_skb_pool_flush` * `refill_skbs` & `refill_skbs_work_handler` * `netcons_skb_pop` * `find_skb` * `push_udp` * `push_eth` * `netpoll_send_udp` & `send_udp` * `resume_target` * `process_resume_target` * `alloc_and_init` * `netconsole_process_cleanups_core` * `netconsole_print_banner` * `enabled_store` * `drop_netconsole_target` * `netconsole_parser_cmdline` * `alloc_param_target` * `free_param_target` * `__netpoll_setup` * `netpoll_setup` * `__netpoll_cleanup` After some further refinement, and to avoid including too many generic functions, I will pare the list down to these key functions: * `netconsole_skb_pool_init` * `netconsole_skb_pool_flush` * `refill_skbs` * `netcons_skb_pop` * `find_skb` * `netpoll_send_udp` * `enabled_store` * `drop_netconsole_target` * `alloc_param_target` * `free_param_target` * `netconsole_parser_cmdline` * `__netpoll_setup` * `netpoll_setup` * `__netpoll_cleanup` The relevant kernel configurations to enable will be `NETCONSOLE` and `NETCONSOLE_DYNAMIC`. These are the core dependencies for exercising this code. To recap, the patch moves SKB pool management and target configurations from `struct netpoll` to `struct netconsole_target`, modifies initialization and flushing and the netpoll setup/cleanup paths. Thus, fuzzing should concentrate on the interaction between configuration, resource management (SKB pool), and the sending of UDP datagrams. The primary targets are within `drivers/net/netconsole.c` but `net/core/netpoll.c` needs to be considered. |
| 12/2 | 2026/07/02 16:01 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"NETCONSOLE",
"NETCONSOLE_DYNAMIC"
],
"FocusSymbols": [
"netconsole_skb_pool_init",
"netconsole_skb_pool_flush",
"refill_skbs",
"netcons_skb_pop",
"find_skb",
"netpoll_send_udp",
"enabled_store",
"drop_netconsole_target",
"alloc_param_target",
"free_param_target",
"netconsole_parser_cmdline",
"__netpoll_setup",
"netpoll_setup",
"__netpoll_cleanup"
],
"Reasoning": "The patch moves the SKB pool and target configuration (ports, MAC) from `struct netpoll` to `struct netconsole_target`. It modifies how netconsole initializes and flushes the SKB pool, and updates the netpoll setup/cleanup paths. This is a functional change to the netconsole driver and netpoll core, which can be reached via configfs or module parameters.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"NETCONSOLE",
"NETCONSOLE_DYNAMIC"
],
"FocusSymbols": [
"netconsole_skb_pool_init",
"netconsole_skb_pool_flush",
"refill_skbs",
"netcons_skb_pop",
"find_skb",
"netpoll_send_udp",
"enabled_store",
"drop_netconsole_target",
"alloc_param_target",
"free_param_target",
"netconsole_parser_cmdline",
"__netpoll_setup",
"netpoll_setup",
"__netpoll_cleanup"
],
"Reasoning": "The patch moves the SKB pool and target configuration (ports, MAC) from `struct netpoll` to `struct netconsole_target`. It modifies how netconsole initializes and flushes the SKB pool, and updates the netpoll setup/cleanup paths. This is a functional change to the netconsole driver and netpoll core, which can be reached via configfs or module parameters.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|