| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/08/12 02:23 | flow | patch-triage |
3mArgs:null Results: {
"EnableConfigs": [
"TUN",
"BRIDGE",
"OPENVSWITCH"
],
"FocusSymbols": [
"tun_set_headroom",
"tun_get_user",
"tun_chr_write_iter",
"tun_sendmsg"
],
"KMSANReasoning": "The patch addresses out-of-bounds accesses and integer overflows. Specifically, it clamps the maximum headroom in `tun_set_headroom` to prevent potential integer overflows or out-of-bounds allocations, and it adds/modifies `pskb_may_pull` checks in `tun_get_user` to ensure that packet headers are safely accessible in the linear portion of the socket buffer before reading them. These are classic memory safety issues (out-of-bounds reads/writes) that are effectively detected by KASAN and UBSAN. There is no introduction or exposure of uninitialized memory (such as uninitialized stack/heap variables or info-leaks to user space) that would require KMSAN.",
"NeedsKMSAN": false,
"Reasoning": "The patch modifies headroom calculation in `tun_set_headroom` and adds packet header pull checks in `tun_get_user` for TUN/TAP devices. These functions are reachable via `write()` or `sendmsg()` to the TUN device, and via bridge or Open vSwitch attaching the TUN device (which triggers `ndo_set_rx_headroom`). These are functional changes to packet processing and device configuration that should be fuzzed.",
"WorthFuzzing": true
} |
| 1/1 | 2026/08/12 02:23 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit c0ddcfaeac32ee654a2a1a7fed12a11c3ab1b912\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Wed Aug 12 02:23:12 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/tun.c b/drivers/net/tun.c\nindex fed9dfdfcc3bc..5bbe3123979e0 100644\n--- a/drivers/net/tun.c\n+++ b/drivers/net/tun.c\n@@ -1107,11 +1107,16 @@ static netdev_features_t tun_net_fix_features(struct net_device *dev,\n static void tun_set_headroom(struct net_device *dev, int new_hr)\n {\n \tstruct tun_struct *tun = netdev_priv(dev);\n+\tsize_t max_headroom;\n \n-\tif (new_hr \u003c NET_SKB_PAD)\n-\t\tnew_hr = NET_SKB_PAD;\n+\tmax_headroom = min_t(size_t, SKB_MAX_HEAD(0), U16_MAX - 1);\n \n-\ttun-\u003ealign = new_hr;\n+\tif ((tun-\u003eflags \u0026 TUN_TYPE_MASK) == IFF_TAP)\n+\t\tmax_headroom -= ETH_HLEN + NET_IP_ALIGN;\n+\telse\n+\t\tmax_headroom -= 1;\n+\n+\ttun-\u003ealign = clamp_t(int, new_hr, NET_SKB_PAD, max_headroom);\n }\n \n static void\n@@ -1822,7 +1827,13 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,\n \tswitch (tun-\u003eflags \u0026 TUN_TYPE_MASK) {\n \tcase IFF_TUN:\n \t\tif (tun-\u003eflags \u0026 IFF_NO_PI) {\n-\t\t\tu8 ip_version = skb-\u003elen ? (skb-\u003edata[0] \u003e\u003e 4) : 0;\n+\t\t\tu8 ip_version;\n+\n+\t\t\tif (!pskb_may_pull(skb, 1)) {\n+\t\t\t\terr = -EINVAL;\n+\t\t\t\tgoto drop;\n+\t\t\t}\n+\t\t\tip_version = skb-\u003edata[0] \u003e\u003e 4;\n \n \t\t\tswitch (ip_version) {\n \t\t\tcase 4:\n@@ -1842,7 +1853,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,\n \t\tskb-\u003edev = tun-\u003edev;\n \t\tbreak;\n \tcase IFF_TAP:\n-\t\tif (frags \u0026\u0026 !pskb_may_pull(skb, ETH_HLEN)) {\n+\t\tif (!pskb_may_pull(skb, ETH_HLEN)) {\n \t\t\terr = -ENOMEM;\n \t\t\tdrop_reason = SKB_DROP_REASON_HDR_TRUNC;\n \t\t\tgoto drop;\n"
} |
| 2/1 | 2026/08/12 02:23 | agent | patch-evaluator |
3mModel:best-expensive Args: null Results: {
"EnableConfigs": [
"TUN",
"BRIDGE",
"OPENVSWITCH"
],
"FocusSymbols": [
"tun_set_headroom",
"tun_get_user",
"tun_chr_write_iter",
"tun_sendmsg"
],
"Reasoning": "The patch modifies headroom calculation in `tun_set_headroom` and adds packet header pull checks in `tun_get_user` for TUN/TAP devices. These functions are reachable via `write()` or `sendmsg()` to the TUN device, and via bridge or Open vSwitch attaching the TUN device (which triggers `ndo_set_rx_headroom`). These are functional changes to packet processing and device configuration that should be fuzzed.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). - Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed, ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU. - Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove) that are executed only during PCI hot-unplug or sysfs driver unbind operations. If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. Prefer non-static, non-inlined API entrypoint functions over internal static helper functions (which are inlined by the compiler and do not have distinct symbol addresses). 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit c0ddcfaeac32ee654a2a1a7fed12a11c3ab1b912
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Aug 12 02:23:12 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index fed9dfdfcc3bc..5bbe3123979e0 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1107,11 +1107,16 @@ static netdev_features_t tun_net_fix_features(struct net_device *dev,
static void tun_set_headroom(struct net_device *dev, int new_hr)
{
struct tun_struct *tun = netdev_priv(dev);
+ size_t max_headroom;
- if (new_hr < NET_SKB_PAD)
- new_hr = NET_SKB_PAD;
+ max_headroom = min_t(size_t, SKB_MAX_HEAD(0), U16_MAX - 1);
- tun->align = new_hr;
+ if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP)
+ max_headroom -= ETH_HLEN + NET_IP_ALIGN;
+ else
+ max_headroom -= 1;
+
+ tun->align = clamp_t(int, new_hr, NET_SKB_PAD, max_headroom);
}
static void
@@ -1822,7 +1827,13 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
switch (tun->flags & TUN_TYPE_MASK) {
case IFF_TUN:
if (tun->flags & IFF_NO_PI) {
- u8 ip_version = skb->len ? (skb->data[0] >> 4) : 0;
+ u8 ip_version;
+
+ if (!pskb_may_pull(skb, 1)) {
+ err = -EINVAL;
+ goto drop;
+ }
+ ip_version = skb->data[0] >> 4;
switch (ip_version) {
case 4:
@@ -1842,7 +1853,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
skb->dev = tun->dev;
break;
case IFF_TAP:
- if (frags && !pskb_may_pull(skb, ETH_HLEN)) {
+ if (!pskb_may_pull(skb, ETH_HLEN)) {
err = -ENOMEM;
drop_reason = SKB_DROP_REASON_HDR_TRUNC;
goto drop;
|
| 3/2 | 2026/08/12 02:23 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 2464 output: 33 thoughts: 564 Thoughts: **Analyzing the TUN/TAP Driver Patch** Okay, so I'm looking at a patch that's making some functional changes to the TUN/TAP driver, specifically within `drivers/net/tun.c`. The core modifications are focused on `tun_set_headroom` and `tun_get_user`. This suggests they are addressing potential issues related to headroom management and data retrieval. Let's dive into `tun_set_headroom`. It looks like the change is replacing a simple minimum check with a more robust clamping mechanism. Instead of just ensuring `new_hr` is at least `NET_SKB_PAD`, it now calculates a `max_headroom` based on `SKB_MAX_HEAD`, `U16_MAX`, and adjusts it depending on whether it's a TAP interface (subtracting `ETH_HLEN + NET_IP_ALIGN`) or TUN interface. It then clamps `new_hr` between `NET_SKB_PAD` and this calculated `max_headroom`. This suggests they're aiming to prevent out-of-bounds access or excessive headroom allocation, especially considering the constraints of different interface types. This clamping is much more sensible. Moving to `tun_get_user`, which is called from `tun_chr_write_iter`, I see changes related to handling both TUN and TAP interfaces in the IFF_NO_PI case. In the TUN case, there's now a check using `pskb_may_pull` to ensure that there's at least one byte available to read the IP version. This looks like a necessary sanity check, and preventing an out-of-bounds read is always a good thing. In the TAP case, the `pskb_may_pull` check is applied unconditionally before reading the Ethernet header, which seems like a much stronger check. If it fails, the packet is dropped with `SKB_DROP_REASON_HDR_TRUNC`. Again, this prevents possible reads beyond the bounds of the SKB, which is critical. So, in summary, these changes appear to be aimed at fixing potential vulnerabilities or data corruption issues related to headroom and data access in the TUN/TAP driver. The code now clamps the headroom and performs better bounds checking. I'll need to confirm exactly how `tun_set_headroom` is being called, but the direction here is good and points to fixing some significant reliability issues. |
| 4/2 | 2026/08/12 02:23 | tool | grepper |
0mArgs:{
"Expression": "tun_set_headroom",
"PathPrefix": "drivers/net/tun.c"
}Results: {
"Output": "drivers/net/tun.c=1099=static netdev_features_t tun_net_fix_features(struct net_device *dev,\n--\ndrivers/net/tun.c-1106-\ndrivers/net/tun.c:1107:static void tun_set_headroom(struct net_device *dev, int new_hr)\ndrivers/net/tun.c-1108-{\n--\ndrivers/net/tun.c=1188=static const struct net_device_ops tun_netdev_ops = {\n--\ndrivers/net/tun.c-1195-\t.ndo_select_queue\t= tun_select_queue,\ndrivers/net/tun.c:1196:\t.ndo_set_rx_headroom\t= tun_set_headroom,\ndrivers/net/tun.c-1197-\t.ndo_get_stats64\t= tun_net_get_stats64,\n--\ndrivers/net/tun.c=1272=static const struct net_device_ops tap_netdev_ops = {\n--\ndrivers/net/tun.c-1283-\t.ndo_features_check\t= passthru_features_check,\ndrivers/net/tun.c:1284:\t.ndo_set_rx_headroom\t= tun_set_headroom,\ndrivers/net/tun.c-1285-\t.ndo_bpf\t\t= tun_xdp,\n"
} |
| 5/2 | 2026/08/12 02:23 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 3378 output: 28 thoughts: 116 Thoughts: **Analyzing the TUN/TAP Driver Patch** Okay, so this patch is touching `tun_set_headroom` and `tun_get_user` within `drivers/net/tun.c`. Interesting. Specifically, `tun_set_headroom` is getting a clamp, presumably to ensure the headroom doesn't exceed some sane maximum. Makes sense, could prevent overflow issues. And then `tun_get_user` is seeing some `pskb_may_pull` checks being added. Right, that's important for ensuring we're not trying to pull data from a packet buffer that doesn't actually exist, or that we don't have permission to access. These are pretty standard defensive programming techniques. This is a functional change in a reachable driver, that's good. Which means, it's something I can absolutely fuzz. The TUN/TAP driver is a prime target for fuzzing anyway. Both `tun_set_headroom` and `tun_get_user` now need to be subjected to intense scrutiny. Let's see what the Kconfig looks like for `drivers/net/tun.c` to confirm my fuzzing strategy. |
| 6/2 | 2026/08/12 02:23 | tool | grepper |
0mArgs:{
"Expression": "config TUN",
"PathPrefix": "drivers/net/Kconfig"
}Results: {
"Output": "drivers/net/Kconfig=386=config RIONET_RX_SIZE\n--\ndrivers/net/Kconfig-390-\ndrivers/net/Kconfig:391:config TUN\ndrivers/net/Kconfig-392-\ttristate \"Universal TUN/TAP device driver support\"\n--\ndrivers/net/Kconfig=415=config TAP\n--\ndrivers/net/Kconfig-420-\ndrivers/net/Kconfig:421:config TUN_VNET_CROSS_LE\ndrivers/net/Kconfig-422-\tbool \"Support for cross-endian vnet headers on little-endian kernels\"\n"
} |
| 7/2 | 2026/08/12 02:23 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 4498 output: 28 thoughts: 126 Thoughts: **Analyzing the TUN Configuration** Okay, so I'm looking at this `TUN` configuration and need to figure out the right functions to interact with it. The guidance is pointing me towards `tun_set_headroom` and `tun_get_user` as key areas to examine. Hmm, hang on a second. It looks like `tun_set_headroom` is actually declared as `static`. That's a bit of a red flag, because the instructions specifically say to prefer non-static, non-inlined API entrypoints over internal helper functions. Wait a minute, although it's static, it *is* assigned to `.ndo_set_rx_headroom`. So, there's a reason it's used. The question now is, is there a non-static wrapper function that calls it? I need to understand the full context. I'll check where `.ndo_set_rx_headroom` is actually used and see if that reveals a more suitable entry point. |
| 8/2 | 2026/08/12 02:24 | tool | grepper |
0mArgs:{
"Expression": "ndo_set_rx_headroom",
"PathPrefix": ""
}Results: {
"Output": "drivers/net/netkit.c=331=static const struct net_device_ops netkit_netdev_ops = {\n--\ndrivers/net/netkit.c-336-\t.ndo_set_rx_mode_async\t= netkit_set_multicast,\ndrivers/net/netkit.c:337:\t.ndo_set_rx_headroom\t= netkit_set_headroom,\ndrivers/net/netkit.c-338-\t.ndo_set_mac_address\t= netkit_set_macaddr,\n--\ndrivers/net/tun.c=1188=static const struct net_device_ops tun_netdev_ops = {\n--\ndrivers/net/tun.c-1195-\t.ndo_select_queue\t= tun_select_queue,\ndrivers/net/tun.c:1196:\t.ndo_set_rx_headroom\t= tun_set_headroom,\ndrivers/net/tun.c-1197-\t.ndo_get_stats64\t= tun_net_get_stats64,\n--\ndrivers/net/tun.c=1272=static const struct net_device_ops tap_netdev_ops = {\n--\ndrivers/net/tun.c-1283-\t.ndo_features_check\t= passthru_features_check,\ndrivers/net/tun.c:1284:\t.ndo_set_rx_headroom\t= tun_set_headroom,\ndrivers/net/tun.c-1285-\t.ndo_bpf\t\t= tun_xdp,\n--\ndrivers/net/veth.c=1709=static const struct net_device_ops veth_netdev_ops = {\n--\ndrivers/net/veth.c-1723-\t.ndo_features_check\t= passthru_features_check,\ndrivers/net/veth.c:1724:\t.ndo_set_rx_headroom\t= veth_set_rx_headroom,\ndrivers/net/veth.c-1725-\t.ndo_bpf\t\t= veth_xdp,\n--\ninclude/linux/netdevice.h=1064=struct netdev_net_notifier {\n--\ninclude/linux/netdevice.h-1396- *\tsampling packet.\ninclude/linux/netdevice.h:1397: * void (*ndo_set_rx_headroom)(struct net_device *dev, int needed_headroom);\ninclude/linux/netdevice.h-1398- *\tThis function is used to specify the headroom that the skb must\n--\ninclude/linux/netdevice.h=1448=struct net_device_ops {\n--\ninclude/linux/netdevice.h-1674-\t\t\t\t\t\t struct sk_buff *skb);\ninclude/linux/netdevice.h:1675:\tvoid\t\t\t(*ndo_set_rx_headroom)(struct net_device *dev,\ninclude/linux/netdevice.h-1676-\t\t\t\t\t\t int needed_headroom);\n--\ninclude/linux/netdevice.h=2754=static inline void netdev_set_rx_headroom(struct net_device *dev, int new_hr)\ninclude/linux/netdevice.h-2755-{\ninclude/linux/netdevice.h:2756:\tif (dev-\u003enetdev_ops-\u003endo_set_rx_headroom)\ninclude/linux/netdevice.h:2757:\t\tdev-\u003enetdev_ops-\u003endo_set_rx_headroom(dev, new_hr);\ninclude/linux/netdevice.h-2758-}\n"
} |
| 9/2 | 2026/08/12 02:24 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 5772 output: 29 thoughts: 20 Thoughts: Here's my thought process, as requested: **Tracing the Origins of `netdev_set_rx_headroom`** Okay, so `netdev_set_rx_headroom` is the function of interest. My immediate question is always, "Where is this called from?" That's the crucial next step in understanding its purpose and impact. I need to trace its usage within the kernel's networking code. Understanding the caller is key to understanding the *why* of this function. I need to find the specific contexts in the driver or networking stack where it's invoked. I know how to use grep and other tools to find usages, but I need to do so quickly. |
| 10/2 | 2026/08/12 02:24 | tool | grepper |
0mArgs:{
"Expression": "netdev_set_rx_headroom",
"PathPrefix": ""
}Results: {
"Output": "include/linux/netdevice.h=2749=static inline unsigned netdev_get_fwd_headroom(struct net_device *dev)\n--\ninclude/linux/netdevice.h-2753-\ninclude/linux/netdevice.h:2754:static inline void netdev_set_rx_headroom(struct net_device *dev, int new_hr)\ninclude/linux/netdevice.h-2755-{\n--\ninclude/linux/netdevice.h=2761=static inline void netdev_reset_rx_headroom(struct net_device *dev)\ninclude/linux/netdevice.h-2762-{\ninclude/linux/netdevice.h:2763:\tnetdev_set_rx_headroom(dev, -1);\ninclude/linux/netdevice.h-2764-}\n--\nnet/bridge/br_if.c=315=static void update_headroom(struct net_bridge *br, int new_hr)\n--\nnet/bridge/br_if.c-319-\tlist_for_each_entry(p, \u0026br-\u003eport_list, list)\nnet/bridge/br_if.c:320:\t\tnetdev_set_rx_headroom(p-\u003edev, new_hr);\nnet/bridge/br_if.c-321-\n--\nnet/bridge/br_if.c=560=int br_add_if(struct net_bridge *br, struct net_device *dev,\n--\nnet/bridge/br_if.c-652-\telse\nnet/bridge/br_if.c:653:\t\tnetdev_set_rx_headroom(dev, br_hr);\nnet/bridge/br_if.c-654-\n--\nnet/openvswitch/datapath.c=2326=static void ovs_update_headroom(struct datapath *dp, unsigned int new_headroom)\n--\nnet/openvswitch/datapath.c-2334-\t\t\t\t\t lockdep_ovsl_is_held())\nnet/openvswitch/datapath.c:2335:\t\t\tnetdev_set_rx_headroom(vport-\u003edev, new_headroom);\nnet/openvswitch/datapath.c-2336-\t}\n--\nnet/openvswitch/datapath.c=2339=static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)\n--\nnet/openvswitch/datapath.c-2416-\telse\nnet/openvswitch/datapath.c:2417:\t\tnetdev_set_rx_headroom(vport-\u003edev, dp-\u003emax_headroom);\nnet/openvswitch/datapath.c-2418-\n"
} |
| 11/2 | 2026/08/12 02:24 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 6665 output: 32 thoughts: 43 Thoughts: Okay, here's my take on those thoughts, framed as my own: **Investigating Network Driver Headroom and Tunnel Behavior** Right, let's see, `netdev_set_rx_headroom` is being called from both bridge and Open vSwitch, which is interesting. I'll need to remember that context later. Now, what about that other function, `tun_get_user`? I need to understand where that's being invoked. It's often the case that seemingly innocuous functions are called in multiple places, creating unforeseen interactions. So, let me quickly trace its call paths to get a better handle on its overall impact. I'm especially interested in how it interacts with the more established pieces of code that I know better. That’s probably the best starting point. |
| 12/2 | 2026/08/12 02:25 | tool | grepper |
0mArgs:{
"Expression": "tun_get_user",
"PathPrefix": "drivers/net/tun.c"
}Results: {
"Output": "drivers/net/tun.c=1603=static struct sk_buff *tun_build_skb(struct tun_struct *tun,\n--\ndrivers/net/tun.c-1699-/* Get packet from user space buffer */\ndrivers/net/tun.c:1700:static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,\ndrivers/net/tun.c-1701-\t\t\t void *msg_control, struct iov_iter *from,\n--\ndrivers/net/tun.c=1998=static ssize_t tun_chr_write_iter(struct kiocb *iocb, struct iov_iter *from)\n--\ndrivers/net/tun.c-2011-\ndrivers/net/tun.c:2012:\tresult = tun_get_user(tun, tfile, NULL, from, noblock, false);\ndrivers/net/tun.c-2013-\n--\ndrivers/net/tun.c=2526=static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len)\n--\ndrivers/net/tun.c-2572-\ndrivers/net/tun.c:2573:\tret = tun_get_user(tun, tfile, ctl ? ctl-\u003eptr : NULL, \u0026m-\u003emsg_iter,\ndrivers/net/tun.c-2574-\t\t\t m-\u003emsg_flags \u0026 MSG_DONTWAIT,\n"
} |
| 13/2 | 2026/08/12 02:25 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7289 output: 34 thoughts: 179 Thoughts: **Focusing on Key Entry Points** Okay, so I'm looking at the core data flow within this TUN driver, and it looks like `tun_chr_write_iter` and `tun_sendmsg` are the key entry points. `tun_chr_write_iter`, right, that's the `.write_iter` method within `tun_fops`, and `tun_sendmsg` corresponds to the `.sendmsg` method in `tun_proto_ops`. That makes sense. Therefore, my initial focus has to be on understanding how these functions work. Now, a red flag! I see `tun_get_user` in this context, and it looks pretty substantial. It's marked as `static`, which implies it's not a direct, external API entry point. The instructions *do* say to prefer non-static, non-inlined entry points over these internal helpers. Hmm...should I include `tun_get_user` in my analysis, even though it's static? I should check if `tun_chr_write_iter` and `tun_sendmsg` are actually non-static - that would be the deciding factor. |
| 14/2 | 2026/08/12 02:25 | tool | grepper |
0mArgs:{
"Expression": "tun_chr_write_iter",
"PathPrefix": "drivers/net/tun.c"
}Results: {
"Output": "drivers/net/tun.c=1700=static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,\n--\ndrivers/net/tun.c-1997-\ndrivers/net/tun.c:1998:static ssize_t tun_chr_write_iter(struct kiocb *iocb, struct iov_iter *from)\ndrivers/net/tun.c-1999-{\n--\ndrivers/net/tun.c=3480=static const struct file_operations tun_fops = {\n--\ndrivers/net/tun.c-3482-\t.read_iter = tun_chr_read_iter,\ndrivers/net/tun.c:3483:\t.write_iter = tun_chr_write_iter,\ndrivers/net/tun.c-3484-\t.poll\t= tun_chr_poll,\n"
} |
| 15/2 | 2026/08/12 02:25 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 6939 output: 31 thoughts: 0 |
| 16/2 | 2026/08/12 02:25 | tool | grepper |
0mArgs:{
"Expression": "tun_sendmsg",
"PathPrefix": "drivers/net/tun.c"
}Results: {
"Output": "drivers/net/tun.c=2390=static int tun_xdp_one(struct tun_struct *tun,\n--\ndrivers/net/tun.c-2525-\ndrivers/net/tun.c:2526:static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len)\ndrivers/net/tun.c-2527-{\n--\ndrivers/net/tun.c=2650=static const struct proto_ops tun_socket_ops = {\ndrivers/net/tun.c-2651-\t.peek_len = tun_peek_len,\ndrivers/net/tun.c:2652:\t.sendmsg = tun_sendmsg,\ndrivers/net/tun.c-2653-\t.recvmsg = tun_recvmsg,\n"
} |
| 17/2 | 2026/08/12 02:25 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 8233 output: 28 thoughts: 393 Thoughts: **My Current Analysis of Relevant Kernel Entry Points** Okay, so I'm looking at these functions and trying to figure out what to focus on. Both `file_operations` and `proto_ops` are static, but they're assigned, so they're definitely entry points. That's good to know. I'll make sure to add `tun_chr_write_iter` and `tun_sendmsg` to my FocusSymbols list. Now, what about `tun_set_headroom`? It's assigned to `ndo_set_rx_headroom`, so that's something to consider. The wrapper is `netdev_set_rx_headroom`, which is inline. I need to trace the callers: `update_headroom` and `br_add_if` within `net/bridge/br_if.c`, plus `ovs_update_headroom` and `ovs_vport_cmd_new` in `net/openvswitch/datapath.c`. Since `netdev_set_rx_headroom` is inlined, but these are all calling it, I think I can safely add `br_add_if` and `ovs_vport_cmd_new` to the list. Wait a second. `tun_set_headroom` is actually static within `drivers/net/tun.c`. That complicates things. If it's static and inlined, the fuzzer might miss it. However, it's assigned to a function pointer, so it's *not* inlined. I was right to focus on it. I'll add `tun_chr_write_iter`, `tun_sendmsg`, `br_add_if`, and `ovs_vport_cmd_new` to the FocusSymbols. I'm thinking about `tun_get_user` too. It's a large function, so it's probably not inlined. Might be worth checking to be sure, but I think `tun_chr_write_iter` and `tun_sendmsg` are solid entry points regardless. It's time to check Kconfig, make sure I have bridge and openvswitch turned on in the config. |
| 18/2 | 2026/08/12 02:26 | tool | grepper |
0mArgs:{
"Expression": "config BRIDGE",
"PathPrefix": "net/bridge/Kconfig"
}Results: {
"Output": "net/bridge/Kconfig-5-\nnet/bridge/Kconfig:6:config BRIDGE\nnet/bridge/Kconfig-7-\ttristate \"802.1d Ethernet Bridging\"\n--\nnet/bridge/Kconfig-35-\nnet/bridge/Kconfig:36:config BRIDGE_IGMP_SNOOPING\nnet/bridge/Kconfig-37-\tbool \"IGMP/MLD snooping\"\n--\nnet/bridge/Kconfig-49-\nnet/bridge/Kconfig:50:config BRIDGE_VLAN_FILTERING\nnet/bridge/Kconfig-51-\tbool \"VLAN filtering\"\n--\nnet/bridge/Kconfig-63-\nnet/bridge/Kconfig:64:config BRIDGE_MRP\nnet/bridge/Kconfig-65-\tbool \"MRP protocol\"\n--\nnet/bridge/Kconfig-75-\nnet/bridge/Kconfig:76:config BRIDGE_CFM\nnet/bridge/Kconfig-77-\tbool \"CFM protocol\"\n"
} |
| 19/2 | 2026/08/12 02:26 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7949 output: 33 thoughts: 0 |
| 20/2 | 2026/08/12 02:26 | tool | grepper |
0mArgs:{
"Expression": "config OPENVSWITCH",
"PathPrefix": "net/openvswitch/Kconfig"
}Results: {
"Output": "net/openvswitch/Kconfig-5-\nnet/openvswitch/Kconfig:6:config OPENVSWITCH\nnet/openvswitch/Kconfig-7-\ttristate \"Open vSwitch\"\n--\nnet/openvswitch/Kconfig-43-\nnet/openvswitch/Kconfig:44:config OPENVSWITCH_GRE\nnet/openvswitch/Kconfig-45-\ttristate \"Open vSwitch GRE tunneling support\"\n--\nnet/openvswitch/Kconfig-56-\nnet/openvswitch/Kconfig:57:config OPENVSWITCH_VXLAN\nnet/openvswitch/Kconfig-58-\ttristate \"Open vSwitch VXLAN tunneling support\"\n--\nnet/openvswitch/Kconfig-68-\nnet/openvswitch/Kconfig:69:config OPENVSWITCH_GENEVE\nnet/openvswitch/Kconfig-70-\ttristate \"Open vSwitch Geneve tunneling support\"\n"
} |
| 21/2 | 2026/08/12 02:26 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 8229 output: 171 thoughts: 843 Thoughts: **Analyzing the Patch for Fuzzing Opportunities** Okay, so I've got this patch that tweaks `drivers/net/tun.c`, specifically `tun_set_headroom` and `tun_get_user`. My initial thought is, this is definitely worth a closer look from a fuzzing perspective. First, `tun_set_headroom` gets called indirectly through `ndo_set_rx_headroom` which is assigned to it, for both `tun` and `tap` devices. Now, `ndo_set_rx_headroom` is triggered by `netdev_set_rx_headroom`, which we see used in both `net/bridge/br_if.c` (via `update_headroom`) and `net/openvswitch/datapath.c` (via `ovs_update_headroom`). So, to test `tun_set_headroom` effectively, I'll need `TUN` configured, and at least one of either `BRIDGE` or `OPENVSWITCH`. That's a solid starting point for our fuzzing configuration. Then there's `tun_get_user`. This one is interesting because it's called by `tun_chr_write_iter` (which is reached via the `write()` system call on `/dev/net/tun`) and `tun_sendmsg` (using `sendmsg()` on a tun socket). The patch adds a `pskb_may_pull()` call in `tun_get_user`. This seems like a functional change dealing with packet parsing, so it's a good target for fuzzing. My primary focus areas for fuzzing will be `tun_set_headroom`, `tun_get_user`, `tun_chr_write_iter` and `tun_sendmsg`, as they are the direct entry points for these changes. I’ll also need to ensure that `TUN`, `BRIDGE` and `OPENVSWITCH` are enabled in the kernel config to cover all the call paths. I need to confirm if `netdev_set_rx_headroom` has any other callers. Okay, the inline wrapper in `include/linux/netdevice.h` doesn't provide anything additional. `BRIDGE` and `OPENVSWITCH` are sufficient. Now, let's refine this a bit further. The changes modify headroom calculation and add packet header checks. These are accessible via `write()` or `sendmsg()` to the TUN device, as well as when bridging or using Open vSwitch to attach the TUN device, which uses the `ndo_set_rx_headroom`. Given these are functional changes to how packets are processed and device configuration is handled, I'm confident that fuzzing here is going to be worthwhile. Therefore, for this fuzzing campaign, I'll set: * **Focus Symbols:** `tun_set_headroom`, `tun_get_user`, `tun_chr_write_iter`, `tun_sendmsg` * **Enabled Configs:** `TUN`, `BRIDGE`, `OPENVSWITCH` |
| 22/2 | 2026/08/12 02:26 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"TUN",
"BRIDGE",
"OPENVSWITCH"
],
"FocusSymbols": [
"tun_set_headroom",
"tun_get_user",
"tun_chr_write_iter",
"tun_sendmsg"
],
"Reasoning": "The patch modifies headroom calculation in `tun_set_headroom` and adds packet header pull checks in `tun_get_user` for TUN/TAP devices. These functions are reachable via `write()` or `sendmsg()` to the TUN device, and via bridge or Open vSwitch attaching the TUN device (which triggers `ndo_set_rx_headroom`). These are functional changes to packet processing and device configuration that should be fuzzed.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"TUN",
"BRIDGE",
"OPENVSWITCH"
],
"FocusSymbols": [
"tun_set_headroom",
"tun_get_user",
"tun_chr_write_iter",
"tun_sendmsg"
],
"Reasoning": "The patch modifies headroom calculation in `tun_set_headroom` and adds packet header pull checks in `tun_get_user` for TUN/TAP devices. These functions are reachable via `write()` or `sendmsg()` to the TUN device, and via bridge or Open vSwitch attaching the TUN device (which triggers `ndo_set_rx_headroom`). These are functional changes to packet processing and device configuration that should be fuzzed.",
"WorthFuzzing": true
} |
| 23/1 | 2026/08/12 02:26 | action | If |
0mArgs:{
"WorthFuzzing": true
}Results: null |
| 24/2 | 2026/08/12 02:26 | agent | kmsan-evaluator |
0mModel:best-expensive Args: null Results: {
"KMSANReasoning": "The patch addresses out-of-bounds accesses and integer overflows. Specifically, it clamps the maximum headroom in `tun_set_headroom` to prevent potential integer overflows or out-of-bounds allocations, and it adds/modifies `pskb_may_pull` checks in `tun_get_user` to ensure that packet headers are safely accessible in the linear portion of the socket buffer before reading them. These are classic memory safety issues (out-of-bounds reads/writes) that are effectively detected by KASAN and UBSAN. There is no introduction or exposure of uninitialized memory (such as uninitialized stack/heap variables or info-leaks to user space) that would require KMSAN.",
"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 c0ddcfaeac32ee654a2a1a7fed12a11c3ab1b912
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Aug 12 02:23:12 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index fed9dfdfcc3bc..5bbe3123979e0 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1107,11 +1107,16 @@ static netdev_features_t tun_net_fix_features(struct net_device *dev,
static void tun_set_headroom(struct net_device *dev, int new_hr)
{
struct tun_struct *tun = netdev_priv(dev);
+ size_t max_headroom;
- if (new_hr < NET_SKB_PAD)
- new_hr = NET_SKB_PAD;
+ max_headroom = min_t(size_t, SKB_MAX_HEAD(0), U16_MAX - 1);
- tun->align = new_hr;
+ if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP)
+ max_headroom -= ETH_HLEN + NET_IP_ALIGN;
+ else
+ max_headroom -= 1;
+
+ tun->align = clamp_t(int, new_hr, NET_SKB_PAD, max_headroom);
}
static void
@@ -1822,7 +1827,13 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
switch (tun->flags & TUN_TYPE_MASK) {
case IFF_TUN:
if (tun->flags & IFF_NO_PI) {
- u8 ip_version = skb->len ? (skb->data[0] >> 4) : 0;
+ u8 ip_version;
+
+ if (!pskb_may_pull(skb, 1)) {
+ err = -EINVAL;
+ goto drop;
+ }
+ ip_version = skb->data[0] >> 4;
switch (ip_version) {
case 4:
@@ -1842,7 +1853,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
skb->dev = tun->dev;
break;
case IFF_TAP:
- if (frags && !pskb_may_pull(skb, ETH_HLEN)) {
+ if (!pskb_may_pull(skb, ETH_HLEN)) {
err = -ENOMEM;
drop_reason = SKB_DROP_REASON_HDR_TRUNC;
goto drop;
|
| 25/3 | 2026/08/12 02:26 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 2461 output: 173 thoughts: 763 Thoughts: **Analyzing the `tun.c` Patch: A KASAN/UBSAN Focus** Okay, let's dissect these changes to `drivers/net/tun.c`. It's pretty clear this is focused on hardening against KASAN and UBSAN reports, which is what I suspected given the code locations. First, in `tun_set_headroom`, they're restricting the maximum headroom using `clamp_t`. Looking at the logic, the intent is to prevent a potential integer overflow or out-of-bounds issue during SKB allocation by setting a hard limit for headroom. The key seems to be the revised calculation of `max_headroom`, taking into account the type of interface (`IFF_TAP` vs `IFF_TUN`). The clamping ensures the allocated memory remains within safe bounds. Second, the `tun_get_user` function for `IFF_TUN` now includes a `pskb_may_pull(skb, 1)` check before reading `skb->data[0]`. This is textbook KASAN mitigation. It prevents accessing data that might not be available or is outside the allocated buffer. If I'm reading this correctly, it specifically addresses a potential out-of-bounds read. Third, a similar fix is applied to `tun_get_user` for `IFF_TAP`. The conditional that had `frags` and `!pskb_may_pull(skb, ETH_HLEN)` has been simplified to just `!pskb_may_pull(skb, ETH_HLEN)`. This ensures that `ETH_HLEN` bytes are available for pulling from the SKB before they're accessed. Again, this is about preventing out-of-bounds reads. Now, the important question is whether these changes introduce or expose an uninitialized memory risk. The answer is *no*. Looking closely at the patch and my experience, the `pskb_may_pull` function isn't about initializing memory. It's solely about ensuring data is accessible in the linear part of the SKB to avoid out-of-bounds reads. The `tun_set_headroom` change simply caps the allocation size, not its initialization. Therefore, these changes are purely focused on eliminating potential KASAN/UBSAN hits by enforcing bounds checks and restricting headroom to prevent overflows, not addressing any uninitialized memory issues. They are all about protecting against known vulnerabilities. I'm comfortable setting NeedsKMSAN to false. |
| 26/3 | 2026/08/12 02:27 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch addresses out-of-bounds accesses and integer overflows. Specifically, it clamps the maximum headroom in `tun_set_headroom` to prevent potential integer overflows or out-of-bounds allocations, and it adds/modifies `pskb_may_pull` checks in `tun_get_user` to ensure that packet headers are safely accessible in the linear portion of the socket buffer before reading them. These are classic memory safety issues (out-of-bounds reads/writes) that are effectively detected by KASAN and UBSAN. There is no introduction or exposure of uninitialized memory (such as uninitialized stack/heap variables or info-leaks to user space) that would require KMSAN.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch addresses out-of-bounds accesses and integer overflows. Specifically, it clamps the maximum headroom in `tun_set_headroom` to prevent potential integer overflows or out-of-bounds allocations, and it adds/modifies `pskb_may_pull` checks in `tun_get_user` to ensure that packet headers are safely accessible in the linear portion of the socket buffer before reading them. These are classic memory safety issues (out-of-bounds reads/writes) that are effectively detected by KASAN and UBSAN. There is no introduction or exposure of uninitialized memory (such as uninitialized stack/heap variables or info-leaks to user space) that would require KMSAN.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|