| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/08/09 21:52 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"OVPN"
],
"FocusSymbols": [
"ovpn_crypto_key_slot_release",
"ovpn_crypto_kill_key",
"ovpn_aead_crypto_key_slot_new",
"ovpn_peer_keepalive_set",
"ovpn_peer_keepalive_work"
],
"KMSANReasoning": "The patch series focuses on fixing a NULL pointer dereference in `ovpn_crypto_kill_key`, reordering cleanup functions to prevent potential use-after-free bugs, and migrating work items from the system workqueue to a dedicated `ovpn_wq` workqueue. These changes address memory safety issues (NULL dereferences, UAF) and concurrency management, which are effectively detected by standard KASAN and LOCKDEP. There are no modifications to structures copied to user space, no new buffer allocations that could leak uninitialized memory, and no changes to data length calculations that would expose uninitialized bytes. Therefore, a dedicated KMSAN fuzzing session is not required.",
"NeedsKMSAN": false,
"Reasoning": "The patch modifies the OpenVPN data channel offload driver (drivers/net/ovpn). It replaces call_rcu with queue_rcu_work for freeing crypto key slots, introduces a dedicated workqueue (ovpn_wq) for all ovpn-specific work, and fixes a logic bug in ovpn_crypto_kill_key. These are functional changes in a reachable network driver.",
"WorthFuzzing": true
} |
| 1/1 | 2026/08/09 21:52 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit a95f26db5222d62a1fe39240c48f8e0aeb916609\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Sun Aug 9 21:52:50 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ovpn/crypto.c b/drivers/net/ovpn/crypto.c\nindex 90580e32052fb..7e545428900a9 100644\n--- a/drivers/net/ovpn/crypto.c\n+++ b/drivers/net/ovpn/crypto.c\n@@ -18,20 +18,12 @@\n #include \"crypto_aead.h\"\n #include \"crypto.h\"\n \n-static void ovpn_ks_destroy_rcu(struct rcu_head *head)\n-{\n-\tstruct ovpn_crypto_key_slot *ks;\n-\n-\tks = container_of(head, struct ovpn_crypto_key_slot, rcu);\n-\tovpn_aead_crypto_key_slot_destroy(ks);\n-}\n-\n void ovpn_crypto_key_slot_release(struct kref *kref)\n {\n \tstruct ovpn_crypto_key_slot *ks;\n \n \tks = container_of(kref, struct ovpn_crypto_key_slot, refcount);\n-\tcall_rcu(\u0026ks-\u003ercu, ovpn_ks_destroy_rcu);\n+\tqueue_rcu_work(ovpn_wq, \u0026ks-\u003efree_work);\n }\n \n /* can only be invoked when all peer references have been dropped (i.e. RCU\n@@ -58,15 +50,19 @@ void ovpn_crypto_state_release(struct ovpn_crypto_state *cs)\n bool ovpn_crypto_kill_key(struct ovpn_crypto_state *cs, u8 key_id)\n {\n \tstruct ovpn_crypto_key_slot *ks = NULL;\n+\tstruct ovpn_crypto_key_slot *tmp;\n+\tint slot = 0;\n \n \tspin_lock_bh(\u0026cs-\u003elock);\n-\tif (rcu_access_pointer(cs-\u003eslots[0])-\u003ekey_id == key_id) {\n-\t\tks = rcu_replace_pointer(cs-\u003eslots[0], NULL,\n-\t\t\t\t\t lockdep_is_held(\u0026cs-\u003elock));\n-\t} else if (rcu_access_pointer(cs-\u003eslots[1])-\u003ekey_id == key_id) {\n-\t\tks = rcu_replace_pointer(cs-\u003eslots[1], NULL,\n-\t\t\t\t\t lockdep_is_held(\u0026cs-\u003elock));\n+\ttmp = rcu_access_pointer(cs-\u003eslots[slot]);\n+\tif (!tmp || tmp-\u003ekey_id != key_id) {\n+\t\tslot = 1;\n+\t\ttmp = rcu_access_pointer(cs-\u003eslots[slot]);\n \t}\n+\n+\tif (tmp \u0026\u0026 tmp-\u003ekey_id == key_id)\n+\t\tks = rcu_replace_pointer(cs-\u003eslots[slot], NULL,\n+\t\t\t\t\t lockdep_is_held(\u0026cs-\u003elock));\n \tspin_unlock_bh(\u0026cs-\u003elock);\n \n \tif (ks)\ndiff --git a/drivers/net/ovpn/crypto.h b/drivers/net/ovpn/crypto.h\nindex 0e284fec3a75a..e3feb16d54985 100644\n--- a/drivers/net/ovpn/crypto.h\n+++ b/drivers/net/ovpn/crypto.h\n@@ -10,6 +10,8 @@\n #ifndef _NET_OVPN_OVPNCRYPTO_H_\n #define _NET_OVPN_OVPNCRYPTO_H_\n \n+#include \u003clinux/workqueue.h\u003e\n+\n #include \"pktid.h\"\n #include \"proto.h\"\n \n@@ -45,8 +47,8 @@ struct ovpn_crypto_key_slot {\n \n \tstruct ovpn_pktid_recv pid_recv ____cacheline_aligned_in_smp;\n \tstruct ovpn_pktid_xmit pid_xmit ____cacheline_aligned_in_smp;\n+\tstruct rcu_work free_work;\n \tstruct kref refcount;\n-\tstruct rcu_head rcu;\n };\n \n struct ovpn_crypto_state {\ndiff --git a/drivers/net/ovpn/crypto_aead.c b/drivers/net/ovpn/crypto_aead.c\nindex 8f07c418622b2..74eaf6fac2f52 100644\n--- a/drivers/net/ovpn/crypto_aead.c\n+++ b/drivers/net/ovpn/crypto_aead.c\n@@ -9,6 +9,7 @@\n \n #include \u003ccrypto/aead.h\u003e\n #include \u003clinux/skbuff.h\u003e\n+#include \u003clinux/workqueue.h\u003e\n #include \u003cnet/ip.h\u003e\n #include \u003cnet/ipv6.h\u003e\n #include \u003cnet/udp.h\u003e\n@@ -380,13 +381,19 @@ static struct crypto_aead *ovpn_aead_init(const char *title,\n \treturn ERR_PTR(ret);\n }\n \n-void ovpn_aead_crypto_key_slot_destroy(struct ovpn_crypto_key_slot *ks)\n+static void ovpn_aead_crypto_key_slot_free(struct ovpn_crypto_key_slot *ks)\n {\n-\tif (!ks)\n-\t\treturn;\n-\n \tcrypto_free_aead(ks-\u003eencrypt);\n \tcrypto_free_aead(ks-\u003edecrypt);\n+}\n+\n+static void ovpn_aead_crypto_key_slot_free_work(struct work_struct *work)\n+{\n+\tstruct ovpn_crypto_key_slot *ks;\n+\n+\tks = container_of(to_rcu_work(work), struct ovpn_crypto_key_slot,\n+\t\t\t free_work);\n+\tovpn_aead_crypto_key_slot_free(ks);\n \tkfree(ks);\n }\n \n@@ -420,6 +427,7 @@ ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc)\n \n \tks-\u003eencrypt = NULL;\n \tks-\u003edecrypt = NULL;\n+\tINIT_RCU_WORK(\u0026ks-\u003efree_work, ovpn_aead_crypto_key_slot_free_work);\n \tkref_init(\u0026ks-\u003erefcount);\n \tks-\u003ekey_id = kc-\u003ekey_id;\n \n@@ -453,7 +461,8 @@ ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc)\n \treturn ks;\n \n destroy_ks:\n-\tovpn_aead_crypto_key_slot_destroy(ks);\n+\tovpn_aead_crypto_key_slot_free(ks);\n+\tkfree(ks);\n \treturn ERR_PTR(ret);\n }\n \ndiff --git a/drivers/net/ovpn/crypto_aead.h b/drivers/net/ovpn/crypto_aead.h\nindex 65a2ff3078986..fae3b585a43b3 100644\n--- a/drivers/net/ovpn/crypto_aead.h\n+++ b/drivers/net/ovpn/crypto_aead.h\n@@ -22,7 +22,6 @@ int ovpn_aead_decrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,\n \n struct ovpn_crypto_key_slot *\n ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc);\n-void ovpn_aead_crypto_key_slot_destroy(struct ovpn_crypto_key_slot *ks);\n \n enum ovpn_cipher_alg ovpn_aead_crypto_alg(struct ovpn_crypto_key_slot *ks);\n \ndiff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c\nindex 9a66d693039a3..9526f8096da60 100644\n--- a/drivers/net/ovpn/io.c\n+++ b/drivers/net/ovpn/io.c\n@@ -204,10 +204,10 @@ void ovpn_decrypt_post(void *data, int ret)\n \t\tovpn_dev_dstats_rx_dropped(peer-\u003eovpn-\u003edev);\n \tkfree_skb(skb);\n drop_nocount:\n-\tif (likely(peer))\n-\t\tovpn_peer_put(peer);\n \tif (likely(ks))\n \t\tovpn_crypto_key_slot_put(ks);\n+\tif (likely(peer))\n+\t\tovpn_peer_put(peer);\n }\n \n /* RX path entry point: decrypt packet and forward it to the device */\n@@ -302,11 +302,11 @@ void ovpn_encrypt_post(void *data, int ret)\n err:\n \tif (unlikely(skb))\n \t\tovpn_dev_dstats_tx_dropped(peer-\u003eovpn-\u003edev);\n-\tif (likely(peer))\n-\t\tovpn_peer_put(peer);\n+\tkfree_skb(skb);\n \tif (likely(ks))\n \t\tovpn_crypto_key_slot_put(ks);\n-\tkfree_skb(skb);\n+\tif (likely(peer))\n+\t\tovpn_peer_put(peer);\n }\n \n static bool ovpn_encrypt_one(struct ovpn_peer *peer, struct sk_buff *skb)\ndiff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c\nindex 168cfe9b59a98..0708249e9607c 100644\n--- a/drivers/net/ovpn/main.c\n+++ b/drivers/net/ovpn/main.c\n@@ -12,6 +12,7 @@\n #include \u003clinux/module.h\u003e\n #include \u003clinux/netdevice.h\u003e\n #include \u003clinux/inetdevice.h\u003e\n+#include \u003clinux/workqueue.h\u003e\n #include \u003cnet/gro_cells.h\u003e\n #include \u003cnet/ip.h\u003e\n #include \u003cnet/rtnetlink.h\u003e\n@@ -26,6 +27,9 @@\n #include \"tcp.h\"\n #include \"udp.h\"\n \n+/* module-owned workqueue on which all ovpn-specific work is queued */\n+struct workqueue_struct *ovpn_wq;\n+\n static void ovpn_priv_free(struct net_device *net)\n {\n \tstruct ovpn_priv *ovpn = netdev_priv(net);\n@@ -264,10 +268,16 @@ static int __init ovpn_init(void)\n \n \tovpn_tcp_init();\n \n+\tovpn_wq = alloc_workqueue(\"ovpn\", WQ_PERCPU, 0);\n+\tif (!ovpn_wq) {\n+\t\tpr_err(\"ovpn: cannot allocate workqueue\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n \terr = rtnl_link_register(\u0026ovpn_link_ops);\n \tif (err) {\n \t\tpr_err(\"ovpn: can't register rtnl link ops: %d\\n\", err);\n-\t\treturn err;\n+\t\tgoto destroy_wq;\n \t}\n \n \terr = ovpn_nl_register();\n@@ -280,6 +290,9 @@ static int __init ovpn_init(void)\n \n unreg_rtnl:\n \trtnl_link_unregister(\u0026ovpn_link_ops);\n+destroy_wq:\n+\tdestroy_workqueue(ovpn_wq);\n+\tovpn_wq = NULL;\n \treturn err;\n }\n \n@@ -288,7 +301,11 @@ static __exit void ovpn_cleanup(void)\n \tovpn_nl_unregister();\n \trtnl_link_unregister(\u0026ovpn_link_ops);\n \n+\tflush_workqueue(ovpn_wq);\n \trcu_barrier();\n+\n+\tdestroy_workqueue(ovpn_wq);\n+\tovpn_wq = NULL;\n }\n \n module_init(ovpn_init);\ndiff --git a/drivers/net/ovpn/ovpnpriv.h b/drivers/net/ovpn/ovpnpriv.h\nindex 5898f6adada7f..84499140e4bd9 100644\n--- a/drivers/net/ovpn/ovpnpriv.h\n+++ b/drivers/net/ovpn/ovpnpriv.h\n@@ -15,6 +15,10 @@\n #include \u003cuapi/linux/if_link.h\u003e\n #include \u003cuapi/linux/ovpn.h\u003e\n \n+struct workqueue_struct;\n+\n+extern struct workqueue_struct *ovpn_wq;\n+\n /**\n * struct ovpn_peer_collection - container of peers for MultiPeer mode\n * @by_id: table of peers index by ID\ndiff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c\nindex b0519f9840d83..c95656ca7c357 100644\n--- a/drivers/net/ovpn/peer.c\n+++ b/drivers/net/ovpn/peer.c\n@@ -62,7 +62,7 @@ void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout)\n \t/* now that interval and timeout have been changed, kick\n \t * off the worker so that the next delay can be recomputed\n \t */\n-\tmod_delayed_work(system_percpu_wq, \u0026peer-\u003eovpn-\u003ekeepalive_work, 0);\n+\tmod_delayed_work(ovpn_wq, \u0026peer-\u003eovpn-\u003ekeepalive_work, 0);\n }\n \n /**\n@@ -1371,7 +1371,7 @@ static time64_t ovpn_peer_keepalive_work_single(struct ovpn_peer *peer,\n \t\t\t peer-\u003eid);\n \t\tif (WARN_ON(!ovpn_peer_hold(peer)))\n \t\t\treturn 0;\n-\t\tif (!schedule_work(\u0026peer-\u003ekeepalive_work))\n+\t\tif (!queue_work(ovpn_wq, \u0026peer-\u003ekeepalive_work))\n \t\t\tovpn_peer_put(peer);\n \t}\n \n@@ -1463,8 +1463,8 @@ void ovpn_peer_keepalive_work(struct work_struct *work)\n \t\tnetdev_dbg(ovpn-\u003edev,\n \t\t\t \"scheduling keepalive work: now=%llu next_run=%llu delta=%llu\\n\",\n \t\t\t next_run, now, next_run - now);\n-\t\tschedule_delayed_work(\u0026ovpn-\u003ekeepalive_work,\n-\t\t\t\t (next_run - now) * HZ);\n+\t\tqueue_delayed_work(ovpn_wq, \u0026ovpn-\u003ekeepalive_work,\n+\t\t\t\t (next_run - now) * HZ);\n \t}\n \tunlock_ovpn(ovpn, \u0026release_list);\n }\ndiff --git a/drivers/net/ovpn/tcp.c b/drivers/net/ovpn/tcp.c\nindex 0af14055c39aa..8fe8a8e750a40 100644\n--- a/drivers/net/ovpn/tcp.c\n+++ b/drivers/net/ovpn/tcp.c\n@@ -151,7 +151,7 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb)\n \t/* take reference for deferred peer deletion. should never fail */\n \tif (WARN_ON(!ovpn_peer_hold(peer)))\n \t\tgoto err_nopeer;\n-\tif (!schedule_work(\u0026peer-\u003etcp.defer_del_work))\n+\tif (!queue_work(ovpn_wq, \u0026peer-\u003etcp.defer_del_work))\n \t\tovpn_peer_put(peer);\n \tovpn_dev_dstats_rx_dropped(peer-\u003eovpn-\u003edev);\n err_nopeer:\n@@ -284,13 +284,12 @@ static void ovpn_tcp_send_sock(struct ovpn_peer *peer, struct sock *sk)\n \t\t\t * stream therefore we abort the connection\n \t\t\t */\n \t\t\tovpn_peer_hold(peer);\n-\t\t\tif (!schedule_work(\u0026peer-\u003etcp.defer_del_work))\n+\t\t\tif (!queue_work(ovpn_wq, \u0026peer-\u003etcp.defer_del_work))\n \t\t\t\tovpn_peer_put(peer);\n \n \t\t\t/* we bail out immediately and keep tx_in_progress set\n \t\t\t * to true. This way we prevent more TX attempts\n-\t\t\t * which would lead to more invocations of\n-\t\t\t * schedule_work()\n+\t\t\t * which would lead to more invocations of queue_work()\n \t\t\t */\n \t\t\treturn;\n \t\t}\n@@ -487,7 +486,7 @@ static void ovpn_tcp_write_space(struct sock *sk)\n \trcu_read_lock();\n \tsock = rcu_dereference_sk_user_data(sk);\n \tif (likely(sock \u0026\u0026 sock-\u003epeer)) {\n-\t\tschedule_work(\u0026sock-\u003etcp_tx_work);\n+\t\tqueue_work(ovpn_wq, \u0026sock-\u003etcp_tx_work);\n \t\tsock-\u003epeer-\u003etcp.sk_cb.sk_write_space(sk);\n \t}\n \trcu_read_unlock();\n"
} |
| 2/1 | 2026/08/09 21:52 | agent | patch-evaluator |
0mModel:best-expensive Args: null Results: {
"EnableConfigs": [
"OVPN"
],
"FocusSymbols": [
"ovpn_crypto_key_slot_release",
"ovpn_crypto_kill_key",
"ovpn_aead_crypto_key_slot_new",
"ovpn_peer_keepalive_set",
"ovpn_peer_keepalive_work"
],
"Reasoning": "The patch modifies the OpenVPN data channel offload driver (drivers/net/ovpn). It replaces call_rcu with queue_rcu_work for freeing crypto key slots, introduces a dedicated workqueue (ovpn_wq) for all ovpn-specific work, and fixes a logic bug in ovpn_crypto_kill_key. These are functional changes in a reachable network driver.",
"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 a95f26db5222d62a1fe39240c48f8e0aeb916609
Author: syz-cluster <triage@syzkaller.com>
Date: Sun Aug 9 21:52:50 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/ovpn/crypto.c b/drivers/net/ovpn/crypto.c
index 90580e32052fb..7e545428900a9 100644
--- a/drivers/net/ovpn/crypto.c
+++ b/drivers/net/ovpn/crypto.c
@@ -18,20 +18,12 @@
#include "crypto_aead.h"
#include "crypto.h"
-static void ovpn_ks_destroy_rcu(struct rcu_head *head)
-{
- struct ovpn_crypto_key_slot *ks;
-
- ks = container_of(head, struct ovpn_crypto_key_slot, rcu);
- ovpn_aead_crypto_key_slot_destroy(ks);
-}
-
void ovpn_crypto_key_slot_release(struct kref *kref)
{
struct ovpn_crypto_key_slot *ks;
ks = container_of(kref, struct ovpn_crypto_key_slot, refcount);
- call_rcu(&ks->rcu, ovpn_ks_destroy_rcu);
+ queue_rcu_work(ovpn_wq, &ks->free_work);
}
/* can only be invoked when all peer references have been dropped (i.e. RCU
@@ -58,15 +50,19 @@ void ovpn_crypto_state_release(struct ovpn_crypto_state *cs)
bool ovpn_crypto_kill_key(struct ovpn_crypto_state *cs, u8 key_id)
{
struct ovpn_crypto_key_slot *ks = NULL;
+ struct ovpn_crypto_key_slot *tmp;
+ int slot = 0;
spin_lock_bh(&cs->lock);
- if (rcu_access_pointer(cs->slots[0])->key_id == key_id) {
- ks = rcu_replace_pointer(cs->slots[0], NULL,
- lockdep_is_held(&cs->lock));
- } else if (rcu_access_pointer(cs->slots[1])->key_id == key_id) {
- ks = rcu_replace_pointer(cs->slots[1], NULL,
- lockdep_is_held(&cs->lock));
+ tmp = rcu_access_pointer(cs->slots[slot]);
+ if (!tmp || tmp->key_id != key_id) {
+ slot = 1;
+ tmp = rcu_access_pointer(cs->slots[slot]);
}
+
+ if (tmp && tmp->key_id == key_id)
+ ks = rcu_replace_pointer(cs->slots[slot], NULL,
+ lockdep_is_held(&cs->lock));
spin_unlock_bh(&cs->lock);
if (ks)
diff --git a/drivers/net/ovpn/crypto.h b/drivers/net/ovpn/crypto.h
index 0e284fec3a75a..e3feb16d54985 100644
--- a/drivers/net/ovpn/crypto.h
+++ b/drivers/net/ovpn/crypto.h
@@ -10,6 +10,8 @@
#ifndef _NET_OVPN_OVPNCRYPTO_H_
#define _NET_OVPN_OVPNCRYPTO_H_
+#include <linux/workqueue.h>
+
#include "pktid.h"
#include "proto.h"
@@ -45,8 +47,8 @@ struct ovpn_crypto_key_slot {
struct ovpn_pktid_recv pid_recv ____cacheline_aligned_in_smp;
struct ovpn_pktid_xmit pid_xmit ____cacheline_aligned_in_smp;
+ struct rcu_work free_work;
struct kref refcount;
- struct rcu_head rcu;
};
struct ovpn_crypto_state {
diff --git a/drivers/net/ovpn/crypto_aead.c b/drivers/net/ovpn/crypto_aead.c
index 8f07c418622b2..74eaf6fac2f52 100644
--- a/drivers/net/ovpn/crypto_aead.c
+++ b/drivers/net/ovpn/crypto_aead.c
@@ -9,6 +9,7 @@
#include <crypto/aead.h>
#include <linux/skbuff.h>
+#include <linux/workqueue.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/udp.h>
@@ -380,13 +381,19 @@ static struct crypto_aead *ovpn_aead_init(const char *title,
return ERR_PTR(ret);
}
-void ovpn_aead_crypto_key_slot_destroy(struct ovpn_crypto_key_slot *ks)
+static void ovpn_aead_crypto_key_slot_free(struct ovpn_crypto_key_slot *ks)
{
- if (!ks)
- return;
-
crypto_free_aead(ks->encrypt);
crypto_free_aead(ks->decrypt);
+}
+
+static void ovpn_aead_crypto_key_slot_free_work(struct work_struct *work)
+{
+ struct ovpn_crypto_key_slot *ks;
+
+ ks = container_of(to_rcu_work(work), struct ovpn_crypto_key_slot,
+ free_work);
+ ovpn_aead_crypto_key_slot_free(ks);
kfree(ks);
}
@@ -420,6 +427,7 @@ ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc)
ks->encrypt = NULL;
ks->decrypt = NULL;
+ INIT_RCU_WORK(&ks->free_work, ovpn_aead_crypto_key_slot_free_work);
kref_init(&ks->refcount);
ks->key_id = kc->key_id;
@@ -453,7 +461,8 @@ ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc)
return ks;
destroy_ks:
- ovpn_aead_crypto_key_slot_destroy(ks);
+ ovpn_aead_crypto_key_slot_free(ks);
+ kfree(ks);
return ERR_PTR(ret);
}
diff --git a/drivers/net/ovpn/crypto_aead.h b/drivers/net/ovpn/crypto_aead.h
index 65a2ff3078986..fae3b585a43b3 100644
--- a/drivers/net/ovpn/crypto_aead.h
+++ b/drivers/net/ovpn/crypto_aead.h
@@ -22,7 +22,6 @@ int ovpn_aead_decrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,
struct ovpn_crypto_key_slot *
ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc);
-void ovpn_aead_crypto_key_slot_destroy(struct ovpn_crypto_key_slot *ks);
enum ovpn_cipher_alg ovpn_aead_crypto_alg(struct ovpn_crypto_key_slot *ks);
diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c
index 9a66d693039a3..9526f8096da60 100644
--- a/drivers/net/ovpn/io.c
+++ b/drivers/net/ovpn/io.c
@@ -204,10 +204,10 @@ void ovpn_decrypt_post(void *data, int ret)
ovpn_dev_dstats_rx_dropped(peer->ovpn->dev);
kfree_skb(skb);
drop_nocount:
- if (likely(peer))
- ovpn_peer_put(peer);
if (likely(ks))
ovpn_crypto_key_slot_put(ks);
+ if (likely(peer))
+ ovpn_peer_put(peer);
}
/* RX path entry point: decrypt packet and forward it to the device */
@@ -302,11 +302,11 @@ void ovpn_encrypt_post(void *data, int ret)
err:
if (unlikely(skb))
ovpn_dev_dstats_tx_dropped(peer->ovpn->dev);
- if (likely(peer))
- ovpn_peer_put(peer);
+ kfree_skb(skb);
if (likely(ks))
ovpn_crypto_key_slot_put(ks);
- kfree_skb(skb);
+ if (likely(peer))
+ ovpn_peer_put(peer);
}
static bool ovpn_encrypt_one(struct ovpn_peer *peer, struct sk_buff *skb)
diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
index 168cfe9b59a98..0708249e9607c 100644
--- a/drivers/net/ovpn/main.c
+++ b/drivers/net/ovpn/main.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
+#include <linux/workqueue.h>
#include <net/gro_cells.h>
#include <net/ip.h>
#include <net/rtnetlink.h>
@@ -26,6 +27,9 @@
#include "tcp.h"
#include "udp.h"
+/* module-owned workqueue on which all ovpn-specific work is queued */
+struct workqueue_struct *ovpn_wq;
+
static void ovpn_priv_free(struct net_device *net)
{
struct ovpn_priv *ovpn = netdev_priv(net);
@@ -264,10 +268,16 @@ static int __init ovpn_init(void)
ovpn_tcp_init();
+ ovpn_wq = alloc_workqueue("ovpn", WQ_PERCPU, 0);
+ if (!ovpn_wq) {
+ pr_err("ovpn: cannot allocate workqueue\n");
+ return -ENOMEM;
+ }
+
err = rtnl_link_register(&ovpn_link_ops);
if (err) {
pr_err("ovpn: can't register rtnl link ops: %d\n", err);
- return err;
+ goto destroy_wq;
}
err = ovpn_nl_register();
@@ -280,6 +290,9 @@ static int __init ovpn_init(void)
unreg_rtnl:
rtnl_link_unregister(&ovpn_link_ops);
+destroy_wq:
+ destroy_workqueue(ovpn_wq);
+ ovpn_wq = NULL;
return err;
}
@@ -288,7 +301,11 @@ static __exit void ovpn_cleanup(void)
ovpn_nl_unregister();
rtnl_link_unregister(&ovpn_link_ops);
+ flush_workqueue(ovpn_wq);
rcu_barrier();
+
+ destroy_workqueue(ovpn_wq);
+ ovpn_wq = NULL;
}
module_init(ovpn_init);
diff --git a/drivers/net/ovpn/ovpnpriv.h b/drivers/net/ovpn/ovpnpriv.h
index 5898f6adada7f..84499140e4bd9 100644
--- a/drivers/net/ovpn/ovpnpriv.h
+++ b/drivers/net/ovpn/ovpnpriv.h
@@ -15,6 +15,10 @@
#include <uapi/linux/if_link.h>
#include <uapi/linux/ovpn.h>
+struct workqueue_struct;
+
+extern struct workqueue_struct *ovpn_wq;
+
/**
* struct ovpn_peer_collection - container of peers for MultiPeer mode
* @by_id: table of peers index by ID
diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
index b0519f9840d83..c95656ca7c357 100644
--- a/drivers/net/ovpn/peer.c
+++ b/drivers/net/ovpn/peer.c
@@ -62,7 +62,7 @@ void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout)
/* now that interval and timeout have been changed, kick
* off the worker so that the next delay can be recomputed
*/
- mod_delayed_work(system_percpu_wq, &peer->ovpn->keepalive_work, 0);
+ mod_delayed_work(ovpn_wq, &peer->ovpn->keepalive_work, 0);
}
/**
@@ -1371,7 +1371,7 @@ static time64_t ovpn_peer_keepalive_work_single(struct ovpn_peer *peer,
peer->id);
if (WARN_ON(!ovpn_peer_hold(peer)))
return 0;
- if (!schedule_work(&peer->keepalive_work))
+ if (!queue_work(ovpn_wq, &peer->keepalive_work))
ovpn_peer_put(peer);
}
@@ -1463,8 +1463,8 @@ void ovpn_peer_keepalive_work(struct work_struct *work)
netdev_dbg(ovpn->dev,
"scheduling keepalive work: now=%llu next_run=%llu delta=%llu\n",
next_run, now, next_run - now);
- schedule_delayed_work(&ovpn->keepalive_work,
- (next_run - now) * HZ);
+ queue_delayed_work(ovpn_wq, &ovpn->keepalive_work,
+ (next_run - now) * HZ);
}
unlock_ovpn(ovpn, &release_list);
}
diff --git a/drivers/net/ovpn/tcp.c b/drivers/net/ovpn/tcp.c
index 0af14055c39aa..8fe8a8e750a40 100644
--- a/drivers/net/ovpn/tcp.c
+++ b/drivers/net/ovpn/tcp.c
@@ -151,7 +151,7 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb)
/* take reference for deferred peer deletion. should never fail */
if (WARN_ON(!ovpn_peer_hold(peer)))
goto err_nopeer;
- if (!schedule_work(&peer->tcp.defer_del_work))
+ if (!queue_work(ovpn_wq, &peer->tcp.defer_del_work))
ovpn_peer_put(peer);
ovpn_dev_dstats_rx_dropped(peer->ovpn->dev);
err_nopeer:
@@ -284,13 +284,12 @@ static void ovpn_tcp_send_sock(struct ovpn_peer *peer, struct sock *sk)
* stream therefore we abort the connection
*/
ovpn_peer_hold(peer);
- if (!schedule_work(&peer->tcp.defer_del_work))
+ if (!queue_work(ovpn_wq, &peer->tcp.defer_del_work))
ovpn_peer_put(peer);
/* we bail out immediately and keep tx_in_progress set
* to true. This way we prevent more TX attempts
- * which would lead to more invocations of
- * schedule_work()
+ * which would lead to more invocations of queue_work()
*/
return;
}
@@ -487,7 +486,7 @@ static void ovpn_tcp_write_space(struct sock *sk)
rcu_read_lock();
sock = rcu_dereference_sk_user_data(sk);
if (likely(sock && sock->peer)) {
- schedule_work(&sock->tcp_tx_work);
+ queue_work(ovpn_wq, &sock->tcp_tx_work);
sock->peer->tcp.sk_cb.sk_write_space(sk);
}
rcu_read_unlock();
|
| 3/2 | 2026/08/09 21:52 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 6221 output: 27 thoughts: 544 Thoughts: **Assessing the Impact of the OpenVPN Patch Series** Okay, let's break this down. My initial assessment is that we need to determine if this patch series introduces functional changes to the kernel that warrant fuzzing efforts. The patch touches a significant number of files within the `drivers/net/ovpn` directory: `crypto.c`, `crypto.h`, `crypto_aead.c`, `crypto_aead.h`, `io.c`, `main.c`, `ovpnpriv.h`, `peer.c`, and `tcp.c`. That's a strong indicator of potential functional impact. Now, let's dissect the changes. First, `ovpn_crypto_key_slot_release` is switching from `call_rcu` to `queue_rcu_work` with `ovpn_wq`. This hints at a move towards a workqueue-based mechanism for resource management, which, if mishandled, *could* introduce subtle race conditions or memory corruption scenarios. Next, `ovpn_crypto_kill_key` has a logic change in how it iterates through and replaces pointers within the `cs->slots` structure. This is immediately interesting because pointer manipulation is a known vulnerability area, and this could open up a vector for exploitation. A module-owned workqueue, `ovpn_wq`, is being introduced. This is significant because it centralizes workqueue operations within the `ovpn` module. The addition of `ovpn_aead_crypto_key_slot_free_work` is directly related to the workqueue-based freeing. This looks like a change to how resources are managed, which is good. There is also a change in the order of put calls, which has the potential to introduce issues. Furthermore, `ovpn_wq` is allocated in `ovpn_init` and destroyed in `ovpn_cleanup`, which means that it has a life cycle tied to the module itself. The rest of the mentioned functions, such as `ovpn_peer_keepalive_set`, `ovpn_peer_keepalive_work_single`, etc., now leverage `ovpn_wq` instead of generic workqueues. Given these changes, it's clear this is a functional modification to the OpenVPN (ovpn) driver. The critical question: is this driver *reachable* and amenable to fuzzing? Well, it's a network driver, which means it should be interactable via netlink and sockets. That's a "yes" on reachability. And considering the pointer logic change in `ovpn_crypto_kill_key` combined with the workqueue modifications, this definitely warrants fuzzing efforts. I need to now check the Kconfig for the ovpn driver to confirm its build options. |
| 4/2 | 2026/08/09 21:52 | tool | grepper |
0mArgs:{
"Expression": "config OVPN",
"PathPrefix": "drivers/net/"
}Results: {
"Output": "drivers/net/Kconfig=92=config WIREGUARD_DEBUG\n--\ndrivers/net/Kconfig-102-\ndrivers/net/Kconfig:103:config OVPN\ndrivers/net/Kconfig-104-\ttristate \"OpenVPN data channel offload\"\n"
} |
| 5/2 | 2026/08/09 21:52 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7464 output: 34 thoughts: 27 Thoughts: Okay, here's my take on those thoughts, framed for an expert audience: **Analyzing the OVPN Configuration** Alright, so the config in play here is definitely `OVPN`. My first instinct is to immediately jump into `drivers/net/Kconfig`. I need to figure out the dependencies related to this OpenVPN configuration. We're looking to understand any build-time relationships, required features, or platform-specific considerations for `OVPN` within this kernel context. This is the starting point to identify any missing pieces or potential conflicts before we even think about building the kernel. Let's see what `Kconfig` reveals... |
| 6/2 | 2026/08/09 21:53 | tool | read-file |
0mArgs:{
"File": "drivers/net/Kconfig",
"FirstLine": 100,
"LineCount": 20
}Results: {
"Contents": " 100:\t\n 101:\t\t Say N here unless you know what you're doing.\n 102:\t\n 103:\tconfig OVPN\n 104:\t\ttristate \"OpenVPN data channel offload\"\n 105:\t\tdepends on NET \u0026\u0026 INET\n 106:\t\tselect DST_CACHE\n 107:\t\tselect NET_UDP_TUNNEL\n 108:\t\tselect CRYPTO\n 109:\t\tselect CRYPTO_AES\n 110:\t\tselect CRYPTO_GCM\n 111:\t\tselect CRYPTO_CHACHA20POLY1305\n 112:\t\tselect STREAM_PARSER\n 113:\t\thelp\n 114:\t\t This module enhances the performance of the OpenVPN userspace software\n 115:\t\t by offloading the data channel processing to kernelspace.\n 116:\t\n 117:\tconfig EQUALIZER\n 118:\t\ttristate \"EQL (serial line load balancing) support\"\n 119:\t\thelp\n"
} |
| 7/2 | 2026/08/09 21:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7934 output: 35 thoughts: 457 Thoughts: **Analyzing OpenVPN Configuration Options** Okay, let's break this down. First, I see the dependencies: `NET` and `INET`. That's standard stuff for network functionality. The selected options are interesting: `DST_CACHE`, which probably means some kind of destination caching, which is an optimization strategy for routing and connection setup; `NET_UDP_TUNNEL`, suggesting UDP tunneling, as expected with OpenVPN; `CRYPTO`, which is a given; then we have the specific cryptographic algorithms – `CRYPTO_AES`, `CRYPTO_GCM`, `CRYPTO_CHACHA20POLY1305` which indicates AES, Galois/Counter Mode, and ChaCha20-Poly1305 encryption support, respectively, and `STREAM_PARSER`, which is almost certainly about parsing the incoming data stream. Right, so to enable the relevant OpenVPN configuration, the key here is `OVPN`. That's our target. Now, where are the key changes? I need to focus on the key areas. I see a list of modified functions. I'm going to run through these in my head. * `ovpn_crypto_key_slot_release`, and `ovpn_crypto_kill_key` these deal with cryptographic keys, likely managing their lifecycle. `ovpn_aead_crypto_key_slot_free_work`, `ovpn_aead_crypto_key_slot_new`, this deals with AEAD ciphers, so probably part of the initial cryptographic setup, or key management. * `ovpn_decrypt_post`, `ovpn_encrypt_post`, these are post-processing steps. * `ovpn_init`, `ovpn_cleanup`, the basic lifecycle. * `ovpn_peer_keepalive_set`, `ovpn_peer_keepalive_work_single`, `ovpn_peer_keepalive_work` which seems to be about keepalive functionality. * `ovpn_tcp_rcv`, `ovpn_tcp_send_sock`, `ovpn_tcp_write_space` is the TCP functionality. Okay, let's hone in on the important functions, this is the core: `ovpn_crypto_key_slot_release`, `ovpn_crypto_kill_key`, `ovpn_aead_crypto_key_slot_new`, `ovpn_peer_keepalive_set`, `ovpn_peer_keepalive_work`. Now, are they exported or static? Ah, good, they're not static, meaning they're accessible from outside the current scope. That is important to remember. This strongly suggests that these functions are entry points or core management functions. I need to keep in mind, I need to verify these functions. This is where the core changes are happening, the cryptographic key management and keepalive mechanisms, so let me take a closer look and begin from there. |
| 8/2 | 2026/08/09 21:53 | tool | grepper |
0mArgs:{
"Expression": "ovpn_crypto_kill_key",
"PathPrefix": "drivers/net/ovpn/"
}Results: {
"Output": "drivers/net/ovpn/crypto.c=32=void ovpn_crypto_state_release(struct ovpn_crypto_state *cs)\n--\ndrivers/net/ovpn/crypto.c-49-/* removes the key matching the specified id from the crypto context */\ndrivers/net/ovpn/crypto.c:50:bool ovpn_crypto_kill_key(struct ovpn_crypto_state *cs, u8 key_id)\ndrivers/net/ovpn/crypto.c-51-{\n--\ndrivers/net/ovpn/crypto.h=141=int ovpn_crypto_config_get(struct ovpn_crypto_state *cs,\n--\ndrivers/net/ovpn/crypto.h-144-\ndrivers/net/ovpn/crypto.h:145:bool ovpn_crypto_kill_key(struct ovpn_crypto_state *cs, u8 key_id);\ndrivers/net/ovpn/crypto.h-146-\n--\ndrivers/net/ovpn/io.c=238=void ovpn_encrypt_post(void *data, int ret)\n--\ndrivers/net/ovpn/io.c-264-\t\t\t peer-\u003eid);\ndrivers/net/ovpn/io.c:265:\t\tif (ovpn_crypto_kill_key(\u0026peer-\u003ecrypto, ks-\u003ekey_id))\ndrivers/net/ovpn/io.c-266-\t\t\t/* let userspace know so that a new key must be negotiated */\n"
} |
| 9/2 | 2026/08/09 21:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 9432 output: 36 thoughts: 47 Thoughts: Okay, here's my interpretation of those thoughts, framed as my own: **Data Path Concerns and Keepalive Integration** Right, so I'm focusing on the OpenVPN kernel module here. The critical function `ovpn_crypto_kill_key` – that's a key management function, likely dealing with crypto key cleanup – it's directly called from `ovpn_encrypt_post`. And `ovpn_encrypt_post`, that's firmly in the *data path*. Meaning any inefficiency there has an immediate impact on throughput and latency. We need to be *very* mindful of the performance characteristics of that `ovpn_crypto_kill_key` call, especially its synchronization or potential locking. Any blocking in key management will bleed directly into the encrypt and transmit time. On the other hand, `ovpn_peer_keepalive_set` is being called from *netlink*. Interesting. That likely ties into the control plane, setting keepalive parameters for a peer, probably in response to user configuration or network events. This suggests a control path integration, with potential to trigger keepalive behaviour on certain conditions. We should make sure we're managing the interactions between these two paths efficiently. Are there any race conditions, data inconsistencies, or contention possibilities that we need to scrutinize carefully? I need to think about how these two independent pieces, data path encryption/key handling and control path keepalives, play together. Any unexpected behaviour on one side will influence the other, this could impact network stability. |
| 10/2 | 2026/08/09 21:53 | tool | grepper |
0mArgs:{
"Expression": "ovpn_peer_keepalive_set",
"PathPrefix": "drivers/net/ovpn/"
}Results: {
"Output": "drivers/net/ovpn/netlink.c=279=static int ovpn_nl_peer_modify(struct ovpn_peer *peer, struct genl_info *info,\n--\ndrivers/net/ovpn/netlink.c-330-\t\ttimeout = nla_get_u32(attrs[OVPN_A_PEER_KEEPALIVE_TIMEOUT]);\ndrivers/net/ovpn/netlink.c:331:\t\tovpn_peer_keepalive_set(peer, interv, timeout);\ndrivers/net/ovpn/netlink.c-332-\t}\n--\ndrivers/net/ovpn/peer.c=25=static void unlock_ovpn(struct ovpn_priv *ovpn,\n--\ndrivers/net/ovpn/peer.c-40-/**\ndrivers/net/ovpn/peer.c:41: * ovpn_peer_keepalive_set - configure keepalive values for peer\ndrivers/net/ovpn/peer.c-42- * @peer: the peer to configure\n--\ndrivers/net/ovpn/peer.c-45- */\ndrivers/net/ovpn/peer.c:46:void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout)\ndrivers/net/ovpn/peer.c-47-{\n--\ndrivers/net/ovpn/peer.h=154=bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,\n--\ndrivers/net/ovpn/peer.h-156-\ndrivers/net/ovpn/peer.h:157:void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout);\ndrivers/net/ovpn/peer.h-158-void ovpn_peer_keepalive_work(struct work_struct *work);\n"
} |
| 11/2 | 2026/08/09 21:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 10316 output: 37 thoughts: 37 Thoughts: Here's my understanding, as if these were my internal thoughts: **Reflecting on OpenVPN Optimization** Okay, so I'm looking at these OpenVPN-related bits and pieces. *`ovpn_peer_keepalive_set`*, yes, that looks promising, good to see that being used, probably for keeping those connections healthy and alive – always a key concern with VPNs. And then... *`ovpn_crypto_key_slot_release`* – ah, right, that's the cleanup mechanism for cryptographic keys, handling their release when the reference count hits zero. That's exactly how it should be. Ensures we're not leaking resources and keeps things secure. Good, efficient memory management is critical here. |
| 12/2 | 2026/08/09 21:53 | tool | grepper |
0mArgs:{
"Expression": "ovpn_crypto_key_slot_release",
"PathPrefix": "drivers/net/ovpn/"
}Results: {
"Output": "drivers/net/ovpn/crypto.c-20-\ndrivers/net/ovpn/crypto.c:21:void ovpn_crypto_key_slot_release(struct kref *kref)\ndrivers/net/ovpn/crypto.c-22-{\n--\ndrivers/net/ovpn/crypto.h=111=ovpn_crypto_key_slot_primary(const struct ovpn_crypto_state *cs)\n--\ndrivers/net/ovpn/crypto.h-123-\ndrivers/net/ovpn/crypto.h:124:void ovpn_crypto_key_slot_release(struct kref *kref);\ndrivers/net/ovpn/crypto.h-125-\ndrivers/net/ovpn/crypto.h=126=static inline void ovpn_crypto_key_slot_put(struct ovpn_crypto_key_slot *ks)\ndrivers/net/ovpn/crypto.h-127-{\ndrivers/net/ovpn/crypto.h:128:\tkref_put(\u0026ks-\u003erefcount, ovpn_crypto_key_slot_release);\ndrivers/net/ovpn/crypto.h-129-}\n"
} |
| 13/2 | 2026/08/09 21:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 10844 output: 40 thoughts: 35 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Analyzing OpenVPN Crypto Key Management** Alright, *ovpn\_crypto\_key\_slot\_release* is precisely what I'd expect to see in a key management system, the expected release of the key slot is good for memory management. That's a solid start. Now, let's drill down a bit deeper into the lifecycle. The natural place to look next is its counterpart, the allocation function: *ovpn\_aead\_crypto\_key\_slot\_new*. I need to understand how these new slots are created. I wonder if there are any specific checks on this function that need to be made. Are they linked, in terms of resource management, or are there separate management functions that overlap? What does the allocation process actually entail – memory allocation, key derivation/generation, initialization of the underlying crypto context? I need to check the potential for vulnerabilities, such as uninitialized memory being used, improper key derivation, or insufficient entropy sourcing during the key generation. I want to look for potential lock-ups too. The more I can understand about this critical pairing, the more effective my overall analysis of OpenVPN's crypto implementation can be. |
| 14/2 | 2026/08/09 21:53 | tool | grepper |
0mArgs:{
"Expression": "ovpn_aead_crypto_key_slot_new",
"PathPrefix": "drivers/net/ovpn/"
}Results: {
"Output": "drivers/net/ovpn/crypto.c=78=int ovpn_crypto_state_reset(struct ovpn_crypto_state *cs,\n--\ndrivers/net/ovpn/crypto.c-87-\ndrivers/net/ovpn/crypto.c:88:\tnew = ovpn_aead_crypto_key_slot_new(\u0026pkr-\u003ekey);\ndrivers/net/ovpn/crypto.c-89-\tif (IS_ERR(new))\n--\ndrivers/net/ovpn/crypto_aead.c=400=struct ovpn_crypto_key_slot *\ndrivers/net/ovpn/crypto_aead.c:401:ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc)\ndrivers/net/ovpn/crypto_aead.c-402-{\n--\ndrivers/net/ovpn/crypto_aead.h=23=struct ovpn_crypto_key_slot *\ndrivers/net/ovpn/crypto_aead.h:24:ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc);\ndrivers/net/ovpn/crypto_aead.h-25-\n"
} |
| 15/2 | 2026/08/09 21:53 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 11486 output: 180 thoughts: 281 Thoughts: **Analyzing the OpenVPN Data Channel Offload Driver Patch** Okay, so `ovpn_aead_crypto_key_slot_new` looks solid, good starting point. My focus, then, needs to be on these symbols: `ovpn_crypto_key_slot_release`, `ovpn_crypto_kill_key`, `ovpn_aead_crypto_key_slot_new`, `ovpn_peer_keepalive_set`, and `ovpn_peer_keepalive_work`. This is about how the crypto keys are handled in the offload driver. The patch is touching the OpenVPN data channel offload driver (`drivers/net/ovpn`), so it's a functional change in a reachable network driver – always something to pay close attention to. Specifically, it's swapping `call_rcu` for `queue_rcu_work` for crypto key slot freeing, which is a good move for increased efficiency and reduced contention. They're introducing a dedicated workqueue (`ovpn_wq`) for all ovpn-specific work, and fixing a logic bug in `ovpn_crypto_kill_key`. These are all crucial improvements, and this is good to see as it streamlines operations. Now, let me just confirm the configurations are all in order. They're referencing `OVPN`, which depends on `NET` and `INET`, which is expected. Looks like it also selects `DST_CACHE`, `NET_UDP_TUNNEL`, `CRYPTO`, `CRYPTO_AES`, `CRYPTO_GCM`, `CRYPTO_CHACHA20POLY1305`, and `STREAM_PARSER`. Good, the configuration is sufficient. Seems like everything checks out. |
| 16/2 | 2026/08/09 21:53 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"OVPN"
],
"FocusSymbols": [
"ovpn_crypto_key_slot_release",
"ovpn_crypto_kill_key",
"ovpn_aead_crypto_key_slot_new",
"ovpn_peer_keepalive_set",
"ovpn_peer_keepalive_work"
],
"Reasoning": "The patch modifies the OpenVPN data channel offload driver (drivers/net/ovpn). It replaces call_rcu with queue_rcu_work for freeing crypto key slots, introduces a dedicated workqueue (ovpn_wq) for all ovpn-specific work, and fixes a logic bug in ovpn_crypto_kill_key. These are functional changes in a reachable network driver.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"OVPN"
],
"FocusSymbols": [
"ovpn_crypto_key_slot_release",
"ovpn_crypto_kill_key",
"ovpn_aead_crypto_key_slot_new",
"ovpn_peer_keepalive_set",
"ovpn_peer_keepalive_work"
],
"Reasoning": "The patch modifies the OpenVPN data channel offload driver (drivers/net/ovpn). It replaces call_rcu with queue_rcu_work for freeing crypto key slots, introduces a dedicated workqueue (ovpn_wq) for all ovpn-specific work, and fixes a logic bug in ovpn_crypto_kill_key. These are functional changes in a reachable network driver.",
"WorthFuzzing": true
} |
| 17/1 | 2026/08/09 21:53 | action | If |
0mArgs:{
"WorthFuzzing": true
}Results: null |
| 18/2 | 2026/08/09 21:53 | agent | kmsan-evaluator |
0mModel:best-expensive Args: null Results: {
"KMSANReasoning": "The patch series focuses on fixing a NULL pointer dereference in `ovpn_crypto_kill_key`, reordering cleanup functions to prevent potential use-after-free bugs, and migrating work items from the system workqueue to a dedicated `ovpn_wq` workqueue. These changes address memory safety issues (NULL dereferences, UAF) and concurrency management, which are effectively detected by standard KASAN and LOCKDEP. There are no modifications to structures copied to user space, no new buffer allocations that could leak uninitialized memory, and no changes to data length calculations that would expose uninitialized bytes. Therefore, a dedicated KMSAN fuzzing session is not required.",
"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 a95f26db5222d62a1fe39240c48f8e0aeb916609
Author: syz-cluster <triage@syzkaller.com>
Date: Sun Aug 9 21:52:50 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/ovpn/crypto.c b/drivers/net/ovpn/crypto.c
index 90580e32052fb..7e545428900a9 100644
--- a/drivers/net/ovpn/crypto.c
+++ b/drivers/net/ovpn/crypto.c
@@ -18,20 +18,12 @@
#include "crypto_aead.h"
#include "crypto.h"
-static void ovpn_ks_destroy_rcu(struct rcu_head *head)
-{
- struct ovpn_crypto_key_slot *ks;
-
- ks = container_of(head, struct ovpn_crypto_key_slot, rcu);
- ovpn_aead_crypto_key_slot_destroy(ks);
-}
-
void ovpn_crypto_key_slot_release(struct kref *kref)
{
struct ovpn_crypto_key_slot *ks;
ks = container_of(kref, struct ovpn_crypto_key_slot, refcount);
- call_rcu(&ks->rcu, ovpn_ks_destroy_rcu);
+ queue_rcu_work(ovpn_wq, &ks->free_work);
}
/* can only be invoked when all peer references have been dropped (i.e. RCU
@@ -58,15 +50,19 @@ void ovpn_crypto_state_release(struct ovpn_crypto_state *cs)
bool ovpn_crypto_kill_key(struct ovpn_crypto_state *cs, u8 key_id)
{
struct ovpn_crypto_key_slot *ks = NULL;
+ struct ovpn_crypto_key_slot *tmp;
+ int slot = 0;
spin_lock_bh(&cs->lock);
- if (rcu_access_pointer(cs->slots[0])->key_id == key_id) {
- ks = rcu_replace_pointer(cs->slots[0], NULL,
- lockdep_is_held(&cs->lock));
- } else if (rcu_access_pointer(cs->slots[1])->key_id == key_id) {
- ks = rcu_replace_pointer(cs->slots[1], NULL,
- lockdep_is_held(&cs->lock));
+ tmp = rcu_access_pointer(cs->slots[slot]);
+ if (!tmp || tmp->key_id != key_id) {
+ slot = 1;
+ tmp = rcu_access_pointer(cs->slots[slot]);
}
+
+ if (tmp && tmp->key_id == key_id)
+ ks = rcu_replace_pointer(cs->slots[slot], NULL,
+ lockdep_is_held(&cs->lock));
spin_unlock_bh(&cs->lock);
if (ks)
diff --git a/drivers/net/ovpn/crypto.h b/drivers/net/ovpn/crypto.h
index 0e284fec3a75a..e3feb16d54985 100644
--- a/drivers/net/ovpn/crypto.h
+++ b/drivers/net/ovpn/crypto.h
@@ -10,6 +10,8 @@
#ifndef _NET_OVPN_OVPNCRYPTO_H_
#define _NET_OVPN_OVPNCRYPTO_H_
+#include <linux/workqueue.h>
+
#include "pktid.h"
#include "proto.h"
@@ -45,8 +47,8 @@ struct ovpn_crypto_key_slot {
struct ovpn_pktid_recv pid_recv ____cacheline_aligned_in_smp;
struct ovpn_pktid_xmit pid_xmit ____cacheline_aligned_in_smp;
+ struct rcu_work free_work;
struct kref refcount;
- struct rcu_head rcu;
};
struct ovpn_crypto_state {
diff --git a/drivers/net/ovpn/crypto_aead.c b/drivers/net/ovpn/crypto_aead.c
index 8f07c418622b2..74eaf6fac2f52 100644
--- a/drivers/net/ovpn/crypto_aead.c
+++ b/drivers/net/ovpn/crypto_aead.c
@@ -9,6 +9,7 @@
#include <crypto/aead.h>
#include <linux/skbuff.h>
+#include <linux/workqueue.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/udp.h>
@@ -380,13 +381,19 @@ static struct crypto_aead *ovpn_aead_init(const char *title,
return ERR_PTR(ret);
}
-void ovpn_aead_crypto_key_slot_destroy(struct ovpn_crypto_key_slot *ks)
+static void ovpn_aead_crypto_key_slot_free(struct ovpn_crypto_key_slot *ks)
{
- if (!ks)
- return;
-
crypto_free_aead(ks->encrypt);
crypto_free_aead(ks->decrypt);
+}
+
+static void ovpn_aead_crypto_key_slot_free_work(struct work_struct *work)
+{
+ struct ovpn_crypto_key_slot *ks;
+
+ ks = container_of(to_rcu_work(work), struct ovpn_crypto_key_slot,
+ free_work);
+ ovpn_aead_crypto_key_slot_free(ks);
kfree(ks);
}
@@ -420,6 +427,7 @@ ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc)
ks->encrypt = NULL;
ks->decrypt = NULL;
+ INIT_RCU_WORK(&ks->free_work, ovpn_aead_crypto_key_slot_free_work);
kref_init(&ks->refcount);
ks->key_id = kc->key_id;
@@ -453,7 +461,8 @@ ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc)
return ks;
destroy_ks:
- ovpn_aead_crypto_key_slot_destroy(ks);
+ ovpn_aead_crypto_key_slot_free(ks);
+ kfree(ks);
return ERR_PTR(ret);
}
diff --git a/drivers/net/ovpn/crypto_aead.h b/drivers/net/ovpn/crypto_aead.h
index 65a2ff3078986..fae3b585a43b3 100644
--- a/drivers/net/ovpn/crypto_aead.h
+++ b/drivers/net/ovpn/crypto_aead.h
@@ -22,7 +22,6 @@ int ovpn_aead_decrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,
struct ovpn_crypto_key_slot *
ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc);
-void ovpn_aead_crypto_key_slot_destroy(struct ovpn_crypto_key_slot *ks);
enum ovpn_cipher_alg ovpn_aead_crypto_alg(struct ovpn_crypto_key_slot *ks);
diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c
index 9a66d693039a3..9526f8096da60 100644
--- a/drivers/net/ovpn/io.c
+++ b/drivers/net/ovpn/io.c
@@ -204,10 +204,10 @@ void ovpn_decrypt_post(void *data, int ret)
ovpn_dev_dstats_rx_dropped(peer->ovpn->dev);
kfree_skb(skb);
drop_nocount:
- if (likely(peer))
- ovpn_peer_put(peer);
if (likely(ks))
ovpn_crypto_key_slot_put(ks);
+ if (likely(peer))
+ ovpn_peer_put(peer);
}
/* RX path entry point: decrypt packet and forward it to the device */
@@ -302,11 +302,11 @@ void ovpn_encrypt_post(void *data, int ret)
err:
if (unlikely(skb))
ovpn_dev_dstats_tx_dropped(peer->ovpn->dev);
- if (likely(peer))
- ovpn_peer_put(peer);
+ kfree_skb(skb);
if (likely(ks))
ovpn_crypto_key_slot_put(ks);
- kfree_skb(skb);
+ if (likely(peer))
+ ovpn_peer_put(peer);
}
static bool ovpn_encrypt_one(struct ovpn_peer *peer, struct sk_buff *skb)
diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
index 168cfe9b59a98..0708249e9607c 100644
--- a/drivers/net/ovpn/main.c
+++ b/drivers/net/ovpn/main.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
+#include <linux/workqueue.h>
#include <net/gro_cells.h>
#include <net/ip.h>
#include <net/rtnetlink.h>
@@ -26,6 +27,9 @@
#include "tcp.h"
#include "udp.h"
+/* module-owned workqueue on which all ovpn-specific work is queued */
+struct workqueue_struct *ovpn_wq;
+
static void ovpn_priv_free(struct net_device *net)
{
struct ovpn_priv *ovpn = netdev_priv(net);
@@ -264,10 +268,16 @@ static int __init ovpn_init(void)
ovpn_tcp_init();
+ ovpn_wq = alloc_workqueue("ovpn", WQ_PERCPU, 0);
+ if (!ovpn_wq) {
+ pr_err("ovpn: cannot allocate workqueue\n");
+ return -ENOMEM;
+ }
+
err = rtnl_link_register(&ovpn_link_ops);
if (err) {
pr_err("ovpn: can't register rtnl link ops: %d\n", err);
- return err;
+ goto destroy_wq;
}
err = ovpn_nl_register();
@@ -280,6 +290,9 @@ static int __init ovpn_init(void)
unreg_rtnl:
rtnl_link_unregister(&ovpn_link_ops);
+destroy_wq:
+ destroy_workqueue(ovpn_wq);
+ ovpn_wq = NULL;
return err;
}
@@ -288,7 +301,11 @@ static __exit void ovpn_cleanup(void)
ovpn_nl_unregister();
rtnl_link_unregister(&ovpn_link_ops);
+ flush_workqueue(ovpn_wq);
rcu_barrier();
+
+ destroy_workqueue(ovpn_wq);
+ ovpn_wq = NULL;
}
module_init(ovpn_init);
diff --git a/drivers/net/ovpn/ovpnpriv.h b/drivers/net/ovpn/ovpnpriv.h
index 5898f6adada7f..84499140e4bd9 100644
--- a/drivers/net/ovpn/ovpnpriv.h
+++ b/drivers/net/ovpn/ovpnpriv.h
@@ -15,6 +15,10 @@
#include <uapi/linux/if_link.h>
#include <uapi/linux/ovpn.h>
+struct workqueue_struct;
+
+extern struct workqueue_struct *ovpn_wq;
+
/**
* struct ovpn_peer_collection - container of peers for MultiPeer mode
* @by_id: table of peers index by ID
diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
index b0519f9840d83..c95656ca7c357 100644
--- a/drivers/net/ovpn/peer.c
+++ b/drivers/net/ovpn/peer.c
@@ -62,7 +62,7 @@ void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout)
/* now that interval and timeout have been changed, kick
* off the worker so that the next delay can be recomputed
*/
- mod_delayed_work(system_percpu_wq, &peer->ovpn->keepalive_work, 0);
+ mod_delayed_work(ovpn_wq, &peer->ovpn->keepalive_work, 0);
}
/**
@@ -1371,7 +1371,7 @@ static time64_t ovpn_peer_keepalive_work_single(struct ovpn_peer *peer,
peer->id);
if (WARN_ON(!ovpn_peer_hold(peer)))
return 0;
- if (!schedule_work(&peer->keepalive_work))
+ if (!queue_work(ovpn_wq, &peer->keepalive_work))
ovpn_peer_put(peer);
}
@@ -1463,8 +1463,8 @@ void ovpn_peer_keepalive_work(struct work_struct *work)
netdev_dbg(ovpn->dev,
"scheduling keepalive work: now=%llu next_run=%llu delta=%llu\n",
next_run, now, next_run - now);
- schedule_delayed_work(&ovpn->keepalive_work,
- (next_run - now) * HZ);
+ queue_delayed_work(ovpn_wq, &ovpn->keepalive_work,
+ (next_run - now) * HZ);
}
unlock_ovpn(ovpn, &release_list);
}
diff --git a/drivers/net/ovpn/tcp.c b/drivers/net/ovpn/tcp.c
index 0af14055c39aa..8fe8a8e750a40 100644
--- a/drivers/net/ovpn/tcp.c
+++ b/drivers/net/ovpn/tcp.c
@@ -151,7 +151,7 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb)
/* take reference for deferred peer deletion. should never fail */
if (WARN_ON(!ovpn_peer_hold(peer)))
goto err_nopeer;
- if (!schedule_work(&peer->tcp.defer_del_work))
+ if (!queue_work(ovpn_wq, &peer->tcp.defer_del_work))
ovpn_peer_put(peer);
ovpn_dev_dstats_rx_dropped(peer->ovpn->dev);
err_nopeer:
@@ -284,13 +284,12 @@ static void ovpn_tcp_send_sock(struct ovpn_peer *peer, struct sock *sk)
* stream therefore we abort the connection
*/
ovpn_peer_hold(peer);
- if (!schedule_work(&peer->tcp.defer_del_work))
+ if (!queue_work(ovpn_wq, &peer->tcp.defer_del_work))
ovpn_peer_put(peer);
/* we bail out immediately and keep tx_in_progress set
* to true. This way we prevent more TX attempts
- * which would lead to more invocations of
- * schedule_work()
+ * which would lead to more invocations of queue_work()
*/
return;
}
@@ -487,7 +486,7 @@ static void ovpn_tcp_write_space(struct sock *sk)
rcu_read_lock();
sock = rcu_dereference_sk_user_data(sk);
if (likely(sock && sock->peer)) {
- schedule_work(&sock->tcp_tx_work);
+ queue_work(ovpn_wq, &sock->tcp_tx_work);
sock->peer->tcp.sk_cb.sk_write_space(sk);
}
rcu_read_unlock();
|
| 19/3 | 2026/08/09 21:53 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 6218 output: 163 thoughts: 1163 Thoughts: **KMSAN Assessment: OpenVPN Driver Patch Series** Okay, let's break down this `ovpn` driver patch series. My initial concern, as always, is whether these changes could potentially introduce memory safety issues or information leaks, specifically those that KMSAN would flag. The core of the patch involves refactoring the driver's workqueue management. We're moving from the standard system workqueue to a dedicated `ovpn_wq`. This involves replacing calls to `schedule_work`, `schedule_delayed_work`, and `call_rcu` with `queue_work`, `queue_delayed_work`, and `queue_rcu_work`, respectively, all directed to this new `ovpn_wq`. Seems like a standard isolation/performance optimization. Beyond the workqueue changes, there are several other notable modifications. `ovpn_crypto_kill_key` has been updated, and I need to look closer at that to ensure there are no subtle issues. Also, there's a reordering of `kfree_skb` and `ovpn_peer_put`/`ovpn_crypto_key_slot_put` within the `ovpn_decrypt_post` and `ovpn_encrypt_post` functions. That screams potential use-after-free, or a cleanup order that needed to be more careful. Now, let's dig into the details: 1. `ovpn_crypto_key_slot_release` now uses `queue_rcu_work`. This is fine, using RCU correctly is good. 2. `ovpn_crypto_kill_key` has been modified. Alright, let's zoom in on that code snippet. The *old* code had a potential NULL pointer dereference! It directly accessed `tmp->key_id` without checking if `cs->slots[0]` or `cs->slots[1]` was actually valid. This is a clear bug fix, ensuring `tmp` is valid before dereferencing. This is *good*, a classic NULL pointer dereference vulnerability fix. 3. `ovpn_aead_crypto_key_slot_free_work` has been introduced. This is probably related to the workqueue and RCU cleanup. Again, expected with the workqueue changes. 4. The reordering of `kfree_skb` and `ovpn_peer_put` in `ovpn_decrypt_post` and `ovpn_encrypt_post`. Previously, the code freed the skb *before* possibly releasing the peer. Now we have a safer order. This is a potential UAF fix; it's a good change. 5. The `ovpn_wq` is created and destroyed appropriately. Sounds clean, no issues there. 6. The workqueue calls are being replaced consistently. Workqueue management, nothing critical in itself. Analyzing the code: None of these changes appear to introduce any new data structures exposed to user space, nor do they add complex conditional logic based on uninitialized variables. The changes are largely focused on: workqueue management (which is a safe refactoring), proper RCU destruction, and fixing known memory safety issues. In particular, the changes to `ovpn_crypto_kill_key` and the reordering of `kfree_skb` are critical, classic bug fixes. The reordering is almost certainly to avoid UAF, so is a good thing to find. Since these changes address known memory safety vulnerabilities and improve general code hygiene, *and* do not introduce any new risky behavior in terms of data structures or information leaks, I can comfortably say that KMSAN is unlikely to flag anything here. This looks like a standard set of bug fixes and improvements to workqueue management. No need for special KMSAN testing. **Therefore, the answer is NeedsKMSAN = false.** |
| 20/3 | 2026/08/09 21:53 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch series focuses on fixing a NULL pointer dereference in `ovpn_crypto_kill_key`, reordering cleanup functions to prevent potential use-after-free bugs, and migrating work items from the system workqueue to a dedicated `ovpn_wq` workqueue. These changes address memory safety issues (NULL dereferences, UAF) and concurrency management, which are effectively detected by standard KASAN and LOCKDEP. There are no modifications to structures copied to user space, no new buffer allocations that could leak uninitialized memory, and no changes to data length calculations that would expose uninitialized bytes. Therefore, a dedicated KMSAN fuzzing session is not required.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch series focuses on fixing a NULL pointer dereference in `ovpn_crypto_kill_key`, reordering cleanup functions to prevent potential use-after-free bugs, and migrating work items from the system workqueue to a dedicated `ovpn_wq` workqueue. These changes address memory safety issues (NULL dereferences, UAF) and concurrency management, which are effectively detected by standard KASAN and LOCKDEP. There are no modifications to structures copied to user space, no new buffer allocations that could leak uninitialized memory, and no changes to data length calculations that would expose uninitialized bytes. Therefore, a dedicated KMSAN fuzzing session is not required.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|