| 0/0 |
2026/07/30 00:05 |
flow |
assessment-security |
8m
Error:
|
| 1/1 |
2026/07/30 00:05 |
action |
syz-repro-to-c-repro |
0m
Results:
|
| 2/1 |
2026/07/30 00:05 |
action |
kernel-checkouter |
0m
Results: map[KernelSrc:/app/workdir/cache/src/bc72b0baf0345f0b613f258c98b80ee7d9215ac1]
|
| 3/1 |
2026/07/30 00:05 |
action |
kernel-builder |
0m
Results: map[KernelObj:/app/workdir/cache/build/8dbafce49c4e73348834a7f02ab3e9aa0ec73fc5]
|
| 4/1 |
2026/07/30 00:05 |
action |
codesearch-prepare |
0m
Results: map[Index:codesearch-index]
|
| 5/1 |
2026/07/30 00:05 |
agent |
expert |
7m
Model:
Error:
Instruction: You are an experienced Linux kernel security engineer. Your task is to analyze given kernel bug report
and determine its security impact based on the following dimensions.
Use the provided tools to examine the source code, check for capability checks (e.g., capable(), ns_capable()),
and understand the nature of the bug. Analyze the given kernel build and configuration.
You can check the kernel config by grepping ".config" file; you can check kernel cmdline by grepping
".config" file for "CONFIG_CMDLINE=". Assume sysctl parameters have default values.
But analyze for the corresponding production build w/o debugging tools enabled (like KASAN, KMSAN, UBSAN).
Try different strategies when analyzing the bug:
- think of ways in which the vulnerable code is unreachable
- or the other way around: try to come up with different ideas of how an unprivileged user can reach the bug
If still unsure err on the side of the bug being non-exploitable/not-accessible.
In the final reply, provide a reasoning for your assessment.
Analysis dimensions:
* Exploitable:
Determine if the bug can result in memory corruption, elevated privileges, or an information leak.
Memory safety issues are almost always exploitable (KASAN or UBSAN reports for use-after-free, out-of-bounds;
refcounting issues, corrupted lists, etc). When kernel is crashing on a completely wild pointer access
(e.g. user-space address, or non-canonical address, but not on NULL or address corresponding to KASAN shadow
for NULL address), including both data accesses and control transfers, that also usually implies possibility
of exploitation. Such reports usually say "unable to handle kernel paging request".
Uses of uninitialized values detected by KMSAN may be exploitable b/c attacker frequently can affect uninit
values with spraying techniques. However, for these exploitability depends on how exactly the uninit value
is used in the code, and what it affects.
Information leaks are exploitable on their own and should be classified as such. A bug that copies kernel
memory contents to userspace (e.g. an out-of-bounds read whose result is returned to the caller, or
uninitialized stack/heap bytes written to a user buffer) is exploitable: it can reveal kernel pointer
values and defeat KASLR, expose sensitive data such as cryptographic keys or other processes' memory, and
serves as a necessary building block in most modern kernel privilege-escalation exploit chains. Do not classify
an information leak as non-exploitable solely because it does not directly cause a memory write or control-flow
hijack; the leak itself is the exploit primitive.
Think of what happens after the bug is triggered. Some bugs cause kernel panic and halt execution,
they are harder to exploit. For example, BUG reports halts the kernel. However, WARNING reports don't halt
execution in production builds. Debug bug detection tools (like KASAN, KMSAN, KCSAN, UBSAN) are also not enabled
in production builds, so attacker can freely exploit these bugs w/o being detected by these tools.
If you see an integer overflow, think how the overflowed value used later (if it's used as allocation size,
or an array index). If you see an out-of-bounds read, think if it's followed by an out-of-bounds write as well.
Some KCSAN data-races may be exploitable by skilled attackers as well. Think what data structures got corrupted
as the result of data races and how. However, note that kernel has lots of "benign" data races that don't lead
to any runtime misbehavior at all.
* Denial Of Service:
Determine if the bug can result in denial-of-service. Most bugs can, since they cause system crash,
hangs, deadlocks, or resource leaks. This is mostly applicable to WARNING bugs that won't cause system crash
in production. For these think what will be consequences of the violation of the kernel assumptions flagged
by the WARNING. In some cases the unexpected condition is also properly handled by the normal control flow
(e.g. with "if (WARN_ON(...))"), these won't cause denial-of-service. If the condition is not handled,
then it may or may not cause denial-of-service.
* Accessible From Unprivileged Processes:
Determine if the bug can be reached from a typical (non-root) user process that does NOT have any special capabilities
(like CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_NET_RAW, CAP_PERFMON) or access to device nodes restricted to root.
Assume that unprivileged_bpf_disabled=1, that is eBPF loading is not accessible. However, cBPF (classical BPF)
is still accessible to non-root processes.
Assume that user namespaces are not accessible, that is, the process cannot get the mentioned capabilities even
within a new user namespace (checked by ns_capable() function in the kernel sources).
* Accessible From User Namespaces:
Determine if the bug can be reached within a user-namespace where the process has all capabilities
(including CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_NET_RAW, CAP_PERFMON). Such capabilities are checked with ns_capable()
function in the kernel sources.
* VM Guest Trigger:
Determine if the bug can be triggered from the context of a typical KVM guest (e.g., set up by a QEMU VMM).
Consider accesses to standard Linux host paravirtualized features (virtio-blk, virtio-net, etc.),
and handling of VM exits in the KVM code.
* VM Host Trigger in The Confidential Computing Context:
Determine if the bug can be triggered in a confidential computing guest kernel from the context of a KVM host.
Consider access to standard Linux guest paravirtualized features (virtio-blk, virtio-net, etc.).
* Ethernet Network Trigger:
Determine if the bug can be triggered by processing ingress network Ethernet traffic, either directly (network stack)
or via drivers exposed to network data.
* Other Remote Trigger:
Determine if the bug can be triggered by processing remote traffic other than Ethernet (Wifi, Bluetooth, NFC, etc).
* Peripheral Trigger:
Determine if the bug can be triggered via an untrusted peripheral device that can be physically plugged
into a system, such as a USB device or a niche hardware driver handling external hardware inputs.
This is particularly important for mobile and desktop environments where users can plug in unknown devices.
* Malicious Filesystem Trigger:
Determine if the bug can be triggered by the kernel mounting and parsing a malicious filesystem image.
This is highly critical for Desktop and Mobile environments where external media or downloaded images
might be auto-mounted.
Don't make assumptions about the kernel source code (it may be different from what you assume it is).
Extensively use the provided code access tools (codesearch-*, git-*, grepper, etc)
to examine the actual source code, and confirm any assumptions.
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:
The kernel bug report is:
====================================
WARNING: syz.3.395/6091 still has locks held!
syzkaller #0 Not tainted
------------------------------------
1 lock held by syz.3.395/6091:
#0: ffff0000cf1b4258 (&devlink->lock_key#3){+.+.}-{4:4}, at: devl_lock+0x24/0x34 net/devlink/core.c:292
stack backtrace:
CPU: 1 UID: 0 PID: 6091 Comm: syz.3.395 Not tainted syzkaller #0 PREEMPT
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/02/2026
Call trace:
show_stack+0x2c/0x3c arch/arm64/kernel/stacktrace.c:499 (C)
__dump_stack+0x30/0x40 lib/dump_stack.c:94
dump_stack_lvl+0xd8/0x12c lib/dump_stack.c:120
dump_stack+0x1c/0x28 lib/dump_stack.c:129
print_held_locks_bug+0x90/0x98 kernel/locking/lockdep.c:6752
debug_check_no_locks_held+0x28/0x34 kernel/locking/lockdep.c:6760
try_to_freeze include/linux/freezer.h:62 [inline]
usermodehelper_read_trylock+0x1d8/0x294 kernel/umh.c:230
fw_load_from_user_helper drivers/base/firmware_loader/fallback.c:147 [inline]
firmware_fallback_sysfs+0x158/0x918 drivers/base/firmware_loader/fallback.c:238
_request_firmware+0xb34/0xf5c drivers/base/firmware_loader/main.c:898
request_firmware+0x4c/0x70 drivers/base/firmware_loader/main.c:948
devlink_compat_flash_update+0x134/0x27c net/devlink/dev.c:1247
dev_ethtool+0x63c/0x1c40 net/ethtool/ioctl.c:3676
dev_ioctl+0x2a4/0xcf0 net/core/dev_ioctl.c:751
sock_do_ioctl+0x198/0x254 net/socket.c:1314
sock_ioctl+0x55c/0x7ec net/socket.c:1421
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__arm64_sys_ioctl+0x14c/0x1c4 fs/ioctl.c:583
__invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
invoke_syscall+0x98/0x244 arch/arm64/kernel/syscall.c:49
el0_svc_common+0xec/0x23c arch/arm64/kernel/syscall.c:121
do_el0_svc+0x4c/0x5c arch/arm64/kernel/syscall.c:140
el0_svc+0x64/0x260 arch/arm64/kernel/entry-common.c:736
el0t_64_sync_handler+0x48/0x148 arch/arm64/kernel/entry-common.c:755
el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:594
|
| 6/2 |
2026/07/30 00:05 |
llm |
expert |
0m
Model:
Tokens:
input: 6719
output: 26
thoughts: 499
Thoughts: **Analyzing a Lock Dep Bug**
Okay, so I've got this bug report β "WARNING: syz.3.395/6091 still has locks held!" β which immediately flags a potential issue, especially with lockdep. The critical detail is that the lock held is `devlink->lock_key#3` and it was acquired at `devl_lock+0x24/0x34 net/devlink/core.c:292`. The stack trace gives me the path of execution.
Looking at the stack trace, I see that lockdep is doing its job, which means there may be a deeper issue here.
The call stack shows a series of calls:
`print_held_locks_bug` -> `debug_check_no_locks_held` -> `usermodehelper_read_trylock` and then the call to `fw_load_from_user_helper`. This immediately says that this is in `firmware_fallback_sysfs` and ultimately coming from `devlink_compat_flash_update` within the `net/devlink` subsystem. After all, the trace also calls through `dev_ethtool`, `dev_ioctl`, and eventually `sock_ioctl`, which tells me that this is being triggered by a userspace interaction, probably an ethtool ioctl. The firmware loading path is often a source of contention, so it is likely to be there.
My next step is to examine the `devlink_compat_flash_update` function in `net/devlink/dev.c`. I need to figure out how this is acquiring the lock and, more importantly, *why* it's not releasing it under these circumstances. This is the likely culprit, especially considering where the lock is taken and when the firmware loading is attempted. I'm going to start there and trace the locking semantics in that function.
|
| 7/2 |
2026/07/30 00:05 |
tool |
codesearch-definition-source |
0m
Args: map[Name:devlink_compat_flash_update]
Results: map[SourceCode:1231: int devlink_compat_flash_update(struct devlink *devlink, const char *file_name)
1232: {
1233: struct devlink_flash_update_params params = {};
1234: int ret;
1235:
1236: devl_lock(devlink);
1237: if (!devl_is_registered(devlink)) {
1238: ret = -ENODEV;
1239: goto out_unlock;
1240: }
1241:
1242: if (!devlink->ops->flash_update) {
1243: ret = -EOPNOTSUPP;
1244: goto out_unlock;
1245: }
1246:
1247: ret = request_firmware(¶ms.fw, file_name, devlink->dev);
1248: if (ret)
1249: goto out_unlock;
1250:
1251: devlink_flash_update_begin_notify(devlink);
1252: ret = devlink->ops->flash_update(devlink, ¶ms, NULL);
1253: devlink_flash_update_end_notify(devlink);
1254:
1255: release_firmware(params.fw);
1256: out_unlock:
1257: devl_unlock(devlink);
1258:
1259: return ret;
1260: }
SourceFile:net/devlink/dev.c]
|
| 8/2 |
2026/07/30 00:05 |
llm |
expert |
0m
Model:
Tokens:
input: 8094
output: 23
thoughts: 114
Thoughts: **My Concerns Regarding the `devlink_compat_flash_update` Function**
Okay, so I'm looking at this `devlink_compat_flash_update` function, and it seems like it's taking a lock β `devl_lock(devlink)` β which makes sense for the operation it's doing. Then it calls `request_firmware`, which is where things get interesting. I know `request_firmware` can be a potential point of contention due to its interactions with user space. Specifically, `request_firmware` calls `usermodehelper_read_trylock`, which I know from experience can be a critical path.
Wait a second... it looks like `usermodehelper_read_trylock` eventually calls `try_to_freeze`. And *that* calls `debug_check_no_locks_held`! Hold on, this is where I need to dig in. Why is `try_to_freeze` checking for held locks? That suggests a potential conflict or a risk of deadlock during a system freeze. This doesn't seem right.
I better go and check the source code for `try_to_freeze` right away in `include/linux/freezer.h` to fully understand what's happening. I need to be certain about the locking behavior and what's going on with these locks, especially during a potential system freeze.
|
| 9/2 |
2026/07/30 00:05 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 56: static inline bool try_to_freeze(void)
57: {
58: might_sleep();
59: if (likely(!freezing(current)))
60: return false;
61: if (!(current->flags & PF_NOFREEZE))
62: debug_check_no_locks_held();
63: return __refrigerator(false);
64: }
SourceFile:include/linux/freezer.h]
|
| 10/2 |
2026/07/30 00:05 |
llm |
expert |
0m
Model:
Tokens:
input: 8673
output: 27
thoughts: 212
Thoughts: **Analyzing a Potential Freeze/Locking Issue**
Okay, so I'm looking at this `try_to_freeze` function, and it's calling `debug_check_no_locks_held()` when the process is actually freezing. I immediately think, "Wait, isn't `debug_check_no_locks_held` a lockdep check?" Is this just a benign lockdep warning, or is there a real underlying problem here?
If `try_to_freeze` gets called while locks *are* held, it could certainly lead to a deadlock. The freezing process could be waiting for a lock held by another process that also needs to freeze, and⦠bam! But then I recall situations like `request_firmware`, which sometimes *can* be called while holding locks. It can sleep, and the `devl_lock` is a mutex, specifically designed for that use case.
Then it hits me: `try_to_freeze` isn't just checking for *specific* locks. It's checking for *ANY* held lock. If a process is frozen while holding *any* lock, the system could deadlock if another process needs that lock and, crucially, *needs* to freeze. That's a classic scenario. So, yes, the `debug_check_no_locks_held` call in `try_to_freeze` is checking for *any* held locks. Let me now dive into how `usermodehelper_read_trylock` interacts with this situation...
|
| 11/2 |
2026/07/30 00:06 |
tool |
codesearch-definition-source |
0m
Args: map[Name:usermodehelper_read_trylock]
Results: map[SourceCode: 209: int usermodehelper_read_trylock(void)
210: {
211: DEFINE_WAIT(wait);
212: int ret = 0;
213:
214: down_read(&umhelper_sem);
215: for (;;) {
216: prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
217: TASK_INTERRUPTIBLE);
218: if (!usermodehelper_disabled)
219: break;
220:
221: if (usermodehelper_disabled == UMH_DISABLED)
222: ret = -EAGAIN;
223:
224: up_read(&umhelper_sem);
225:
226: if (ret)
227: break;
228:
229: schedule();
230: try_to_freeze();
231:
232: down_read(&umhelper_sem);
233: }
234: finish_wait(&usermodehelper_disabled_waitq, &wait);
235: return ret;
236: }
SourceFile:kernel/umh.c]
|
| 12/2 |
2026/07/30 00:06 |
llm |
expert |
1m
Model:
Tokens:
input: 9610
output: 25
thoughts: 87
Thoughts: Okay, let's break this down.
**Investigating a Freeze in User Mode Helper During Suspend/Resume**
Right, so I'm digging into a potential hang during suspend/resume operations. I see that the `usermodehelper_read_trylock` function is calling `try_to_freeze()` under specific conditions. Specifically, this happens when `usermodehelper_disabled` is true, but not when it's set to the value of `UMH_DISABLED`. That's the key trigger. This seems relevant to the observed behavior during suspend/resume, which is a common scenario for this kind of interaction. Now, the question is, *where* is `usermodehelper_read_trylock` being called during this process? Aha! I see that `firmware_fallback_sysfs` also calls `usermodehelper_read_trylock`. That's my next point of focus. I need to understand how `firmware_fallback_sysfs` interacts with the user mode helper system, especially during suspend and resume. Let's dive into that and see if we can find the root cause of this freeze.
|
| 13/2 |
2026/07/30 00:07 |
tool |
codesearch-definition-source |
0m
Args: map[Name:firmware_fallback_sysfs]
Results: map[SourceCode: 202: /**
203: * firmware_fallback_sysfs() - use the fallback mechanism to find firmware
204: * @fw: pointer to firmware image
205: * @name: name of firmware file to look for
206: * @device: device for which firmware is being loaded
207: * @opt_flags: options to control firmware loading behaviour, as defined by
208: * &enum fw_opt
209: * @ret: return value from direct lookup which triggered the fallback mechanism
210: *
211: * This function is called if direct lookup for the firmware failed, it enables
212: * a fallback mechanism through userspace by exposing a sysfs loading
213: * interface. Userspace is in charge of loading the firmware through the sysfs
214: * loading interface. This sysfs fallback mechanism may be disabled completely
215: * on a system by setting the proc sysctl value ignore_sysfs_fallback to true.
216: * If this is false we check if the internal API caller set the
217: * @FW_OPT_NOFALLBACK_SYSFS flag, if so it would also disable the fallback
218: * mechanism. A system may want to enforce the sysfs fallback mechanism at all
219: * times, it can do this by setting ignore_sysfs_fallback to false and
220: * force_sysfs_fallback to true.
221: * Enabling force_sysfs_fallback is functionally equivalent to build a kernel
222: * with CONFIG_FW_LOADER_USER_HELPER_FALLBACK.
223: **/
224: int firmware_fallback_sysfs(struct firmware *fw, const char *name,
225: struct device *device,
226: u32 opt_flags,
227: int ret)
228: {
229: if (!fw_run_sysfs_fallback(opt_flags))
230: return ret;
231:
232: if (!(opt_flags & FW_OPT_NO_WARN))
233: dev_warn(device, "Falling back to sysfs fallback for: %s\n",
234: name);
235: else
236: dev_dbg(device, "Falling back to sysfs fallback for: %s\n",
237: name);
238: return fw_load_from_user_helper(fw, name, device, opt_flags);
239: }
SourceFile:drivers/base/firmware_loader/fallback.c]
|
| 14/2 |
2026/07/30 00:07 |
llm |
expert |
0m
Model:
Tokens:
input: 10681
output: 27
thoughts: 117
Thoughts: **Lockdep Warning Analysis**
Okay, here's what's running through my mind. This "bug" is actually a **WARNING** coming from lockdep β that's the first clue. It's flagging: "WARNING: syz.3.395/6091 still has locks held!" Specifically, `debug_check_no_locks_held` is the function that detected a lock being held. And the culprit is `devlink->lock_key#3`. Right, so this confirms it's a lockdep warning. In production, of course, `debug_check_no_locks_held` would be a no-op since lockdep isn't enabled by default. Given the warning, I should probably double-check that `debug_check_no_locks_held` call. I need to understand why this is happening during the execution of this particular syz call.
|
| 15/2 |
2026/07/30 00:08 |
tool |
codesearch-definition-source |
0m
Args: map[Name:debug_check_no_locks_held]
Results: map[SourceCode:6757: void debug_check_no_locks_held(void)
6758: {
6759: if (unlikely(current->lockdep_depth > 0))
6760: print_held_locks_bug();
6761: }
SourceFile:kernel/locking/lockdep.c]
|
| 16/2 |
2026/07/30 00:08 |
llm |
expert |
0m
Model:
Tokens:
input: 11123
output: 26
thoughts: 129
Thoughts: **Lockdep Investigation**
Okay, so I'm digging into this and the definition of the function I'm interested in, `debug_check_no_locks_held`, is right there in `kernel/locking/lockdep.c`. Obvious, really. The code is structured so that if lockdep is disabled, it just becomes a no-op, which makes sense. But hang on, are there *other* consequences I'm not seeing here? I need to think this through carefully.
Right, I remember now. A process frozen while holding a lock is a known problem, especially when dealing with suspend/resume cycles. That can lead to a proper deadlock situation. Now the critical question: is this exploitable? Can someone actually *trigger* this vulnerability?
If an unprivileged user can somehow manipulate this, they could potentially cause a deadlock during suspend, which would be a nasty denial-of-service vector. I have to figure out if there's a path for an unprivileged user to call `devlink_compat_flash_update`, that seems like the most likely entry point. Let's start by analyzing the call graph for `devlink_compat_flash_update` to see if there are any obvious vulnerable points.
|
| 17/2 |
2026/07/30 00:08 |
tool |
codesearch-find-references |
0m
Args: map[Name:devlink_compat_flash_update]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:dev_ethtool SourceFile:net/ethtool/ioctl.c SourceLine:3676]] TruncatedOutput:false]
|
| 18/2 |
2026/07/30 00:08 |
llm |
expert |
0m
Model:
Tokens:
input: 11612
output: 23
thoughts: 24
Thoughts: Okay, here's my attempt at summarizing the thought process, tailored for an expert audience, and written in the first person:
**Decoding the `dev_ethtool` Call**
Right, so I'm tracing this ethtool functionality, and it looks like the entry point for this particular operation is `dev_ethtool`. Interesting. The code reference points to `net/ethtool/ioctl.c`. I'm immediately thinking about how this ties into the larger kernel network stack architecture. Specifically, how the ioctl interface is being utilized here to expose ethtool capabilities. I need to dig deeper into that source file and understand the exact mechanics of the interaction between the user space `ethtool` tool and the kernel's network device drivers. I'm imagining the flow - some user space command comes in, it hits this `dev_ethtool` function through the ioctl system call, and then the function probably dispatches to various driver-specific handlers. Time to dive into the implementation.
|
| 19/2 |
2026/07/30 00:08 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:3646: int dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr)
3647: {
3648: struct ethtool_devlink_compat *state;
3649: u32 ethcmd;
3650: int rc;
3651:
3652: if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd)))
3653: return -EFAULT;
3654:
3655: state = kzalloc_obj(*state);
3656: if (!state)
3657: return -ENOMEM;
3658:
3659: switch (ethcmd) {
3660: case ETHTOOL_FLASHDEV:
3661: if (copy_from_user(&state->efl, useraddr, sizeof(state->efl))) {
3662: rc = -EFAULT;
3663: goto exit_free;
3664: }
3665: state->efl.data[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0;
3666: break;
3667: }
3668:
3669: rc = __dev_ethtool(net, ifr, useraddr, ethcmd, state);
3670: if (rc)
3671: goto exit_free;
3672:
3673: switch (ethcmd) {
3674: case ETHTOOL_FLASHDEV:
3675: if (state->devlink)
3676: rc = devlink_compat_flash_update(state->devlink,
3677: state->efl.data);
3678: break;
3679: case ETHTOOL_GDRVINFO:
3680: if (state->devlink)
3681: devlink_compat_running_version(state->devlink,
3682: state->info.fw_version,
3683: sizeof(state->info.fw_version));
3684: if (copy_to_user(useraddr, &state->info, sizeof(state->info))) {
3685: rc = -EFAULT;
3686: goto exit_free;
3687: }
3688: break;
3689: }
3690:
3691: exit_free:
3692: if (state->devlink)
3693: devlink_put(state->devlink);
3694: kfree(state);
3695: return rc;
3696: }
SourceFile:net/ethtool/ioctl.c]
|
| 20/2 |
2026/07/30 00:08 |
llm |
expert |
0m
Model:
Tokens:
input: 12626
output: 24
thoughts: 55
Thoughts: Here's my thought process, as requested:
**Investigating the Security Context of `dev_ethtool`**
Okay, so I'm digging into `dev_ioctl` in `net/core/dev_ioctl.c`, and I see that it calls `dev_ethtool`. My immediate question is, does this `dev_ethtool` function itself have any access requirements or capabilities it enforces? I need to understand if this is a potential security vulnerability point or not. The control flow is there, but what are the checks at the entry point? To get to the bottom of this, I'm going to jump into the code for `__dev_ethtool` to get a clearer picture of its own access control mechanisms, or the lack thereof. Time to dive into the internals.
|
| 21/2 |
2026/07/30 00:08 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:3609: static int
3610: __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr,
3611: u32 ethcmd, struct ethtool_devlink_compat *devlink_state)
3612: {
3613: netdevice_tracker dev_tracker;
3614: struct net_device *dev;
3615: bool need_rtnl;
3616: int rc;
3617:
3618: dev = netdev_get_by_name(net, ifr->ifr_name, &dev_tracker, GFP_KERNEL);
3619: if (!dev)
3620: return -ENODEV;
3621:
3622: need_rtnl = !netdev_need_ops_lock(dev) ||
3623: ethtool_cmd_changes_features(ethcmd) ||
3624: ethtool_ioctl_needs_rtnl(dev, ethcmd);
3625: if (need_rtnl)
3626: rtnl_lock();
3627: netdev_lock_ops(dev);
3628: if (dev->reg_state > NETREG_REGISTERED ||
3629: dev->moving_ns || !net_eq(dev_net(dev), net)) {
3630: rc = -ENODEV;
3631: goto exit_ops_unlock;
3632: }
3633:
3634: rc = dev_ethtool_locked(net, dev, useraddr, ethcmd, devlink_state,
3635: need_rtnl);
3636:
3637: exit_ops_unlock:
3638: netdev_unlock_ops(dev);
3639: if (need_rtnl)
3640: rtnl_unlock();
3641: netdev_put(dev, &dev_tracker);
3642:
3643: return rc;
3644: }
SourceFile:net/ethtool/ioctl.c]
|
| 22/2 |
2026/07/30 00:08 |
llm |
expert |
0m
Model:
Tokens:
input: 13468
output: 25
thoughts: 13
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience and written in the first person:
**Checking `dev_ethtool_locked`**
Okay, so I need to quickly assess something. My initial thought is to dive straight into examining `dev_ethtool_locked`. I'm going to assume, based on the naming, that it's a key variable in controlling access or the state of ethtool operations on a device. My focus is going to be on understanding *why* I need to check it. Is this a common debugging step in a particular context? Am I expecting a lock contention issue? Or am I simply looking for the current state of the lock as a preliminary step to understand a potential problem? Knowing the context would greatly assist in assessing the significance of this variable. The subsequent action I take will depend heavily on the reason for the inspection. I'll need to remember the architectural context - is this kernel-space, userspace, or something else entirely? The type of this variable, the functions which use it, and the locking mechanism in use (mutex, spinlock, etc.) are all relevant pieces of information that I'll need to keep in mind as I begin to trace through the code.
|
| 23/2 |
2026/07/30 00:08 |
tool |
codesearch-definition-source |
0m
Args: map[Name:dev_ethtool_locked]
Results: map[SourceCode:3271: static int
3272: dev_ethtool_locked(struct net *net, struct net_device *dev,
3273: void __user *useraddr,
3274: u32 ethcmd, struct ethtool_devlink_compat *devlink_state,
3275: bool has_rtnl_lock)
3276: {
3277: u32 sub_cmd;
3278: int rc;
3279: netdev_features_t old_features;
3280:
3281: if (ethcmd == ETHTOOL_PERQUEUE) {
3282: if (copy_from_user(&sub_cmd, useraddr + sizeof(ethcmd), sizeof(sub_cmd)))
3283: return -EFAULT;
3284: } else {
3285: sub_cmd = ethcmd;
3286: }
3287: /* Allow some commands to be done by anyone */
3288: switch (sub_cmd) {
3289: case ETHTOOL_GSET:
3290: case ETHTOOL_GDRVINFO:
3291: case ETHTOOL_GMSGLVL:
3292: case ETHTOOL_GLINK:
3293: case ETHTOOL_GCOALESCE:
3294: case ETHTOOL_GRINGPARAM:
3295: case ETHTOOL_GPAUSEPARAM:
3296: case ETHTOOL_GRXCSUM:
3297: case ETHTOOL_GTXCSUM:
3298: case ETHTOOL_GSG:
3299: case ETHTOOL_GSSET_INFO:
3300: case ETHTOOL_GSTRINGS:
3301: case ETHTOOL_GSTATS:
3302: case ETHTOOL_GPHYSTATS:
3303: case ETHTOOL_GTSO:
3304: case ETHTOOL_GPERMADDR:
3305: case ETHTOOL_GUFO:
3306: case ETHTOOL_GGSO:
3307: case ETHTOOL_GGRO:
3308: case ETHTOOL_GFLAGS:
3309: case ETHTOOL_GPFLAGS:
3310: case ETHTOOL_GRXFH:
3311: case ETHTOOL_GRXRINGS:
3312: case ETHTOOL_GRXCLSRLCNT:
3313: case ETHTOOL_GRXCLSRULE:
3314: case ETHTOOL_GRXCLSRLALL:
3315: case ETHTOOL_GRXFHINDIR:
3316: case ETHTOOL_GRSSH:
3317: case ETHTOOL_GFEATURES:
3318: case ETHTOOL_GCHANNELS:
3319: case ETHTOOL_GET_TS_INFO:
3320: case ETHTOOL_GEEE:
3321: case ETHTOOL_GTUNABLE:
3322: case ETHTOOL_PHY_GTUNABLE:
3323: case ETHTOOL_GLINKSETTINGS:
3324: case ETHTOOL_GFECPARAM:
3325: break;
3326: default:
3327: if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
3328: return -EPERM;
3329: }
3330:
3331: netdev_assert_locked_ops_compat(dev);
3332:
3333: if (dev->dev.parent)
3334: pm_runtime_get_sync(dev->dev.parent);
3335:
3336: if (!netif_device_present(dev)) {
3337: rc = -ENODEV;
3338: goto out;
3339: }
3340:
3341: if (dev->ethtool_ops->begin) {
3342: rc = dev->ethtool_ops->begin(dev);
3343: if (rc < 0)
3344: goto out;
3345: }
3346: old_features = dev->features;
3347:
3348: switch (ethcmd) {
3349: case ETHTOOL_GSET:
3350: rc = ethtool_get_settings(dev, useraddr);
3351: break;
3352: case ETHTOOL_SSET:
3353: rc = ethtool_set_settings(dev, useraddr);
3354: break;
3355: case ETHTOOL_GDRVINFO:
3356: rc = ethtool_get_drvinfo(dev, devlink_state);
3357: break;
3358: case ETHTOOL_GREGS:
3359: rc = ethtool_get_regs(dev, useraddr);
3360: break;
3361: case ETHTOOL_GWOL:
3362: rc = ethtool_get_wol(dev, useraddr);
3363: break;
3364: case ETHTOOL_SWOL:
3365: rc = ethtool_set_wol(dev, useraddr);
3366: break;
3367: case ETHTOOL_GMSGLVL:
3368: rc = ethtool_get_value(dev, useraddr, ethcmd,
3369: dev->ethtool_ops->get_msglevel);
3370: break;
3371: case ETHTOOL_SMSGLVL:
3372: rc = ethtool_set_value_void(dev, useraddr,
3373: dev->ethtool_ops->set_msglevel);
3374: if (!rc)
3375: ethtool_notify(dev, ETHTOOL_MSG_DEBUG_NTF);
3376: break;
3377: case ETHTOOL_GEEE:
3378: rc = ethtool_get_eee(dev, useraddr);
3379: break;
3380: case ETHTOOL_SEEE:
3381: rc = ethtool_set_eee(dev, useraddr);
3382: break;
3383: case ETHTOOL_NWAY_RST:
3384: rc = ethtool_nway_reset(dev);
3385: break;
3386: case ETHTOOL_GLINK:
3387: rc = ethtool_get_link(dev, useraddr);
3388: break;
3389: case ETHTOOL_GEEPROM:
3390: rc = ethtool_get_eeprom(dev, useraddr);
3391: break;
3392: case ETHTOOL_SEEPROM:
3393: rc = ethtool_set_eeprom(dev, useraddr);
3394: break;
3395: case ETHTOOL_GCOALESCE:
3396: rc = ethtool_get_coalesce(dev, useraddr);
3397: break;
3398: case ETHTOOL_SCOALESCE:
3399: rc = ethtool_set_coalesce(dev, useraddr);
3400: break;
3401: case ETHTOOL_GRINGPARAM:
3402: rc = ethtool_get_ringparam(dev, useraddr);
3403: break;
3404: case ETHTOOL_SRINGPARAM:
3405: rc = ethtool_set_ringparam(dev, useraddr);
3406: break;
3407: case ETHTOOL_GPAUSEPARAM:
3408: rc = ethtool_get_pauseparam(dev, useraddr);
3409: break;
3410: case ETHTOOL_SPAUSEPARAM:
3411: rc = ethtool_set_pauseparam(dev, useraddr);
3412: break;
3413: case ETHTOOL_TEST:
3414: rc = ethtool_self_test(dev, useraddr);
3415: break;
3416: case ETHTOOL_GSTRINGS:
3417: rc = ethtool_get_strings(dev, useraddr);
3418: break;
3419: case ETHTOOL_PHYS_ID:
3420: rc = ethtool_phys_id(dev, useraddr, has_rtnl_lock);
3421: break;
3422: case ETHTOOL_GSTATS:
3423: rc = ethtool_get_stats(dev, useraddr);
3424: break;
3425: case ETHTOOL_GPERMADDR:
3426: rc = ethtool_get_perm_addr(dev, useraddr);
3427: break;
3428: case ETHTOOL_GFLAGS:
3429: rc = ethtool_get_value(dev, useraddr, ethcmd,
3430: __ethtool_get_flags);
3431: break;
3432: case ETHTOOL_SFLAGS:
3433: rc = ethtool_set_value(dev, useraddr, __ethtool_set_flags);
3434: break;
3435: case ETHTOOL_GPFLAGS:
3436: rc = ethtool_get_value(dev, useraddr, ethcmd,
3437: dev->ethtool_ops->get_priv_flags);
3438: if (!rc)
3439: ethtool_notify(dev, ETHTOOL_MSG_PRIVFLAGS_NTF);
3440: break;
3441: case ETHTOOL_SPFLAGS:
3442: rc = ethtool_set_value(dev, useraddr,
3443: dev->ethtool_ops->set_priv_flags);
3444: break;
3445: case ETHTOOL_GRXFH:
3446: rc = ethtool_get_rxfh_fields(dev, ethcmd, useraddr);
3447: break;
3448: case ETHTOOL_SRXFH:
3449: rc = ethtool_set_rxfh_fields(dev, ethcmd, useraddr);
3450: break;
3451: case ETHTOOL_GRXRINGS:
3452: rc = ethtool_get_rxrings(dev, ethcmd, useraddr);
3453: break;
3454: case ETHTOOL_GRXCLSRLCNT:
3455: case ETHTOOL_GRXCLSRULE:
3456: case ETHTOOL_GRXCLSRLALL:
3457: rc = ethtool_get_rxnfc(dev, ethcmd, useraddr);
3458: break;
3459: case ETHTOOL_SRXCLSRLDEL:
3460: case ETHTOOL_SRXCLSRLINS:
3461: rc = ethtool_set_rxnfc(dev, ethcmd, useraddr);
3462: break;
3463: case ETHTOOL_FLASHDEV:
3464: rc = ethtool_flash_device(dev, devlink_state);
3465: break;
3466: case ETHTOOL_RESET:
3467: rc = ethtool_reset(dev, useraddr);
3468: break;
3469: case ETHTOOL_GSSET_INFO:
3470: rc = ethtool_get_sset_info(dev, useraddr);
3471: break;
3472: case ETHTOOL_GRXFHINDIR:
3473: rc = ethtool_get_rxfh_indir(dev, useraddr);
3474: break;
3475: case ETHTOOL_SRXFHINDIR:
3476: rc = ethtool_set_rxfh_indir(dev, useraddr);
3477: break;
3478: case ETHTOOL_GRSSH:
3479: rc = ethtool_get_rxfh(dev, useraddr);
3480: break;
3481: case ETHTOOL_SRSSH:
3482: rc = ethtool_set_rxfh(dev, useraddr);
3483: break;
3484: case ETHTOOL_GFEATURES:
3485: rc = ethtool_get_features(dev, useraddr);
3486: break;
3487: case ETHTOOL_SFEATURES:
3488: rc = ethtool_set_features(dev, useraddr);
3489: break;
3490: case ETHTOOL_GTXCSUM:
3491: case ETHTOOL_GRXCSUM:
3492: case ETHTOOL_GSG:
3493: case ETHTOOL_GTSO:
3494: case ETHTOOL_GGSO:
3495: case ETHTOOL_GGRO:
3496: rc = ethtool_get_one_feature(dev, useraddr, ethcmd);
3497: break;
3498: case ETHTOOL_STXCSUM:
3499: case ETHTOOL_SRXCSUM:
3500: case ETHTOOL_SSG:
3501: case ETHTOOL_STSO:
3502: case ETHTOOL_SGSO:
3503: case ETHTOOL_SGRO:
3504: rc = ethtool_set_one_feature(dev, useraddr, ethcmd);
3505: break;
3506: case ETHTOOL_GCHANNELS:
3507: rc = ethtool_get_channels(dev, useraddr);
3508: break;
3509: case ETHTOOL_SCHANNELS:
3510: rc = ethtool_set_channels(dev, useraddr);
3511: break;
3512: case ETHTOOL_SET_DUMP:
3513: rc = ethtool_set_dump(dev, useraddr);
3514: break;
3515: case ETHTOOL_GET_DUMP_FLAG:
3516: rc = ethtool_get_dump_flag(dev, useraddr);
3517: break;
3518: case ETHTOOL_GET_DUMP_DATA:
3519: rc = ethtool_get_dump_data(dev, useraddr);
3520: break;
3521: case ETHTOOL_GET_TS_INFO:
3522: rc = ethtool_get_ts_info(dev, useraddr);
3523: break;
3524: case ETHTOOL_GMODULEINFO:
3525: rc = ethtool_get_module_info(dev, useraddr);
3526: break;
3527: case ETHTOOL_GMODULEEEPROM:
3528: rc = ethtool_get_module_eeprom(dev, useraddr);
3529: break;
3530: case ETHTOOL_GTUNABLE:
3531: rc = ethtool_get_tunable(dev, useraddr);
3532: break;
3533: case ETHTOOL_STUNABLE:
3534: rc = ethtool_set_tunable(dev, useraddr);
3535: break;
3536: case ETHTOOL_GPHYSTATS:
3537: rc = ethtool_get_phy_stats(dev, useraddr);
3538: break;
3539: case ETHTOOL_PERQUEUE:
3540: rc = ethtool_set_per_queue(dev, useraddr, sub_cmd);
3541: break;
3542: case ETHTOOL_GLINKSETTINGS:
3543: rc = ethtool_get_link_ksettings(dev, useraddr);
3544: break;
3545: case ETHTOOL_SLINKSETTINGS:
3546: rc = ethtool_set_link_ksettings(dev, useraddr);
3547: break;
3548: case ETHTOOL_PHY_GTUNABLE:
3549: rc = get_phy_tunable(dev, useraddr);
3550: break;
3551: case ETHTOOL_PHY_STUNABLE:
3552: rc = set_phy_tunable(dev, useraddr);
3553: break;
3554: case ETHTOOL_GFECPARAM:
3555: rc = ethtool_get_fecparam(dev, useraddr);
3556: break;
3557: case ETHTOOL_SFECPARAM:
3558: rc = ethtool_set_fecparam(dev, useraddr);
3559: break;
3560: default:
3561: rc = -EOPNOTSUPP;
3562: }
3563:
3564: if (dev->ethtool_ops->complete)
3565: dev->ethtool_ops->complete(dev);
3566:
3567: switch (ethcmd) {
3568: case ETHTOOL_PHYS_ID:
3569: /* Don't check features if operation drops the locks.
3570: * Someone else may have changed features in parallel.
3571: */
3572: break;
3573: default:
3574: if (old_features != dev->features) {
3575: if (has_rtnl_lock)
3576: netdev_features_change(dev);
3577: else
3578: netdev_WARN(dev, "ethtool cmd %u changed features without rtnl_lock", ethcmd);
3579: }
3580: }
3581: out:
3582: if (dev->dev.parent)
3583: pm_runtime_put(dev->dev.parent);
3584:
3585: return rc;
3586: }
SourceFile:net/ethtool/ioctl.c]
|
| 24/2 |
2026/07/30 00:08 |
llm |
expert |
0m
Model:
Tokens:
input: 18806
output: 28
thoughts: 436
Thoughts: **Analyzing the Security Implications of ETHTOOL_FLASHDEV**
Okay, so `ETHTOOL_FLASHDEV` isn't on the "safe" list, which means it demands `CAP_NET_ADMIN`. That means an unprivileged user can't just run it, unless they're playing around in a user namespace where they *do* have `CAP_NET_ADMIN`. But hang on... `ETHTOOL_FLASHDEV` actually needs `CAP_NET_ADMIN` in the *network* namespace, right?
So, theoretically, a user could conjure up a new network and user namespace, and presto, `CAP_NET_ADMIN`. But can they actually then trigger `devlink_compat_flash_update` on a real device? If they're locked in a new network namespace, aren't they just looking at the loopback or veth devices which don't support this kind of flashing or devlink?
Right, but what if, hypothetically, they have a devlink-supporting device *in their namespace* somehow? They can't move a physical device into their new namespace β that needs `CAP_NET_ADMIN` in the original, unprivileged namespace. They are stuck, so they can't trigger this on a physical device.
So, they need a *virtual* device, a *netdevsim* perhaps? Can an unprivileged user even *create* a netdevsim device? Does that need `CAP_NET_ADMIN` in the initial namespace, or maybe via netlink if they have CAP_NET_ADMIN in the user namespace? I should check that. Usually, netdevsim devices are created via sysfs or devlink. Devlink requires `CAP_NET_ADMIN` in the initial namespace for most operations, but devlink is namespace-aware now. Alright, time to check `devlink_nl_cmd_flash_update`.
|
| 25/2 |
2026/07/30 00:08 |
tool |
codesearch-definition-source |
0m
Error:
Args: map[Name:devlink_nl_cmd_flash_update]
Results: map[SourceCode: SourceFile:]
|
| 26/2 |
2026/07/30 00:08 |
llm |
expert |
0m
Model:
Tokens:
input: 19692
output: 24
thoughts: 30
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Investigating a Flash Update Function**
Okay, so I need to dig into the flash update functionality for a devlink device. My first instinct, given the naming conventions, is to start with the `devlink_nl_cmd_flash_update` function. Itβs highly likely I'll find it defined in `net/devlink/dev.c` or a file similarly named within the networking subsystem. Thatβs usually where the core NL command handlers reside for this kind of functionality. Iβll need to understand the arguments it expects, any locking it uses, how it interacts with the underlying hardware (or driver if it's mediated), and what error conditions it's designed to handle. I'm also looking for potential race conditions, especially if it involves any asynchronous operations or shared resources. Let's see what we can find.
|
| 27/2 |
2026/07/30 00:08 |
tool |
grepper |
0m
Error:
Args: map[Expression:devlink_nl_cmd_flash_update]
Results:
|
| 28/2 |
2026/07/30 00:08 |
llm |
expert |
0m
Model:
Tokens:
input: 19956
output: 28
thoughts: 15
Thoughts: Okay, here's my summarized thought process, presented as if I were thinking it:
**Digging into Device Link for Flash Updates**
Alright, before I dive too deep into this problem, I should probably start by checking the `net/devlink/` subsystem. That's the logical place to start when I'm dealing with any kind of firmware or flash update on network devices, so I should see if there's anything relevant there. It's the standard location for managing these types of operations, so checking `net/devlink/` feels like a good, solid first step.
|
| 29/2 |
2026/07/30 00:08 |
tool |
grepper |
0m
Args: map[Expression:flash_update PathPrefix:net/devlink/]
Results: map[Output:net/devlink/dev.c=943=int devlink_nl_info_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb)
--
net/devlink/dev.c-947-
net/devlink/dev.c:948:static int devlink_nl_flash_update_fill(struct sk_buff *msg,
net/devlink/dev.c-949- struct devlink *devlink,
--
net/devlink/dev.c-991-
net/devlink/dev.c:992:static void __devlink_flash_update_notify(struct devlink *devlink,
net/devlink/dev.c-993- enum devlink_command cmd,
--
net/devlink/dev.c-1009-
net/devlink/dev.c:1010: err = devlink_nl_flash_update_fill(msg, devlink, cmd, params);
net/devlink/dev.c-1011- if (err)
--
net/devlink/dev.c-1020-
net/devlink/dev.c:1021:static void devlink_flash_update_begin_notify(struct devlink *devlink)
net/devlink/dev.c-1022-{
--
net/devlink/dev.c-1024-
net/devlink/dev.c:1025: __devlink_flash_update_notify(devlink,
net/devlink/dev.c-1026- DEVLINK_CMD_FLASH_UPDATE,
--
net/devlink/dev.c-1029-
net/devlink/dev.c:1030:static void devlink_flash_update_end_notify(struct devlink *devlink)
net/devlink/dev.c-1031-{
--
net/devlink/dev.c-1033-
net/devlink/dev.c:1034: __devlink_flash_update_notify(devlink,
net/devlink/dev.c-1035- DEVLINK_CMD_FLASH_UPDATE_END,
--
net/devlink/dev.c-1038-
net/devlink/dev.c:1039:void devlink_flash_update_status_notify(struct devlink *devlink,
net/devlink/dev.c-1040- const char *status_msg,
--
net/devlink/dev.c-1051-
net/devlink/dev.c:1052: __devlink_flash_update_notify(devlink,
net/devlink/dev.c-1053- DEVLINK_CMD_FLASH_UPDATE_STATUS,
--
net/devlink/dev.c-1055-}
net/devlink/dev.c:1056:EXPORT_SYMBOL_GPL(devlink_flash_update_status_notify);
net/devlink/dev.c-1057-
net/devlink/dev.c:1058:void devlink_flash_update_timeout_notify(struct devlink *devlink,
net/devlink/dev.c-1059- const char *status_msg,
--
net/devlink/dev.c-1068-
net/devlink/dev.c:1069: __devlink_flash_update_notify(devlink,
net/devlink/dev.c-1070- DEVLINK_CMD_FLASH_UPDATE_STATUS,
--
net/devlink/dev.c-1072-}
net/devlink/dev.c:1073:EXPORT_SYMBOL_GPL(devlink_flash_update_timeout_notify);
net/devlink/dev.c-1074-
--
net/devlink/dev.c=1095=static int devlink_flash_component_get(struct devlink *devlink,
--
net/devlink/dev.c-1132-
net/devlink/dev.c:1133:int devlink_nl_flash_update_doit(struct sk_buff *skb, struct genl_info *info)
net/devlink/dev.c-1134-{
net/devlink/dev.c-1135- struct nlattr *nla_overwrite_mask, *nla_file_name;
net/devlink/dev.c:1136: struct devlink_flash_update_params params = {};
net/devlink/dev.c-1137- struct devlink *devlink = info->user_ptr[0];
--
net/devlink/dev.c-1141-
net/devlink/dev.c:1142: if (!devlink->ops->flash_update)
net/devlink/dev.c-1143- return -EOPNOTSUPP;
--
net/devlink/dev.c-1153-
net/devlink/dev.c:1154: supported_params = devlink->ops->supported_flash_update_params;
net/devlink/dev.c-1155-
--
net/devlink/dev.c-1177-
net/devlink/dev.c:1178: devlink_flash_update_begin_notify(devlink);
net/devlink/dev.c:1179: ret = devlink->ops->flash_update(devlink, ¶ms, info->extack);
net/devlink/dev.c:1180: devlink_flash_update_end_notify(devlink);
net/devlink/dev.c-1181-
--
net/devlink/dev.c=1219=void devlink_compat_running_version(struct devlink *devlink,
--
net/devlink/dev.c-1230-
net/devlink/dev.c:1231:int devlink_compat_flash_update(struct devlink *devlink, const char *file_name)
net/devlink/dev.c-1232-{
net/devlink/dev.c:1233: struct devlink_flash_update_params params = {};
net/devlink/dev.c-1234- int ret;
--
net/devlink/dev.c-1241-
net/devlink/dev.c:1242: if (!devlink->ops->flash_update) {
net/devlink/dev.c-1243- ret = -EOPNOTSUPP;
--
net/devlink/dev.c-1250-
net/devlink/dev.c:1251: devlink_flash_update_begin_notify(devlink);
net/devlink/dev.c:1252: ret = devlink->ops->flash_update(devlink, ¶ms, NULL);
net/devlink/dev.c:1253: devlink_flash_update_end_notify(devlink);
net/devlink/dev.c-1254-
--
net/devlink/netlink_gen.c=493=static const struct nla_policy devlink_health_reporter_dump_clear_nl_policy[DEVLINK_ATTR_INDEX + 1] = {
--
net/devlink/netlink_gen.c-501-/* DEVLINK_CMD_FLASH_UPDATE - do */
net/devlink/netlink_gen.c:502:static const struct nla_policy devlink_flash_update_nl_policy[DEVLINK_ATTR_INDEX + 1] = {
net/devlink/netlink_gen.c-503- [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
--
net/devlink/netlink_gen.c=694=const struct genl_split_ops devlink_nl_ops[75] = {
--
net/devlink/netlink_gen.c-1175- .pre_doit = devlink_nl_pre_doit,
net/devlink/netlink_gen.c:1176: .doit = devlink_nl_flash_update_doit,
net/devlink/netlink_gen.c-1177- .post_doit = devlink_nl_post_doit,
net/devlink/netlink_gen.c:1178: .policy = devlink_flash_update_nl_policy,
net/devlink/netlink_gen.c-1179- .maxattr = DEVLINK_ATTR_INDEX,
--
net/devlink/netlink_gen.h=116=int devlink_nl_health_reporter_dump_clear_doit(struct sk_buff *skb,
net/devlink/netlink_gen.h-117- struct genl_info *info);
net/devlink/netlink_gen.h:118:int devlink_nl_flash_update_doit(struct sk_buff *skb, struct genl_info *info);
net/devlink/netlink_gen.h-119-int devlink_nl_trap_get_doit(struct sk_buff *skb, struct genl_info *info);
]
|
| 30/2 |
2026/07/30 00:08 |
llm |
expert |
0m
Model:
Tokens:
input: 22454
output: 24
thoughts: 58
Thoughts: **Analyzing the Flash Update Handler**
Okay, so I'm looking at `devlink_nl_flash_update_doit`. That's our netlink handler for flash updates, right? The first question that pops into my head β as it always does with anything network-related β is: Does this operation require the `CAP_NET_ADMIN` capability? That's a critical security check, and I need to make sure we're properly protecting this functionality. I need to confirm whether our netlink handler respects those privileges before I can move on. I know that information will be in the `devlink_nl_ops` structure. I'll take a look at the code in `net/devlink/netlink_gen.c` to verify that assumption.
|
| 31/2 |
2026/07/30 00:08 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 693: /* Ops table for devlink */
694: const struct genl_split_ops devlink_nl_ops[75] = {
695: {
696: .cmd = DEVLINK_CMD_GET,
697: .validate = GENL_DONT_VALIDATE_STRICT,
698: .pre_doit = devlink_nl_pre_doit,
699: .doit = devlink_nl_get_doit,
700: .post_doit = devlink_nl_post_doit,
701: .policy = devlink_get_nl_policy,
702: .maxattr = DEVLINK_ATTR_INDEX,
703: .flags = GENL_CMD_CAP_DO,
704: },
705: {
706: .cmd = DEVLINK_CMD_GET,
707: .validate = GENL_DONT_VALIDATE_DUMP,
708: .dumpit = devlink_nl_get_dumpit,
709: .flags = GENL_CMD_CAP_DUMP,
710: },
711: {
712: .cmd = DEVLINK_CMD_PORT_GET,
713: .validate = GENL_DONT_VALIDATE_STRICT,
714: .pre_doit = devlink_nl_pre_doit_port,
715: .doit = devlink_nl_port_get_doit,
716: .post_doit = devlink_nl_post_doit,
717: .policy = devlink_port_get_do_nl_policy,
718: .maxattr = DEVLINK_ATTR_INDEX,
719: .flags = GENL_CMD_CAP_DO,
720: },
721: {
722: .cmd = DEVLINK_CMD_PORT_GET,
723: .dumpit = devlink_nl_port_get_dumpit,
724: .policy = devlink_port_get_dump_nl_policy,
725: .maxattr = DEVLINK_ATTR_INDEX,
726: .flags = GENL_CMD_CAP_DUMP,
727: },
728: {
729: .cmd = DEVLINK_CMD_PORT_SET,
730: .validate = GENL_DONT_VALIDATE_STRICT,
731: .pre_doit = devlink_nl_pre_doit_port,
732: .doit = devlink_nl_port_set_doit,
733: .post_doit = devlink_nl_post_doit,
734: .policy = devlink_port_set_nl_policy,
735: .maxattr = DEVLINK_ATTR_INDEX,
736: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
737: },
738: {
739: .cmd = DEVLINK_CMD_PORT_NEW,
740: .validate = GENL_DONT_VALIDATE_STRICT,
741: .pre_doit = devlink_nl_pre_doit,
742: .doit = devlink_nl_port_new_doit,
743: .post_doit = devlink_nl_post_doit,
744: .policy = devlink_port_new_nl_policy,
745: .maxattr = DEVLINK_ATTR_INDEX,
746: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
747: },
748: {
749: .cmd = DEVLINK_CMD_PORT_DEL,
750: .validate = GENL_DONT_VALIDATE_STRICT,
751: .pre_doit = devlink_nl_pre_doit_port,
752: .doit = devlink_nl_port_del_doit,
753: .post_doit = devlink_nl_post_doit,
754: .policy = devlink_port_del_nl_policy,
755: .maxattr = DEVLINK_ATTR_INDEX,
756: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
757: },
758: {
759: .cmd = DEVLINK_CMD_PORT_SPLIT,
760: .validate = GENL_DONT_VALIDATE_STRICT,
761: .pre_doit = devlink_nl_pre_doit_port,
762: .doit = devlink_nl_port_split_doit,
763: .post_doit = devlink_nl_post_doit,
764: .policy = devlink_port_split_nl_policy,
765: .maxattr = DEVLINK_ATTR_INDEX,
766: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
767: },
768: {
769: .cmd = DEVLINK_CMD_PORT_UNSPLIT,
770: .validate = GENL_DONT_VALIDATE_STRICT,
771: .pre_doit = devlink_nl_pre_doit_port,
772: .doit = devlink_nl_port_unsplit_doit,
773: .post_doit = devlink_nl_post_doit,
774: .policy = devlink_port_unsplit_nl_policy,
775: .maxattr = DEVLINK_ATTR_INDEX,
776: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
777: },
778: {
779: .cmd = DEVLINK_CMD_SB_GET,
780: .validate = GENL_DONT_VALIDATE_STRICT,
781: .pre_doit = devlink_nl_pre_doit,
782: .doit = devlink_nl_sb_get_doit,
783: .post_doit = devlink_nl_post_doit,
784: .policy = devlink_sb_get_do_nl_policy,
785: .maxattr = DEVLINK_ATTR_INDEX,
786: .flags = GENL_CMD_CAP_DO,
787: },
788: {
789: .cmd = DEVLINK_CMD_SB_GET,
790: .dumpit = devlink_nl_sb_get_dumpit,
791: .policy = devlink_sb_get_dump_nl_policy,
792: .maxattr = DEVLINK_ATTR_INDEX,
793: .flags = GENL_CMD_CAP_DUMP,
794: },
795: {
796: .cmd = DEVLINK_CMD_SB_POOL_GET,
797: .validate = GENL_DONT_VALIDATE_STRICT,
798: .pre_doit = devlink_nl_pre_doit,
799: .doit = devlink_nl_sb_pool_get_doit,
800: .post_doit = devlink_nl_post_doit,
801: .policy = devlink_sb_pool_get_do_nl_policy,
802: .maxattr = DEVLINK_ATTR_INDEX,
803: .flags = GENL_CMD_CAP_DO,
804: },
805: {
806: .cmd = DEVLINK_CMD_SB_POOL_GET,
807: .dumpit = devlink_nl_sb_pool_get_dumpit,
808: .policy = devlink_sb_pool_get_dump_nl_policy,
809: .maxattr = DEVLINK_ATTR_INDEX,
810: .flags = GENL_CMD_CAP_DUMP,
811: },
812: {
813: .cmd = DEVLINK_CMD_SB_POOL_SET,
814: .validate = GENL_DONT_VALIDATE_STRICT,
815: .pre_doit = devlink_nl_pre_doit,
816: .doit = devlink_nl_sb_pool_set_doit,
817: .post_doit = devlink_nl_post_doit,
818: .policy = devlink_sb_pool_set_nl_policy,
819: .maxattr = DEVLINK_ATTR_INDEX,
820: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
821: },
822: {
823: .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
824: .validate = GENL_DONT_VALIDATE_STRICT,
825: .pre_doit = devlink_nl_pre_doit_port,
826: .doit = devlink_nl_sb_port_pool_get_doit,
827: .post_doit = devlink_nl_post_doit,
828: .policy = devlink_sb_port_pool_get_do_nl_policy,
829: .maxattr = DEVLINK_ATTR_INDEX,
830: .flags = GENL_CMD_CAP_DO,
831: },
832: {
833: .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
834: .dumpit = devlink_nl_sb_port_pool_get_dumpit,
835: .policy = devlink_sb_port_pool_get_dump_nl_policy,
836: .maxattr = DEVLINK_ATTR_INDEX,
837: .flags = GENL_CMD_CAP_DUMP,
838: },
839: {
840: .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
841: .validate = GENL_DONT_VALIDATE_STRICT,
842: .pre_doit = devlink_nl_pre_doit_port,
843: .doit = devlink_nl_sb_port_pool_set_doit,
844: .post_doit = devlink_nl_post_doit,
845: .policy = devlink_sb_port_pool_set_nl_policy,
846: .maxattr = DEVLINK_ATTR_INDEX,
847: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
848: },
849: {
850: .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
851: .validate = GENL_DONT_VALIDATE_STRICT,
852: .pre_doit = devlink_nl_pre_doit_port,
853: .doit = devlink_nl_sb_tc_pool_bind_get_doit,
854: .post_doit = devlink_nl_post_doit,
855: .policy = devlink_sb_tc_pool_bind_get_do_nl_policy,
856: .maxattr = DEVLINK_ATTR_INDEX,
857: .flags = GENL_CMD_CAP_DO,
858: },
859: {
860: .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
861: .dumpit = devlink_nl_sb_tc_pool_bind_get_dumpit,
862: .policy = devlink_sb_tc_pool_bind_get_dump_nl_policy,
863: .maxattr = DEVLINK_ATTR_INDEX,
864: .flags = GENL_CMD_CAP_DUMP,
865: },
866: {
867: .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
868: .validate = GENL_DONT_VALIDATE_STRICT,
869: .pre_doit = devlink_nl_pre_doit_port,
870: .doit = devlink_nl_sb_tc_pool_bind_set_doit,
871: .post_doit = devlink_nl_post_doit,
872: .policy = devlink_sb_tc_pool_bind_set_nl_policy,
873: .maxattr = DEVLINK_ATTR_INDEX,
874: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
875: },
876: {
877: .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
878: .validate = GENL_DONT_VALIDATE_STRICT,
879: .pre_doit = devlink_nl_pre_doit,
880: .doit = devlink_nl_sb_occ_snapshot_doit,
881: .post_doit = devlink_nl_post_doit,
882: .policy = devlink_sb_occ_snapshot_nl_policy,
883: .maxattr = DEVLINK_ATTR_INDEX,
884: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
885: },
886: {
887: .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
888: .validate = GENL_DONT_VALIDATE_STRICT,
889: .pre_doit = devlink_nl_pre_doit,
890: .doit = devlink_nl_sb_occ_max_clear_doit,
891: .post_doit = devlink_nl_post_doit,
892: .policy = devlink_sb_occ_max_clear_nl_policy,
893: .maxattr = DEVLINK_ATTR_INDEX,
894: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
895: },
896: {
897: .cmd = DEVLINK_CMD_ESWITCH_GET,
898: .validate = GENL_DONT_VALIDATE_STRICT,
899: .pre_doit = devlink_nl_pre_doit,
900: .doit = devlink_nl_eswitch_get_doit,
901: .post_doit = devlink_nl_post_doit,
902: .policy = devlink_eswitch_get_nl_policy,
903: .maxattr = DEVLINK_ATTR_INDEX,
904: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
905: },
906: {
907: .cmd = DEVLINK_CMD_ESWITCH_SET,
908: .validate = GENL_DONT_VALIDATE_STRICT,
909: .pre_doit = devlink_nl_pre_doit,
910: .doit = devlink_nl_eswitch_set_doit,
911: .post_doit = devlink_nl_post_doit,
912: .policy = devlink_eswitch_set_nl_policy,
913: .maxattr = DEVLINK_ATTR_INDEX,
914: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
915: },
916: {
917: .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
918: .validate = GENL_DONT_VALIDATE_STRICT,
919: .pre_doit = devlink_nl_pre_doit,
920: .doit = devlink_nl_dpipe_table_get_doit,
921: .post_doit = devlink_nl_post_doit,
922: .policy = devlink_dpipe_table_get_nl_policy,
923: .maxattr = DEVLINK_ATTR_INDEX,
924: .flags = GENL_CMD_CAP_DO,
925: },
926: {
927: .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
928: .validate = GENL_DONT_VALIDATE_STRICT,
929: .pre_doit = devlink_nl_pre_doit,
930: .doit = devlink_nl_dpipe_entries_get_doit,
931: .post_doit = devlink_nl_post_doit,
932: .policy = devlink_dpipe_entries_get_nl_policy,
933: .maxattr = DEVLINK_ATTR_INDEX,
934: .flags = GENL_CMD_CAP_DO,
935: },
936: {
937: .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
938: .validate = GENL_DONT_VALIDATE_STRICT,
939: .pre_doit = devlink_nl_pre_doit,
940: .doit = devlink_nl_dpipe_headers_get_doit,
941: .post_doit = devlink_nl_post_doit,
942: .policy = devlink_dpipe_headers_get_nl_policy,
943: .maxattr = DEVLINK_ATTR_INDEX,
944: .flags = GENL_CMD_CAP_DO,
945: },
946: {
947: .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
948: .validate = GENL_DONT_VALIDATE_STRICT,
949: .pre_doit = devlink_nl_pre_doit,
950: .doit = devlink_nl_dpipe_table_counters_set_doit,
951: .post_doit = devlink_nl_post_doit,
952: .policy = devlink_dpipe_table_counters_set_nl_policy,
953: .maxattr = DEVLINK_ATTR_INDEX,
954: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
955: },
956: {
957: .cmd = DEVLINK_CMD_RESOURCE_SET,
958: .validate = GENL_DONT_VALIDATE_STRICT,
959: .pre_doit = devlink_nl_pre_doit,
960: .doit = devlink_nl_resource_set_doit,
961: .post_doit = devlink_nl_post_doit,
962: .policy = devlink_resource_set_nl_policy,
963: .maxattr = DEVLINK_ATTR_INDEX,
964: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
965: },
966: {
967: .cmd = DEVLINK_CMD_RESOURCE_DUMP,
968: .validate = GENL_DONT_VALIDATE_STRICT,
969: .pre_doit = devlink_nl_pre_doit_port_optional,
970: .doit = devlink_nl_resource_dump_doit,
971: .post_doit = devlink_nl_post_doit,
972: .policy = devlink_resource_dump_do_nl_policy,
973: .maxattr = DEVLINK_ATTR_INDEX,
974: .flags = GENL_CMD_CAP_DO,
975: },
976: {
977: .cmd = DEVLINK_CMD_RESOURCE_DUMP,
978: .dumpit = devlink_nl_resource_dump_dumpit,
979: .policy = devlink_resource_dump_dump_nl_policy,
980: .maxattr = DEVLINK_ATTR_RESOURCE_SCOPE_MASK,
981: .flags = GENL_CMD_CAP_DUMP,
982: },
983: {
984: .cmd = DEVLINK_CMD_RELOAD,
985: .validate = GENL_DONT_VALIDATE_STRICT,
986: .pre_doit = devlink_nl_pre_doit_dev_lock,
987: .doit = devlink_nl_reload_doit,
988: .post_doit = devlink_nl_post_doit_dev_lock,
989: .policy = devlink_reload_nl_policy,
990: .maxattr = DEVLINK_ATTR_INDEX,
991: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
992: },
993: {
994: .cmd = DEVLINK_CMD_PARAM_GET,
995: .validate = GENL_DONT_VALIDATE_STRICT,
996: .pre_doit = devlink_nl_pre_doit,
997: .doit = devlink_nl_param_get_doit,
998: .post_doit = devlink_nl_post_doit,
999: .policy = devlink_param_get_do_nl_policy,
1000: .maxattr = DEVLINK_ATTR_INDEX,
1001: .flags = GENL_CMD_CAP_DO,
1002: },
1003: {
1004: .cmd = DEVLINK_CMD_PARAM_GET,
1005: .dumpit = devlink_nl_param_get_dumpit,
1006: .policy = devlink_param_get_dump_nl_policy,
1007: .maxattr = DEVLINK_ATTR_INDEX,
1008: .flags = GENL_CMD_CAP_DUMP,
1009: },
1010: {
1011: .cmd = DEVLINK_CMD_PARAM_SET,
1012: .validate = GENL_DONT_VALIDATE_STRICT,
1013: .pre_doit = devlink_nl_pre_doit,
1014: .doit = devlink_nl_param_set_doit,
1015: .post_doit = devlink_nl_post_doit,
1016: .policy = devlink_param_set_nl_policy,
1017: .maxattr = DEVLINK_ATTR_INDEX,
1018: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1019: },
1020: {
1021: .cmd = DEVLINK_CMD_REGION_GET,
1022: .validate = GENL_DONT_VALIDATE_STRICT,
1023: .pre_doit = devlink_nl_pre_doit_port_optional,
1024: .doit = devlink_nl_region_get_doit,
1025: .post_doit = devlink_nl_post_doit,
1026: .policy = devlink_region_get_do_nl_policy,
1027: .maxattr = DEVLINK_ATTR_INDEX,
1028: .flags = GENL_CMD_CAP_DO,
1029: },
1030: {
1031: .cmd = DEVLINK_CMD_REGION_GET,
1032: .dumpit = devlink_nl_region_get_dumpit,
1033: .policy = devlink_region_get_dump_nl_policy,
1034: .maxattr = DEVLINK_ATTR_INDEX,
1035: .flags = GENL_CMD_CAP_DUMP,
1036: },
1037: {
1038: .cmd = DEVLINK_CMD_REGION_NEW,
1039: .validate = GENL_DONT_VALIDATE_STRICT,
1040: .pre_doit = devlink_nl_pre_doit_port_optional,
1041: .doit = devlink_nl_region_new_doit,
1042: .post_doit = devlink_nl_post_doit,
1043: .policy = devlink_region_new_nl_policy,
1044: .maxattr = DEVLINK_ATTR_INDEX,
1045: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1046: },
1047: {
1048: .cmd = DEVLINK_CMD_REGION_DEL,
1049: .validate = GENL_DONT_VALIDATE_STRICT,
1050: .pre_doit = devlink_nl_pre_doit_port_optional,
1051: .doit = devlink_nl_region_del_doit,
1052: .post_doit = devlink_nl_post_doit,
1053: .policy = devlink_region_del_nl_policy,
1054: .maxattr = DEVLINK_ATTR_INDEX,
1055: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1056: },
1057: {
1058: .cmd = DEVLINK_CMD_REGION_READ,
1059: .validate = GENL_DONT_VALIDATE_DUMP_STRICT,
1060: .dumpit = devlink_nl_region_read_dumpit,
1061: .policy = devlink_region_read_nl_policy,
1062: .maxattr = DEVLINK_ATTR_INDEX,
1063: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
1064: },
1065: {
1066: .cmd = DEVLINK_CMD_PORT_PARAM_GET,
1067: .validate = GENL_DONT_VALIDATE_STRICT,
1068: .pre_doit = devlink_nl_pre_doit_port,
1069: .doit = devlink_nl_port_param_get_doit,
1070: .post_doit = devlink_nl_post_doit,
1071: .policy = devlink_port_param_get_nl_policy,
1072: .maxattr = DEVLINK_ATTR_INDEX,
1073: .flags = GENL_CMD_CAP_DO,
1074: },
1075: {
1076: .cmd = DEVLINK_CMD_PORT_PARAM_GET,
1077: .validate = GENL_DONT_VALIDATE_DUMP_STRICT,
1078: .dumpit = devlink_nl_port_param_get_dumpit,
1079: .flags = GENL_CMD_CAP_DUMP,
1080: },
1081: {
1082: .cmd = DEVLINK_CMD_PORT_PARAM_SET,
1083: .validate = GENL_DONT_VALIDATE_STRICT,
1084: .pre_doit = devlink_nl_pre_doit_port,
1085: .doit = devlink_nl_port_param_set_doit,
1086: .post_doit = devlink_nl_post_doit,
1087: .policy = devlink_port_param_set_nl_policy,
1088: .maxattr = DEVLINK_ATTR_INDEX,
1089: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1090: },
1091: {
1092: .cmd = DEVLINK_CMD_INFO_GET,
1093: .validate = GENL_DONT_VALIDATE_STRICT,
1094: .pre_doit = devlink_nl_pre_doit,
1095: .doit = devlink_nl_info_get_doit,
1096: .post_doit = devlink_nl_post_doit,
1097: .policy = devlink_info_get_nl_policy,
1098: .maxattr = DEVLINK_ATTR_INDEX,
1099: .flags = GENL_CMD_CAP_DO,
1100: },
1101: {
1102: .cmd = DEVLINK_CMD_INFO_GET,
1103: .validate = GENL_DONT_VALIDATE_DUMP,
1104: .dumpit = devlink_nl_info_get_dumpit,
1105: .flags = GENL_CMD_CAP_DUMP,
1106: },
1107: {
1108: .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
1109: .validate = GENL_DONT_VALIDATE_STRICT,
1110: .pre_doit = devlink_nl_pre_doit_port_optional,
1111: .doit = devlink_nl_health_reporter_get_doit,
1112: .post_doit = devlink_nl_post_doit,
1113: .policy = devlink_health_reporter_get_do_nl_policy,
1114: .maxattr = DEVLINK_ATTR_INDEX,
1115: .flags = GENL_CMD_CAP_DO,
1116: },
1117: {
1118: .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
1119: .dumpit = devlink_nl_health_reporter_get_dumpit,
1120: .policy = devlink_health_reporter_get_dump_nl_policy,
1121: .maxattr = DEVLINK_ATTR_INDEX,
1122: .flags = GENL_CMD_CAP_DUMP,
1123: },
1124: {
1125: .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
1126: .validate = GENL_DONT_VALIDATE_STRICT,
1127: .pre_doit = devlink_nl_pre_doit_port_optional,
1128: .doit = devlink_nl_health_reporter_set_doit,
1129: .post_doit = devlink_nl_post_doit,
1130: .policy = devlink_health_reporter_set_nl_policy,
1131: .maxattr = DEVLINK_ATTR_INDEX,
1132: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1133: },
1134: {
1135: .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
1136: .validate = GENL_DONT_VALIDATE_STRICT,
1137: .pre_doit = devlink_nl_pre_doit_port_optional,
1138: .doit = devlink_nl_health_reporter_recover_doit,
1139: .post_doit = devlink_nl_post_doit,
1140: .policy = devlink_health_reporter_recover_nl_policy,
1141: .maxattr = DEVLINK_ATTR_INDEX,
1142: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1143: },
1144: {
1145: .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
1146: .validate = GENL_DONT_VALIDATE_STRICT,
1147: .pre_doit = devlink_nl_pre_doit_port_optional,
1148: .doit = devlink_nl_health_reporter_diagnose_doit,
1149: .post_doit = devlink_nl_post_doit,
1150: .policy = devlink_health_reporter_diagnose_nl_policy,
1151: .maxattr = DEVLINK_ATTR_INDEX,
1152: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1153: },
1154: {
1155: .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
1156: .validate = GENL_DONT_VALIDATE_DUMP_STRICT,
1157: .dumpit = devlink_nl_health_reporter_dump_get_dumpit,
1158: .policy = devlink_health_reporter_dump_get_nl_policy,
1159: .maxattr = DEVLINK_ATTR_INDEX,
1160: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
1161: },
1162: {
1163: .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
1164: .validate = GENL_DONT_VALIDATE_STRICT,
1165: .pre_doit = devlink_nl_pre_doit_port_optional,
1166: .doit = devlink_nl_health_reporter_dump_clear_doit,
1167: .post_doit = devlink_nl_post_doit,
1168: .policy = devlink_health_reporter_dump_clear_nl_policy,
1169: .maxattr = DEVLINK_ATTR_INDEX,
1170: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1171: },
1172: {
1173: .cmd = DEVLINK_CMD_FLASH_UPDATE,
1174: .validate = GENL_DONT_VALIDATE_STRICT,
1175: .pre_doit = devlink_nl_pre_doit,
1176: .doit = devlink_nl_flash_update_doit,
1177: .post_doit = devlink_nl_post_doit,
1178: .policy = devlink_flash_update_nl_policy,
1179: .maxattr = DEVLINK_ATTR_INDEX,
1180: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1181: },
1182: {
1183: .cmd = DEVLINK_CMD_TRAP_GET,
1184: .validate = GENL_DONT_VALIDATE_STRICT,
1185: .pre_doit = devlink_nl_pre_doit,
1186: .doit = devlink_nl_trap_get_doit,
1187: .post_doit = devlink_nl_post_doit,
1188: .policy = devlink_trap_get_do_nl_policy,
1189: .maxattr = DEVLINK_ATTR_INDEX,
1190: .flags = GENL_CMD_CAP_DO,
1191: },
1192: {
1193: .cmd = DEVLINK_CMD_TRAP_GET,
1194: .dumpit = devlink_nl_trap_get_dumpit,
1195: .policy = devlink_trap_get_dump_nl_policy,
1196: .maxattr = DEVLINK_ATTR_INDEX,
1197: .flags = GENL_CMD_CAP_DUMP,
1198: },
1199: {
1200: .cmd = DEVLINK_CMD_TRAP_SET,
1201: .validate = GENL_DONT_VALIDATE_STRICT,
1202: .pre_doit = devlink_nl_pre_doit,
1203: .doit = devlink_nl_trap_set_doit,
1204: .post_doit = devlink_nl_post_doit,
1205: .policy = devlink_trap_set_nl_policy,
1206: .maxattr = DEVLINK_ATTR_INDEX,
1207: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1208: },
1209: {
1210: .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
1211: .validate = GENL_DONT_VALIDATE_STRICT,
1212: .pre_doit = devlink_nl_pre_doit,
1213: .doit = devlink_nl_trap_group_get_doit,
1214: .post_doit = devlink_nl_post_doit,
1215: .policy = devlink_trap_group_get_do_nl_policy,
1216: .maxattr = DEVLINK_ATTR_INDEX,
1217: .flags = GENL_CMD_CAP_DO,
1218: },
1219: {
1220: .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
1221: .dumpit = devlink_nl_trap_group_get_dumpit,
1222: .policy = devlink_trap_group_get_dump_nl_policy,
1223: .maxattr = DEVLINK_ATTR_INDEX,
1224: .flags = GENL_CMD_CAP_DUMP,
1225: },
1226: {
1227: .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
1228: .validate = GENL_DONT_VALIDATE_STRICT,
1229: .pre_doit = devlink_nl_pre_doit,
1230: .doit = devlink_nl_trap_group_set_doit,
1231: .post_doit = devlink_nl_post_doit,
1232: .policy = devlink_trap_group_set_nl_policy,
1233: .maxattr = DEVLINK_ATTR_INDEX,
1234: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1235: },
1236: {
1237: .cmd = DEVLINK_CMD_TRAP_POLICER_GET,
1238: .validate = GENL_DONT_VALIDATE_STRICT,
1239: .pre_doit = devlink_nl_pre_doit,
1240: .doit = devlink_nl_trap_policer_get_doit,
1241: .post_doit = devlink_nl_post_doit,
1242: .policy = devlink_trap_policer_get_do_nl_policy,
1243: .maxattr = DEVLINK_ATTR_INDEX,
1244: .flags = GENL_CMD_CAP_DO,
1245: },
1246: {
1247: .cmd = DEVLINK_CMD_TRAP_POLICER_GET,
1248: .dumpit = devlink_nl_trap_policer_get_dumpit,
1249: .policy = devlink_trap_policer_get_dump_nl_policy,
1250: .maxattr = DEVLINK_ATTR_INDEX,
1251: .flags = GENL_CMD_CAP_DUMP,
1252: },
1253: {
1254: .cmd = DEVLINK_CMD_TRAP_POLICER_SET,
1255: .validate = GENL_DONT_VALIDATE_STRICT,
1256: .pre_doit = devlink_nl_pre_doit,
1257: .doit = devlink_nl_trap_policer_set_doit,
1258: .post_doit = devlink_nl_post_doit,
1259: .policy = devlink_trap_policer_set_nl_policy,
1260: .maxattr = DEVLINK_ATTR_INDEX,
1261: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1262: },
1263: {
1264: .cmd = DEVLINK_CMD_HEALTH_REPORTER_TEST,
1265: .validate = GENL_DONT_VALIDATE_STRICT,
1266: .pre_doit = devlink_nl_pre_doit_port_optional,
1267: .doit = devlink_nl_health_reporter_test_doit,
1268: .post_doit = devlink_nl_post_doit,
1269: .policy = devlink_health_reporter_test_nl_policy,
1270: .maxattr = DEVLINK_ATTR_INDEX,
1271: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1272: },
1273: {
1274: .cmd = DEVLINK_CMD_RATE_GET,
1275: .validate = GENL_DONT_VALIDATE_STRICT,
1276: .pre_doit = devlink_nl_pre_doit,
1277: .doit = devlink_nl_rate_get_doit,
1278: .post_doit = devlink_nl_post_doit,
1279: .policy = devlink_rate_get_do_nl_policy,
1280: .maxattr = DEVLINK_ATTR_INDEX,
1281: .flags = GENL_CMD_CAP_DO,
1282: },
1283: {
1284: .cmd = DEVLINK_CMD_RATE_GET,
1285: .dumpit = devlink_nl_rate_get_dumpit,
1286: .policy = devlink_rate_get_dump_nl_policy,
1287: .maxattr = DEVLINK_ATTR_INDEX,
1288: .flags = GENL_CMD_CAP_DUMP,
1289: },
1290: {
1291: .cmd = DEVLINK_CMD_RATE_SET,
1292: .validate = GENL_DONT_VALIDATE_STRICT,
1293: .pre_doit = devlink_nl_pre_doit,
1294: .doit = devlink_nl_rate_set_doit,
1295: .post_doit = devlink_nl_post_doit,
1296: .policy = devlink_rate_set_nl_policy,
1297: .maxattr = DEVLINK_ATTR_INDEX,
1298: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1299: },
1300: {
1301: .cmd = DEVLINK_CMD_RATE_NEW,
1302: .validate = GENL_DONT_VALIDATE_STRICT,
1303: .pre_doit = devlink_nl_pre_doit,
1304: .doit = devlink_nl_rate_new_doit,
1305: .post_doit = devlink_nl_post_doit,
1306: .policy = devlink_rate_new_nl_policy,
1307: .maxattr = DEVLINK_ATTR_INDEX,
1308: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1309: },
1310: {
1311: .cmd = DEVLINK_CMD_RATE_DEL,
1312: .validate = GENL_DONT_VALIDATE_STRICT,
1313: .pre_doit = devlink_nl_pre_doit,
1314: .doit = devlink_nl_rate_del_doit,
1315: .post_doit = devlink_nl_post_doit,
1316: .policy = devlink_rate_del_nl_policy,
1317: .maxattr = DEVLINK_ATTR_INDEX,
1318: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1319: },
1320: {
1321: .cmd = DEVLINK_CMD_LINECARD_GET,
1322: .validate = GENL_DONT_VALIDATE_STRICT,
1323: .pre_doit = devlink_nl_pre_doit,
1324: .doit = devlink_nl_linecard_get_doit,
1325: .post_doit = devlink_nl_post_doit,
1326: .policy = devlink_linecard_get_do_nl_policy,
1327: .maxattr = DEVLINK_ATTR_INDEX,
1328: .flags = GENL_CMD_CAP_DO,
1329: },
1330: {
1331: .cmd = DEVLINK_CMD_LINECARD_GET,
1332: .dumpit = devlink_nl_linecard_get_dumpit,
1333: .policy = devlink_linecard_get_dump_nl_policy,
1334: .maxattr = DEVLINK_ATTR_INDEX,
1335: .flags = GENL_CMD_CAP_DUMP,
1336: },
1337: {
1338: .cmd = DEVLINK_CMD_LINECARD_SET,
1339: .validate = GENL_DONT_VALIDATE_STRICT,
1340: .pre_doit = devlink_nl_pre_doit,
1341: .doit = devlink_nl_linecard_set_doit,
1342: .post_doit = devlink_nl_post_doit,
1343: .policy = devlink_linecard_set_nl_policy,
1344: .maxattr = DEVLINK_ATTR_INDEX,
1345: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1346: },
1347: {
1348: .cmd = DEVLINK_CMD_SELFTESTS_GET,
1349: .validate = GENL_DONT_VALIDATE_STRICT,
1350: .pre_doit = devlink_nl_pre_doit,
1351: .doit = devlink_nl_selftests_get_doit,
1352: .post_doit = devlink_nl_post_doit,
1353: .policy = devlink_selftests_get_nl_policy,
1354: .maxattr = DEVLINK_ATTR_INDEX,
1355: .flags = GENL_CMD_CAP_DO,
1356: },
1357: {
1358: .cmd = DEVLINK_CMD_SELFTESTS_GET,
1359: .validate = GENL_DONT_VALIDATE_DUMP,
1360: .dumpit = devlink_nl_selftests_get_dumpit,
1361: .flags = GENL_CMD_CAP_DUMP,
1362: },
1363: {
1364: .cmd = DEVLINK_CMD_SELFTESTS_RUN,
1365: .validate = GENL_DONT_VALIDATE_STRICT,
1366: .pre_doit = devlink_nl_pre_doit,
1367: .doit = devlink_nl_selftests_run_doit,
1368: .post_doit = devlink_nl_post_doit,
1369: .policy = devlink_selftests_run_nl_policy,
1370: .maxattr = DEVLINK_ATTR_INDEX,
1371: .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
1372: },
1373: {
1374: .cmd = DEVLINK_CMD_NOTIFY_FILTER_SET,
1375: .doit = devlink_nl_notify_filter_set_doit,
1376: .policy = devlink_notify_filter_set_nl_policy,
1377: .maxattr = DEVLINK_ATTR_INDEX,
1378: .flags = GENL_CMD_CAP_DO,
1379: },
1380: };
SourceFile:net/devlink/netlink_gen.c]
|
| 32/2 |
2026/07/30 00:08 |
llm |
expert |
0m
Model:
Tokens:
input: 36400
output: 24
thoughts: 171
Thoughts: **Investigating the Security Implications of `DEVLINK_CMD_FLASH_UPDATE`**
Okay, so I'm digging into this `DEVLINK_CMD_FLASH_UPDATE` command. It has these flags, `.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO`. That `GENL_ADMIN_PERM` bit is the key. It means the user needs `CAP_NET_ADMIN` in the namespace where the Netlink socket is opened to even *use* this thing. That's my starting point.
Hereβs where it gets interesting: can an unprivileged user just *get* that capability and bypass the intended protections? Well, they can create a user namespace and a network namespace, and then poof β they have `CAP_NET_ADMIN` in *that* isolated environment. So, can they then just go ahead and create a devlink device within this newly minted namespace? That's the core question I need to answer.
I need to investigate if there are any *virtual* devlink devices that unprivileged users *could* potentially create within their own namespace. A critical attack vector would be a virtual device type that can be manipulated by `devlink` commands.
Let's look at `netdevsim`. It's a virtual device, and as far as I know, it supports devlink. This seems like a likely candidate to test. Can an unprivileged user, ensconced in their shiny new user namespace, actually spin up a `netdevsim` instance? That's what I need to check. Let's dig into the `netdevsim` creation process and see what it takes.
|
| 33/2 |
2026/07/30 00:08 |
tool |
codesearch-definition-source |
0m
Error:
Args: map[Name:nsim_dev_create]
Results: map[SourceCode: SourceFile:]
|
| 34/2 |
2026/07/30 00:08 |
llm |
expert |
0m
Model:
Tokens:
input: 36977
output: 31
thoughts: 12
Thoughts: Okay, here's my attempt at summarizing that thought process, tailored for an expert audience:
**Investigating `netdevsim` Creation**
Right, let's dive straight in. My first thought is to pinpoint the creation of `netdevsim`. I need to figure out how this virtual network device gets instantiated and brought into existence. I'm thinking I'll start with a targeted search string, something like, you guessed it, "`netdevsim` creation." This should give me a pretty good starting point. I'm expecting to see kernel function calls, maybe some module loading, definitely some `struct net_device` allocation, and initialization calls. My intuition is telling me I need to chase that thread.
|
| 35/2 |
2026/07/30 00:08 |
tool |
grepper |
0m
Args: map[Expression:netdevsim PathPrefix:drivers/net/netdevsim/]
Results: map[Output:
Full output is too long, showing 500 out of 811 lines.
Use more precise expression if possible.
drivers/net/netdevsim/Makefile-2-
drivers/net/netdevsim/Makefile:3:obj-$(CONFIG_NETDEVSIM) += netdevsim.o
drivers/net/netdevsim/Makefile-4-
drivers/net/netdevsim/Makefile:5:netdevsim-objs := \
drivers/net/netdevsim/Makefile-6- netdev.o dev.o ethtool.o fib.o bus.o health.o hwstats.o udp_tunnels.o tc.o
--
drivers/net/netdevsim/Makefile=8=ifeq ($(CONFIG_BPF_SYSCALL),y)
drivers/net/netdevsim/Makefile:9:netdevsim-objs += \
drivers/net/netdevsim/Makefile-10- bpf.o
--
drivers/net/netdevsim/Makefile=13=ifneq ($(CONFIG_XFRM_OFFLOAD),)
drivers/net/netdevsim/Makefile:14:netdevsim-objs += ipsec.o
drivers/net/netdevsim/Makefile-15-endif
--
drivers/net/netdevsim/Makefile=17=ifneq ($(CONFIG_PSAMPLE),)
drivers/net/netdevsim/Makefile:18:netdevsim-objs += psample.o
drivers/net/netdevsim/Makefile-19-endif
--
drivers/net/netdevsim/Makefile=21=ifneq ($(CONFIG_INET_PSP),)
drivers/net/netdevsim/Makefile:22:netdevsim-objs += psp.o
drivers/net/netdevsim/Makefile-23-endif
--
drivers/net/netdevsim/Makefile=25=ifneq ($(CONFIG_MACSEC),)
drivers/net/netdevsim/Makefile:26:netdevsim-objs += macsec.o
drivers/net/netdevsim/Makefile-27-endif
--
drivers/net/netdevsim/bpf.c-23-
drivers/net/netdevsim/bpf.c:24:#include "netdevsim.h"
drivers/net/netdevsim/bpf.c-25-
drivers/net/netdevsim/bpf.c-26-#define pr_vlog(env, fmt, ...) \
drivers/net/netdevsim/bpf.c:27: bpf_verifier_log_write(env, "[netdevsim] " fmt, ##__VA_ARGS__)
drivers/net/netdevsim/bpf.c-28-
--
drivers/net/netdevsim/bpf.c=40=struct nsim_bpf_bound_map {
drivers/net/netdevsim/bpf.c:41: struct netdevsim *ns;
drivers/net/netdevsim/bpf.c-42- struct bpf_offloaded_map *map;
--
drivers/net/netdevsim/bpf.c=63=nsim_bpf_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn)
--
drivers/net/netdevsim/bpf.c-72- if (insn_idx == env->prog->len - 1) {
drivers/net/netdevsim/bpf.c:73: pr_vlog(env, "Hello from netdevsim!\n");
drivers/net/netdevsim/bpf.c-74-
--
drivers/net/netdevsim/bpf.c=82=static int nsim_bpf_finalize(struct bpf_verifier_env *env)
--
drivers/net/netdevsim/bpf.c-86-
drivers/net/netdevsim/bpf.c:87:static bool nsim_xdp_offload_active(struct netdevsim *ns)
drivers/net/netdevsim/bpf.c-88-{
--
drivers/net/netdevsim/bpf.c=103=static int
drivers/net/netdevsim/bpf.c:104:nsim_bpf_offload(struct netdevsim *ns, struct bpf_prog *prog, bool oldprog)
drivers/net/netdevsim/bpf.c-105-{
--
drivers/net/netdevsim/bpf.c=118=int nsim_bpf_setup_tc_block_cb(enum tc_setup_type type,
--
drivers/net/netdevsim/bpf.c-122- struct bpf_prog *prog = cls_bpf->prog;
drivers/net/netdevsim/bpf.c:123: struct netdevsim *ns = cb_priv;
drivers/net/netdevsim/bpf.c-124- struct bpf_prog *oldprog;
--
drivers/net/netdevsim/bpf.c-136- NSIM_EA(cls_bpf->common.extack,
drivers/net/netdevsim/bpf.c:137: "netdevsim configured to reject BPF TC offload");
drivers/net/netdevsim/bpf.c-138- return -EOPNOTSUPP;
--
drivers/net/netdevsim/bpf.c-142- NSIM_EA(cls_bpf->common.extack,
drivers/net/netdevsim/bpf.c:143: "netdevsim configured to reject unbound programs");
drivers/net/netdevsim/bpf.c-144- return -EOPNOTSUPP;
--
drivers/net/netdevsim/bpf.c-166-
drivers/net/netdevsim/bpf.c:167:int nsim_bpf_disable_tc(struct netdevsim *ns)
drivers/net/netdevsim/bpf.c-168-{
--
drivers/net/netdevsim/bpf.c-173-
drivers/net/netdevsim/bpf.c:174:static int nsim_xdp_offload_prog(struct netdevsim *ns, struct netdev_bpf *bpf)
drivers/net/netdevsim/bpf.c-175-{
--
drivers/net/netdevsim/bpf.c=186=static int
drivers/net/netdevsim/bpf.c:187:nsim_xdp_set_prog(struct netdevsim *ns, struct netdev_bpf *bpf,
drivers/net/netdevsim/bpf.c-188- struct xdp_attachment_info *xdp)
--
drivers/net/netdevsim/bpf.c=285=static const struct bpf_prog_offload_ops nsim_bpf_dev_ops = {
--
drivers/net/netdevsim/bpf.c-292-
drivers/net/netdevsim/bpf.c:293:static int nsim_setup_prog_checks(struct netdevsim *ns, struct netdev_bpf *bpf)
drivers/net/netdevsim/bpf.c-294-{
--
drivers/net/netdevsim/bpf.c=307=static int
drivers/net/netdevsim/bpf.c:308:nsim_setup_prog_hw_checks(struct netdevsim *ns, struct netdev_bpf *bpf)
drivers/net/netdevsim/bpf.c-309-{
--
drivers/net/netdevsim/bpf.c=484=static int
drivers/net/netdevsim/bpf.c:485:nsim_bpf_map_alloc(struct netdevsim *ns, struct bpf_offloaded_map *offmap)
drivers/net/netdevsim/bpf.c-486-{
--
drivers/net/netdevsim/bpf.c=548=int nsim_bpf(struct net_device *dev, struct netdev_bpf *bpf)
drivers/net/netdevsim/bpf.c-549-{
drivers/net/netdevsim/bpf.c:550: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/bpf.c-551- int err;
--
drivers/net/netdevsim/bpf.c=609=void nsim_bpf_dev_exit(struct nsim_dev *nsim_dev)
--
drivers/net/netdevsim/bpf.c-615-
drivers/net/netdevsim/bpf.c:616:int nsim_bpf_init(struct netdevsim *ns)
drivers/net/netdevsim/bpf.c-617-{
--
drivers/net/netdevsim/bpf.c-647-
drivers/net/netdevsim/bpf.c:648:void nsim_bpf_uninit(struct netdevsim *ns)
drivers/net/netdevsim/bpf.c-649-{
--
drivers/net/netdevsim/bus.c-15-
drivers/net/netdevsim/bus.c:16:#include "netdevsim.h"
drivers/net/netdevsim/bus.c-17-
--
drivers/net/netdevsim/bus.c=253=static ssize_t link_device_store(const struct bus_type *bus, const char *buf, size_t count)
drivers/net/netdevsim/bus.c-254-{
drivers/net/netdevsim/bus.c:255: struct netdevsim *nsim_a, *nsim_b, *peer;
drivers/net/netdevsim/bus.c-256- struct net_device *dev_a, *dev_b;
--
drivers/net/netdevsim/bus.c-290- if (!netdev_is_nsim(dev_a)) {
drivers/net/netdevsim/bus.c:291: pr_err("Device with ifindex %u in netnsfd %d is not a netdevsim\n",
drivers/net/netdevsim/bus.c-292- ifidx_a, netnsfd_a);
--
drivers/net/netdevsim/bus.c-303- if (!netdev_is_nsim(dev_b)) {
drivers/net/netdevsim/bus.c:304: pr_err("Device with ifindex %u in netnsfd %d is not a netdevsim\n",
drivers/net/netdevsim/bus.c-305- ifidx_b, netnsfd_b);
--
drivers/net/netdevsim/bus.c-309- if (dev_a == dev_b) {
drivers/net/netdevsim/bus.c:310: pr_err("Cannot link a netdevsim to itself\n");
drivers/net/netdevsim/bus.c-311- goto out_err;
--
drivers/net/netdevsim/bus.c=349=static ssize_t unlink_device_store(const struct bus_type *bus, const char *buf, size_t count)
drivers/net/netdevsim/bus.c-350-{
drivers/net/netdevsim/bus.c:351: struct netdevsim *nsim, *peer;
drivers/net/netdevsim/bus.c-352- struct net_device *dev;
--
drivers/net/netdevsim/bus.c-378- if (!netdev_is_nsim(dev)) {
drivers/net/netdevsim/bus.c:379: pr_err("Device with ifindex %u in netnsfd %d is not a netdevsim\n",
drivers/net/netdevsim/bus.c-380- ifidx, netnsfd);
--
drivers/net/netdevsim/dev.c-36-
drivers/net/netdevsim/dev.c:37:#include "netdevsim.h"
drivers/net/netdevsim/dev.c-38-
--
drivers/net/netdevsim/dev.c=667=static int nsim_esw_switchdev_enable(struct nsim_dev *nsim_dev,
--
drivers/net/netdevsim/dev.c-675- if (err) {
drivers/net/netdevsim/dev.c:676: NL_SET_ERR_MSG_MOD(extack, "Failed to initialize VFs' netdevsim ports");
drivers/net/netdevsim/dev.c-677- pr_err("Failed to initialize VF id=%d. %d.\n", i, err);
--
drivers/net/netdevsim/dev.c=720=struct nsim_trap_data {
--
drivers/net/netdevsim/dev.c-729-/* All driver-specific traps must be documented in
drivers/net/netdevsim/dev.c:730: * Documentation/networking/devlink/netdevsim.rst
drivers/net/netdevsim/dev.c-731- */
--
drivers/net/netdevsim/ethtool.c-7-
drivers/net/netdevsim/ethtool.c:8:#include "netdevsim.h"
drivers/net/netdevsim/ethtool.c-9-
--
drivers/net/netdevsim/ethtool.c=11=nsim_get_pause_stats(struct net_device *dev,
--
drivers/net/netdevsim/ethtool.c-13-{
drivers/net/netdevsim/ethtool.c:14: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ethtool.c-15-
--
drivers/net/netdevsim/ethtool.c=23=nsim_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
drivers/net/netdevsim/ethtool.c-24-{
drivers/net/netdevsim/ethtool.c:25: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ethtool.c-26-
--
drivers/net/netdevsim/ethtool.c=33=nsim_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
drivers/net/netdevsim/ethtool.c-34-{
drivers/net/netdevsim/ethtool.c:35: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ethtool.c-36-
--
drivers/net/netdevsim/ethtool.c=45=static int nsim_get_coalesce(struct net_device *dev,
--
drivers/net/netdevsim/ethtool.c-49-{
drivers/net/netdevsim/ethtool.c:50: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ethtool.c-51-
--
drivers/net/netdevsim/ethtool.c=56=static int nsim_set_coalesce(struct net_device *dev,
--
drivers/net/netdevsim/ethtool.c-60-{
drivers/net/netdevsim/ethtool.c:61: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ethtool.c-62-
--
drivers/net/netdevsim/ethtool.c=67=static void nsim_get_ringparam(struct net_device *dev,
--
drivers/net/netdevsim/ethtool.c-71-{
drivers/net/netdevsim/ethtool.c:72: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ethtool.c-73-
--
drivers/net/netdevsim/ethtool.c=81=static int nsim_set_ringparam(struct net_device *dev,
--
drivers/net/netdevsim/ethtool.c-85-{
drivers/net/netdevsim/ethtool.c:86: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ethtool.c-87-
--
drivers/net/netdevsim/ethtool.c=96=nsim_get_channels(struct net_device *dev, struct ethtool_channels *ch)
drivers/net/netdevsim/ethtool.c-97-{
drivers/net/netdevsim/ethtool.c:98: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ethtool.c-99-
--
drivers/net/netdevsim/ethtool.c=105=nsim_wake_queues(struct net_device *dev)
drivers/net/netdevsim/ethtool.c-106-{
drivers/net/netdevsim/ethtool.c:107: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ethtool.c:108: struct netdevsim *peer;
drivers/net/netdevsim/ethtool.c-109-
--
drivers/net/netdevsim/ethtool.c=121=nsim_set_channels(struct net_device *dev, struct ethtool_channels *ch)
drivers/net/netdevsim/ethtool.c-122-{
drivers/net/netdevsim/ethtool.c:123: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ethtool.c-124- int err;
--
drivers/net/netdevsim/ethtool.c=141=nsim_get_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
drivers/net/netdevsim/ethtool.c-142-{
drivers/net/netdevsim/ethtool.c:143: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ethtool.c-144-
--
drivers/net/netdevsim/ethtool.c=152=nsim_set_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
drivers/net/netdevsim/ethtool.c-153-{
drivers/net/netdevsim/ethtool.c:154: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ethtool.c-155- u32 fec;
--
drivers/net/netdevsim/ethtool.c-167-
drivers/net/netdevsim/ethtool.c:168:static const struct ethtool_fec_hist_range netdevsim_fec_ranges[] = {
drivers/net/netdevsim/ethtool.c-169- { 0, 0},
--
drivers/net/netdevsim/ethtool.c=176=nsim_get_fec_stats(struct net_device *dev, struct ethtool_fec_stats *fec_stats,
--
drivers/net/netdevsim/ethtool.c-180-
drivers/net/netdevsim/ethtool.c:181: hist->ranges = netdevsim_fec_ranges;
drivers/net/netdevsim/ethtool.c-182-
--
drivers/net/netdevsim/ethtool.c=198=static int nsim_get_ts_info(struct net_device *dev,
--
drivers/net/netdevsim/ethtool.c-200-{
drivers/net/netdevsim/ethtool.c:201: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ethtool.c-202-
--
drivers/net/netdevsim/ethtool.c=208=static const struct ethtool_ops nsim_ethtool_ops = {
--
drivers/net/netdevsim/ethtool.c-227-
drivers/net/netdevsim/ethtool.c:228:static void nsim_ethtool_ring_init(struct netdevsim *ns)
drivers/net/netdevsim/ethtool.c-229-{
--
drivers/net/netdevsim/ethtool.c-237-
drivers/net/netdevsim/ethtool.c:238:void nsim_ethtool_init(struct netdevsim *ns)
drivers/net/netdevsim/ethtool.c-239-{
--
drivers/net/netdevsim/ethtool.c-276-
drivers/net/netdevsim/ethtool.c:277:void nsim_ethtool_fini(struct netdevsim *ns)
drivers/net/netdevsim/ethtool.c-278-{
--
drivers/net/netdevsim/fib.c-32-
drivers/net/netdevsim/fib.c:33:#include "netdevsim.h"
drivers/net/netdevsim/fib.c-34-
--
drivers/net/netdevsim/fib.c=977=static int nsim_fib_event_schedule_work(struct nsim_fib_data *data,
--
drivers/net/netdevsim/fib.c-984- if (info->family != AF_INET && info->family != AF_INET6)
drivers/net/netdevsim/fib.c:985: /* netdevsim does not support 'RTNL_FAMILY_IP6MR' and
drivers/net/netdevsim/fib.c-986- * 'RTNL_FAMILY_IPMR' and should ignore them.
--
drivers/net/netdevsim/health.c-8-
drivers/net/netdevsim/health.c:9:#include "netdevsim.h"
drivers/net/netdevsim/health.c-10-
--
drivers/net/netdevsim/hwstats.c-4-
drivers/net/netdevsim/hwstats.c:5:#include "netdevsim.h"
drivers/net/netdevsim/hwstats.c-6-
--
drivers/net/netdevsim/ipsec.c-7-
drivers/net/netdevsim/ipsec.c:8:#include "netdevsim.h"
drivers/net/netdevsim/ipsec.c-9-
--
drivers/net/netdevsim/ipsec.c=12=static ssize_t nsim_dbg_netdev_ops_read(struct file *filp,
--
drivers/net/netdevsim/ipsec.c-15-{
drivers/net/netdevsim/ipsec.c:16: struct netdevsim *ns = filp->private_data;
drivers/net/netdevsim/ipsec.c-17- struct nsim_ipsec *ipsec = &ns->ipsec;
--
drivers/net/netdevsim/ipsec.c=132=static int nsim_ipsec_add_sa(struct net_device *dev,
--
drivers/net/netdevsim/ipsec.c-136- struct nsim_ipsec *ipsec;
drivers/net/netdevsim/ipsec.c:137: struct netdevsim *ns;
drivers/net/netdevsim/ipsec.c-138- struct nsim_sa sa;
--
drivers/net/netdevsim/ipsec.c=202=static void nsim_ipsec_del_sa(struct net_device *dev, struct xfrm_state *xs)
drivers/net/netdevsim/ipsec.c-203-{
drivers/net/netdevsim/ipsec.c:204: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/ipsec.c-205- struct nsim_ipsec *ipsec = &ns->ipsec;
--
drivers/net/netdevsim/ipsec.c=219=static const struct xfrmdev_ops nsim_xfrmdev_ops = {
--
drivers/net/netdevsim/ipsec.c-223-
drivers/net/netdevsim/ipsec.c:224:bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
drivers/net/netdevsim/ipsec.c-225-{
--
drivers/net/netdevsim/ipsec.c-270-
drivers/net/netdevsim/ipsec.c:271:void nsim_ipsec_init(struct netdevsim *ns)
drivers/net/netdevsim/ipsec.c-272-{
--
drivers/net/netdevsim/ipsec.c-287-
drivers/net/netdevsim/ipsec.c:288:void nsim_ipsec_teardown(struct netdevsim *ns)
drivers/net/netdevsim/ipsec.c-289-{
--
drivers/net/netdevsim/macsec.c-3-#include <net/macsec.h>
drivers/net/netdevsim/macsec.c:4:#include "netdevsim.h"
drivers/net/netdevsim/macsec.c-5-
drivers/net/netdevsim/macsec.c:6:static int nsim_macsec_find_secy(struct netdevsim *ns, sci_t sci)
drivers/net/netdevsim/macsec.c-7-{
--
drivers/net/netdevsim/macsec.c=30=static int nsim_macsec_add_secy(struct macsec_context *ctx)
drivers/net/netdevsim/macsec.c-31-{
drivers/net/netdevsim/macsec.c:32: struct netdevsim *ns = netdev_priv(ctx->netdev);
drivers/net/netdevsim/macsec.c-33- int idx;
--
drivers/net/netdevsim/macsec.c=59=static int nsim_macsec_upd_secy(struct macsec_context *ctx)
drivers/net/netdevsim/macsec.c-60-{
drivers/net/netdevsim/macsec.c:61: struct netdevsim *ns = netdev_priv(ctx->netdev);
drivers/net/netdevsim/macsec.c-62- int idx;
--
drivers/net/netdevsim/macsec.c=77=static int nsim_macsec_del_secy(struct macsec_context *ctx)
drivers/net/netdevsim/macsec.c-78-{
drivers/net/netdevsim/macsec.c:79: struct netdevsim *ns = netdev_priv(ctx->netdev);
drivers/net/netdevsim/macsec.c-80- int idx;
--
drivers/net/netdevsim/macsec.c=99=static int nsim_macsec_add_rxsc(struct macsec_context *ctx)
drivers/net/netdevsim/macsec.c-100-{
drivers/net/netdevsim/macsec.c:101: struct netdevsim *ns = netdev_priv(ctx->netdev);
drivers/net/netdevsim/macsec.c-102- struct nsim_secy *secy;
--
drivers/net/netdevsim/macsec.c=134=static int nsim_macsec_upd_rxsc(struct macsec_context *ctx)
drivers/net/netdevsim/macsec.c-135-{
drivers/net/netdevsim/macsec.c:136: struct netdevsim *ns = netdev_priv(ctx->netdev);
drivers/net/netdevsim/macsec.c-137- struct nsim_secy *secy;
--
drivers/net/netdevsim/macsec.c=161=static int nsim_macsec_del_rxsc(struct macsec_context *ctx)
drivers/net/netdevsim/macsec.c-162-{
drivers/net/netdevsim/macsec.c:163: struct netdevsim *ns = netdev_priv(ctx->netdev);
drivers/net/netdevsim/macsec.c-164- struct nsim_secy *secy;
--
drivers/net/netdevsim/macsec.c=192=static int nsim_macsec_add_rxsa(struct macsec_context *ctx)
drivers/net/netdevsim/macsec.c-193-{
drivers/net/netdevsim/macsec.c:194: struct netdevsim *ns = netdev_priv(ctx->netdev);
drivers/net/netdevsim/macsec.c-195- struct nsim_secy *secy;
--
drivers/net/netdevsim/macsec.c=219=static int nsim_macsec_upd_rxsa(struct macsec_context *ctx)
drivers/net/netdevsim/macsec.c-220-{
drivers/net/netdevsim/macsec.c:221: struct netdevsim *ns = netdev_priv(ctx->netdev);
drivers/net/netdevsim/macsec.c-222- struct nsim_secy *secy;
--
drivers/net/netdevsim/macsec.c=246=static int nsim_macsec_del_rxsa(struct macsec_context *ctx)
drivers/net/netdevsim/macsec.c-247-{
drivers/net/netdevsim/macsec.c:248: struct netdevsim *ns = netdev_priv(ctx->netdev);
drivers/net/netdevsim/macsec.c-249- struct nsim_secy *secy;
--
drivers/net/netdevsim/macsec.c=273=static int nsim_macsec_add_txsa(struct macsec_context *ctx)
drivers/net/netdevsim/macsec.c-274-{
drivers/net/netdevsim/macsec.c:275: struct netdevsim *ns = netdev_priv(ctx->netdev);
drivers/net/netdevsim/macsec.c-276- int idx;
--
drivers/net/netdevsim/macsec.c=291=static int nsim_macsec_upd_txsa(struct macsec_context *ctx)
drivers/net/netdevsim/macsec.c-292-{
drivers/net/netdevsim/macsec.c:293: struct netdevsim *ns = netdev_priv(ctx->netdev);
drivers/net/netdevsim/macsec.c-294- int idx;
--
drivers/net/netdevsim/macsec.c=309=static int nsim_macsec_del_txsa(struct macsec_context *ctx)
drivers/net/netdevsim/macsec.c-310-{
drivers/net/netdevsim/macsec.c:311: struct netdevsim *ns = netdev_priv(ctx->netdev);
drivers/net/netdevsim/macsec.c-312- int idx;
--
drivers/net/netdevsim/macsec.c=327=static const struct macsec_ops nsim_macsec_ops = {
--
drivers/net/netdevsim/macsec.c-341-
drivers/net/netdevsim/macsec.c:342:void nsim_macsec_init(struct netdevsim *ns)
drivers/net/netdevsim/macsec.c-343-{
--
drivers/net/netdevsim/macsec.c-348-
drivers/net/netdevsim/macsec.c:349:void nsim_macsec_teardown(struct netdevsim *ns)
drivers/net/netdevsim/macsec.c-350-{
--
drivers/net/netdevsim/netdev.c-33-
drivers/net/netdevsim/netdev.c:34:#include "netdevsim.h"
drivers/net/netdevsim/netdev.c-35-
--
drivers/net/netdevsim/netdev.c=40=static void nsim_start_peer_tx_queue(struct net_device *dev, struct nsim_rq *rq)
drivers/net/netdevsim/netdev.c-41-{
drivers/net/netdevsim/netdev.c:42: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c-43- struct net_device *peer_dev;
drivers/net/netdevsim/netdev.c:44: struct netdevsim *peer_ns;
drivers/net/netdevsim/netdev.c-45- struct netdev_queue *txq;
--
drivers/net/netdevsim/netdev.c=123=static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
drivers/net/netdevsim/netdev.c-124-{
drivers/net/netdevsim/netdev.c:125: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c-126- struct skb_ext *psp_ext = NULL;
--
drivers/net/netdevsim/netdev.c-128- unsigned int len = skb->len;
drivers/net/netdevsim/netdev.c:129: struct netdevsim *peer_ns;
drivers/net/netdevsim/netdev.c-130- struct netdev_config *cfg;
--
drivers/net/netdevsim/netdev.c=195=static int nsim_change_mtu(struct net_device *dev, int new_mtu)
drivers/net/netdevsim/netdev.c-196-{
drivers/net/netdevsim/netdev.c:197: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c-198-
--
drivers/net/netdevsim/netdev.c=208=static int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac)
drivers/net/netdevsim/netdev.c-209-{
drivers/net/netdevsim/netdev.c:210: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c-211- struct nsim_dev *nsim_dev = ns->nsim_dev;
--
drivers/net/netdevsim/netdev.c=221=static int nsim_set_vf_vlan(struct net_device *dev, int vf,
--
drivers/net/netdevsim/netdev.c-223-{
drivers/net/netdevsim/netdev.c:224: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c-225- struct nsim_dev *nsim_dev = ns->nsim_dev;
--
drivers/net/netdevsim/netdev.c=237=static int nsim_set_vf_rate(struct net_device *dev, int vf, int min, int max)
drivers/net/netdevsim/netdev.c-238-{
drivers/net/netdevsim/netdev.c:239: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c-240- struct nsim_dev *nsim_dev = ns->nsim_dev;
--
drivers/net/netdevsim/netdev.c=256=static int nsim_set_vf_spoofchk(struct net_device *dev, int vf, bool val)
drivers/net/netdevsim/netdev.c-257-{
drivers/net/netdevsim/netdev.c:258: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c-259- struct nsim_dev *nsim_dev = ns->nsim_dev;
--
drivers/net/netdevsim/netdev.c=268=static int nsim_set_vf_rss_query_en(struct net_device *dev, int vf, bool val)
drivers/net/netdevsim/netdev.c-269-{
drivers/net/netdevsim/netdev.c:270: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c-271- struct nsim_dev *nsim_dev = ns->nsim_dev;
--
drivers/net/netdevsim/netdev.c=280=static int nsim_set_vf_trust(struct net_device *dev, int vf, bool val)
drivers/net/netdevsim/netdev.c-281-{
drivers/net/netdevsim/netdev.c:282: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c-283- struct nsim_dev *nsim_dev = ns->nsim_dev;
--
drivers/net/netdevsim/netdev.c=293=nsim_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivi)
drivers/net/netdevsim/netdev.c-294-{
drivers/net/netdevsim/netdev.c:295: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c-296- struct nsim_dev *nsim_dev = ns->nsim_dev;
--
drivers/net/netdevsim/netdev.c=316=static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state)
drivers/net/netdevsim/netdev.c-317-{
drivers/net/netdevsim/netdev.c:318: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c-319- struct nsim_dev *nsim_dev = ns->nsim_dev;
--
drivers/net/netdevsim/netdev.c=339=nsim_set_features(struct net_device *dev, netdev_features_t features)
drivers/net/netdevsim/netdev.c-340-{
drivers/net/netdevsim/netdev.c:341: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c-342-
--
drivers/net/netdevsim/netdev.c=349=static int nsim_get_iflink(const struct net_device *dev)
drivers/net/netdevsim/netdev.c-350-{
drivers/net/netdevsim/netdev.c:351: struct netdevsim *nsim, *peer;
drivers/net/netdevsim/netdev.c-352- int iflink;
--
drivers/net/netdevsim/netdev.c=365=static int nsim_rcv(struct nsim_rq *rq, int budget)
--
drivers/net/netdevsim/netdev.c-368- struct bpf_prog *xdp_prog;
drivers/net/netdevsim/netdev.c:369: struct netdevsim *ns;
drivers/net/netdevsim/netdev.c-370- struct sk_buff *skb;
--
drivers/net/netdevsim/netdev.c=417=static int nsim_create_page_pool(struct page_pool **p, struct napi_struct *napi)
--
drivers/net/netdevsim/netdev.c-437-
drivers/net/netdevsim/netdev.c:438:static int nsim_init_napi(struct netdevsim *ns)
drivers/net/netdevsim/netdev.c-439-{
--
drivers/net/netdevsim/netdev.c=482=static void nsim_rq_timer_init(struct nsim_rq *rq)
--
drivers/net/netdevsim/netdev.c-487-
drivers/net/netdevsim/netdev.c:488:static void nsim_enable_napi(struct netdevsim *ns)
drivers/net/netdevsim/netdev.c-489-{
--
drivers/net/netdevsim/netdev.c=501=static int nsim_open(struct net_device *dev)
drivers/net/netdevsim/netdev.c-502-{
drivers/net/netdevsim/netdev.c:503: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c:504: struct netdevsim *peer;
drivers/net/netdevsim/netdev.c-505- int err;
--
drivers/net/netdevsim/netdev.c-523-
drivers/net/netdevsim/netdev.c:524:static void nsim_del_napi(struct netdevsim *ns)
drivers/net/netdevsim/netdev.c-525-{
--
drivers/net/netdevsim/netdev.c=543=static int nsim_stop(struct net_device *dev)
drivers/net/netdevsim/netdev.c-544-{
drivers/net/netdevsim/netdev.c:545: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c:546: struct netdevsim *peer;
drivers/net/netdevsim/netdev.c-547-
--
drivers/net/netdevsim/netdev.c=560=static int nsim_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
drivers/net/netdevsim/netdev.c-561-{
drivers/net/netdevsim/netdev.c:562: struct netdevsim *ns = netdev_priv(dev);
drivers/net/netdevsim/netdev.c-563-
--
drivers/net/netdevsim/netdev.c=575=static int nsim_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
drivers/net/netdevsim/netdev.c-576-{
]
|
| 36/2 |
2026/07/30 00:08 |
llm |
expert |
0m
Model:
Tokens:
input: 48006
output: 23
thoughts: 24
Thoughts: Here's my take on the thought process, as if it were my own:
**Investigating `netdevsim` Device Creation**
Okay, time to dive into this. My first thought is to zero in on the `netdevsim` creation process. Since I'm thinking about how the simulated network devices get instantiated, the logical place to start is the `drivers/net/netdevsim/bus.c` file. That's the likely location for the core registration and initialization logic related to the virtual bus and the devices attached to it. I need to understand how these simulated devices are constructed, registered, and integrated with the kernel's network stack within that context. From there I'll be able to work backwards or forwards to whatever problems are indicated.
|
| 37/2 |
2026/07/30 00:09 |
tool |
codesearch-definition-source |
0m
Args: map[Name:new_device_store]
Results: map[SourceCode: 158: static ssize_t
159: new_device_store(const struct bus_type *bus, const char *buf, size_t count)
160: {
161: unsigned int id, port_count, num_queues;
162: struct nsim_bus_dev *nsim_bus_dev;
163: int err;
164:
165: err = sscanf(buf, "%u %u %u", &id, &port_count, &num_queues);
166: switch (err) {
167: case 1:
168: port_count = 1;
169: fallthrough;
170: case 2:
171: num_queues = 1;
172: fallthrough;
173: case 3:
174: if (id > INT_MAX) {
175: pr_err("Value of \"id\" is too big.\n");
176: return -EINVAL;
177: }
178: break;
179: default:
180: pr_err("Format for adding new device is \"id port_count num_queues\" (uint uint uint).\n");
181: return -EINVAL;
182: }
183:
184: mutex_lock(&nsim_bus_dev_list_lock);
185: /* Prevent to use resource before initialization. */
186: if (!smp_load_acquire(&nsim_bus_enable)) {
187: err = -EBUSY;
188: goto err;
189: }
190:
191: nsim_bus_dev = nsim_bus_dev_new(id, port_count, num_queues);
192: if (IS_ERR(nsim_bus_dev)) {
193: err = PTR_ERR(nsim_bus_dev);
194: goto err;
195: }
196:
197: refcount_inc(&nsim_bus_devs);
198: /* Allow using nsim_bus_dev */
199: smp_store_release(&nsim_bus_dev->init, true);
200:
201: list_add_tail(&nsim_bus_dev->list, &nsim_bus_dev_list);
202: mutex_unlock(&nsim_bus_dev_list_lock);
203:
204: return count;
205: err:
206: mutex_unlock(&nsim_bus_dev_list_lock);
207: return err;
208: }
SourceFile:drivers/net/netdevsim/bus.c]
|
| 38/2 |
2026/07/30 00:09 |
llm |
expert |
0m
Model:
Tokens:
input: 49013
output: 36
thoughts: 617
Thoughts: **Investigating Netdevsim Device Creation**
Okay, so I'm looking at `new_device_store`, which is the function that creates `netdevsim` devices, exposed at `/sys/bus/netdevsim/new_device`. Right, sysfs attributes are generally root-owned and inaccessible within user namespaces. So, a regular user, without root privileges, is blocked from creating these devices through the typical sysfs interface.
My next thought is, can they leverage a netlink interface? I'm pretty sure `netdevsim` doesn't have a netlink interface for device creation; it's a bus driver, and creation is handled through sysfs. But, hold on... what about other virtual devices? Could any of *them* use devlink? Let's quickly run through the usual suspects: `veth`, `macsec`, `dummy`, `wireguard`, `batman-adv`, `team`, `bonding`, `bridge`, `vlan`, `macvlan`, `ipvlan`, `vxlan`, `geneve`, `bareudp`, `gtp`, `ipsec`, `xfrm`, `tun`, `tap`, `vcan`, `vxcan`, `nlmon`, `vrf`, `mac80211_hwsim`, `wwan`...nope. None of those support devlink. Wait, it seems that `netdevsim` is the *only* virtual device that supports devlink. And it is only creatable by root, in the initial namespace, via sysfs.
But then I remember syzkaller. How is it creating `netdevsim` devices? It runs as an unprivileged user in a user namespace. It could have access to `/sys/bus/netdevsim/new_device` if not properly isolated, or it uses another mechanism. Then it hits me, syzkaller utilizes `syz_genetlink_get_family_id` and then netlink messages. So my next question: Can syzkaller create a `netdevsim` device via netlink? It's time to check if there is a netlink interface to create `netdevsim` devices.
|
| 39/2 |
2026/07/30 00:09 |
tool |
grepper |
0m
Args: map[Expression:nsim_bus_dev_new PathPrefix:drivers/net/netdevsim/]
Results: map[Output:drivers/net/netdevsim/bus.c=65=new_port_store(struct device *dev, struct device_attribute *attr,
--
drivers/net/netdevsim/bus.c-100-
drivers/net/netdevsim/bus.c:101:static struct device_attribute nsim_bus_dev_new_port_attr = __ATTR_WO(new_port);
drivers/net/netdevsim/bus.c-102-
--
drivers/net/netdevsim/bus.c=124=static struct attribute *nsim_bus_dev_attrs[] = {
drivers/net/netdevsim/bus.c-125- &nsim_bus_dev_numvfs_attr.attr,
drivers/net/netdevsim/bus.c:126: &nsim_bus_dev_new_port_attr.attr,
drivers/net/netdevsim/bus.c-127- &nsim_bus_dev_del_port_attr.attr,
--
drivers/net/netdevsim/bus.c=155=static struct nsim_bus_dev *
drivers/net/netdevsim/bus.c:156:nsim_bus_dev_new(unsigned int id, unsigned int port_count, unsigned int num_queues);
drivers/net/netdevsim/bus.c-157-
--
drivers/net/netdevsim/bus.c=159=new_device_store(const struct bus_type *bus, const char *buf, size_t count)
--
drivers/net/netdevsim/bus.c-190-
drivers/net/netdevsim/bus.c:191: nsim_bus_dev = nsim_bus_dev_new(id, port_count, num_queues);
drivers/net/netdevsim/bus.c-192- if (IS_ERR(nsim_bus_dev)) {
--
drivers/net/netdevsim/bus.c=448=static struct nsim_bus_dev *
drivers/net/netdevsim/bus.c:449:nsim_bus_dev_new(unsigned int id, unsigned int port_count, unsigned int num_queues)
drivers/net/netdevsim/bus.c-450-{
]
|
| 40/2 |
2026/07/30 00:09 |
llm |
expert |
0m
Model:
Tokens:
input: 50705
output: 26
thoughts: 463
Thoughts: **Unprivileged Access to the Devlink Flash Update Bug - A Deep Dive**
Okay, let's break this down. My initial thought was that `nsim_bus_dev_new` is only called from `new_device_store`, which means netdevsim devices are only created via sysfs. I know sysfs is mountable in user namespaces, but the `/sys/bus` directory is typically not writable by unprivileged users, even in a user namespace. Then I remembered something important. If sysfs is mounted in the *initial* namespace, the path `/sys/bus/netdevsim/new_device` is owned by root:root with a mode of 0200. This means an unprivileged user cannot write to it, and therefore they can't create a netdevsim device. So, the bug isn't exploitable there.
My next line of thought: could an unprivileged user trigger this on a *physical* device? To do that, assuming the device supports devlink flash update, they'd need `CAP_NET_ADMIN` in the namespace where the device resides. Physical devices initially reside in the initial network namespace. Crucially, an unprivileged user cannot move a physical device to their network namespace because that requires `CAP_NET_ADMIN` in the initial namespace. Thus, they cannot trigger the bug on a physical device.
So, it's starting to look like unprivileged processes and user namespaces are protected. But what about Netlink? I'm thinking, could this bug be triggered via netlink `DEVLINK_CMD_FLASH_UPDATE`? `devlink_nl_flash_update_doit` requires `GENL_ADMIN_PERM`, which in turn checks for `CAP_NET_ADMIN` in the *namespace of the netlink socket*. Now, here's where it gets interesting. If an unprivileged user can create a user namespace and a network namespace, they'd indeed have `CAP_NET_ADMIN` in that new namespace. They *could* open a generic netlink socket and try to send `DEVLINK_CMD_FLASH_UPDATE`.
However... they'd need to specify a devlink device. Devlink devices are identified by bus name and device name. If there are *no* devlink devices in their *network* namespace, the command would fail to find the device, right? Wait... it just hit me. Devlink devices are *not* associated with network namespaces! They're global, or associated with the devlink instance itself. This changes everything. Let's dig into `devlink_get_from_attrs`. I need to confirm the device association.
|
| 41/2 |
2026/07/30 00:09 |
tool |
codesearch-definition-source |
0m
Error:
Args: map[Name:devlink_get_from_attrs]
Results: map[SourceCode: SourceFile:]
|
| 42/2 |
2026/07/30 00:09 |
llm |
expert |
0m
Model:
Tokens:
input: 51778
output: 29
thoughts: 24
Thoughts: Okay, here's my attempt at summarizing the thought process, tailored for an expert audience, and written in the first person:
**Diving into `devlink_nl_flash_update_doit` - Instance Retrieval**
Alright, let's dissect this. My immediate thought is, I need to understand how `devlink_nl_flash_update_doit` actually *gets* the `devlink` instance. This is foundational; without that instance, the update function is dead in the water. I need to trace the code path back from this function and see how the relevant `devlink` is identified and passed in. Is it based on a device name, a unique ID, or perhaps a file descriptor associated with the device? Is it cached somewhere, or looked up dynamically? I'm anticipating there could be some interesting logic around resource management or locking if multiple updates could potentially target the same `devlink` at the same time. I'll be looking for potential race conditions or synchronization primitives. My intuition leans towards the need to be cautious about concurrent access, so Iβm expecting some form of protection to prevent corruption. Let's see how they've handled that. Knowing the details of this retrieval process will give me a solid foundation for evaluating the rest of the function's functionality and potential weaknesses.
|
| 43/2 |
2026/07/30 00:09 |
tool |
codesearch-definition-source |
0m
Args: map[Name:devlink_nl_flash_update_doit]
Results: map[SourceCode:1133: int devlink_nl_flash_update_doit(struct sk_buff *skb, struct genl_info *info)
1134: {
1135: struct nlattr *nla_overwrite_mask, *nla_file_name;
1136: struct devlink_flash_update_params params = {};
1137: struct devlink *devlink = info->user_ptr[0];
1138: const char *file_name;
1139: u32 supported_params;
1140: int ret;
1141:
1142: if (!devlink->ops->flash_update)
1143: return -EOPNOTSUPP;
1144:
1145: if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME))
1146: return -EINVAL;
1147:
1148: ret = devlink_flash_component_get(devlink,
1149: info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT],
1150: ¶ms.component, info->extack);
1151: if (ret)
1152: return ret;
1153:
1154: supported_params = devlink->ops->supported_flash_update_params;
1155:
1156: nla_overwrite_mask = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK];
1157: if (nla_overwrite_mask) {
1158: struct nla_bitfield32 sections;
1159:
1160: if (!(supported_params & DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK)) {
1161: NL_SET_ERR_MSG_ATTR(info->extack, nla_overwrite_mask,
1162: "overwrite settings are not supported by this device");
1163: return -EOPNOTSUPP;
1164: }
1165: sections = nla_get_bitfield32(nla_overwrite_mask);
1166: params.overwrite_mask = sections.value & sections.selector;
1167: }
1168:
1169: nla_file_name = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME];
1170: file_name = nla_data(nla_file_name);
1171: ret = request_firmware(¶ms.fw, file_name, devlink->dev);
1172: if (ret) {
1173: NL_SET_ERR_MSG_ATTR(info->extack, nla_file_name,
1174: "failed to locate the requested firmware file");
1175: return ret;
1176: }
1177:
1178: devlink_flash_update_begin_notify(devlink);
1179: ret = devlink->ops->flash_update(devlink, ¶ms, info->extack);
1180: devlink_flash_update_end_notify(devlink);
1181:
1182: release_firmware(params.fw);
1183:
1184: return ret;
1185: }
SourceFile:net/devlink/dev.c]
|
| 44/2 |
2026/07/30 00:09 |
llm |
expert |
0m
Model:
Tokens:
input: 53023
output: 27
thoughts: 47
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:
**Decoding This Devlink Pointer**
Alright, I'm digging into this code and I see we're grabbing a `devlink` pointer directly from `info->user_ptr[0]`. That's the starting point, but the immediate question bubbling up is: *how* did that particular element get populated? `info->user_ptr` is often a dumping ground for various contextual pointers, so I need to trace back the initialization to be certain of its contents.
My gut reaction is that this information must have been set up beforehand, so let's start by scrutinizing `devlink_nl_pre_doit`. I'm going to look for any calls or assignments related to `info->user_ptr[0]` within that function. I expect it to either be explicitly set there, or possibly passed in via arguments and then assigned. Understanding the control flow around that function is crucial here, because my expectation is that it might be where a new `devlink` is looked up, found, validated, and then the pointer set to be available to whoever calls us here.
|
| 45/2 |
2026/07/30 00:09 |
tool |
codesearch-definition-source |
0m
Args: map[Name:devlink_nl_pre_doit]
Results: map[SourceCode: 276: int devlink_nl_pre_doit(const struct genl_split_ops *ops,
277: struct sk_buff *skb, struct genl_info *info)
278: {
279: return __devlink_nl_pre_doit(skb, info, 0);
280: }
SourceFile:net/devlink/netlink.c]
|
| 46/2 |
2026/07/30 00:09 |
llm |
expert |
0m
Model:
Tokens:
input: 53478
output: 28
thoughts: 16
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and presented as if it were my own internal monologue:
**Diving into the `__devlink_nl_pre_doit` Function**
Alright, time to get to the core. The issue likely lies somewhere in the Netlink pre-processing for Devlink operations. Let's start with `__devlink_nl_pre_doit`. I'm immediately interested in what this function does *before* the main Netlink handler is invoked for Devlink messages. I'm expecting this to handle things like initial validation of the Netlink message, potentially some resource checking related to device state, maybe even some basic permission checks or sanity checks on the attributes. Anything to avoid needlessly processing a malformed message or one that targets an invalid device.
I'll be looking to see if there are any obvious bottlenecks or potential race conditions here that could manifest the observed issues. I'm thinking about aspects such as mutex contention, the handling of different Devlink message types within this pre-processing stage. Given the context, this function is potentially the gateway that leads into the specific Devlink action and I will want to trace the flow. This could be where the root of the problem might actually lie.
|
| 47/2 |
2026/07/30 00:09 |
tool |
codesearch-definition-source |
0m
Args: map[Name:__devlink_nl_pre_doit]
Results: map[SourceCode: 242: static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info,
243: u8 flags)
244: {
245: bool dev_lock = flags & DEVLINK_NL_FLAG_NEED_DEV_LOCK;
246: struct devlink_port *devlink_port;
247: struct devlink *devlink;
248: int err;
249:
250: devlink = devlink_get_from_attrs_lock(genl_info_net(info), info->attrs,
251: dev_lock);
252: if (IS_ERR(devlink))
253: return PTR_ERR(devlink);
254:
255: info->user_ptr[0] = devlink;
256: if (flags & DEVLINK_NL_FLAG_NEED_PORT) {
257: devlink_port = devlink_port_get_from_info(devlink, info);
258: if (IS_ERR(devlink_port)) {
259: err = PTR_ERR(devlink_port);
260: goto unlock;
261: }
262: info->user_ptr[1] = devlink_port;
263: } else if (flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
264: devlink_port = devlink_port_get_from_info(devlink, info);
265: if (!IS_ERR(devlink_port))
266: info->user_ptr[1] = devlink_port;
267: }
268: return 0;
269:
270: unlock:
271: devl_dev_unlock(devlink, dev_lock);
272: devlink_put(devlink);
273: return err;
274: }
SourceFile:net/devlink/netlink.c]
|
| 48/2 |
2026/07/30 00:09 |
llm |
expert |
0m
Model:
Tokens:
input: 54368
output: 28
thoughts: 16
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Analyzing `devlink_get_from_attrs_lock`**
Okay, let's dive into this `devlink_get_from_attrs_lock` function. My initial thought process here is to quickly assess its role in the larger device linking context. Given the name, it's pretty clear this is about retrieving a `devlink` structure, probably based on some attributes, and crucially, it likely involves some form of locking. I need to understand the locking semantics.
Specifically, I'm thinking:
* **Attribute Handling:** What kind of attributes is it using as input? Is it a single attribute, or is it dealing with a set of them? Are there any ordering dependencies? Knowing the input attributes will allow to determine how the devlink is being searched, and if there are any collisions that need to be accounted for.
* **Locking Scope:** What's being locked? Is it a global lock, a per-devlink lock, or something more granular? I need to understand how the lock is protecting the `devlink` structure and any associated data or resources during the retrieval process.
* **Contention:** What's the potential for contention? If the lock is too coarse-grained, we might be seeing performance bottlenecks. A more fine-grained lock could have a performance gain, but might be difficult to implement correctly.
* **Error Handling:** What happens if the `devlink` isn't found? How are errors handled? Is it returning an error code, or are exceptions thrown? I'd expect proper error handling to be incorporated as this is likely to be a core lookup function.
Ultimately, I need to figure out:
* Is this locking strategy appropriate for the expected load and access patterns?
* Are there any potential race conditions that need further scrutiny?
* How can this retrieval function be optimized, especially in high-concurrency scenarios?
I'll probably start by looking at the function's definition, any related comments, and then trace its usage in the code to get a comprehensive understanding. Knowing the exact attributes and locking mechanism will enable my evaluation.
|
| 49/2 |
2026/07/30 00:09 |
tool |
codesearch-definition-source |
0m
Args: map[Name:devlink_get_from_attrs_lock]
Results: map[SourceCode: 189: struct devlink *
190: devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs,
191: bool dev_lock)
192: {
193: struct devlink *devlink;
194: unsigned long index;
195: char *busname;
196: char *devname;
197:
198: if (attrs[DEVLINK_ATTR_INDEX]) {
199: if (attrs[DEVLINK_ATTR_BUS_NAME] ||
200: attrs[DEVLINK_ATTR_DEV_NAME])
201: return ERR_PTR(-EINVAL);
202: index = nla_get_u32(attrs[DEVLINK_ATTR_INDEX]);
203: devlink = devlinks_xa_lookup_get(net, index);
204: if (!devlink)
205: return ERR_PTR(-ENODEV);
206: goto found;
207: }
208:
209: if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
210: return ERR_PTR(-EINVAL);
211:
212: busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
213: devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
214:
215: if (!strcmp(busname, DEVLINK_INDEX_BUS_NAME)) {
216: if (kstrtoul(devname, 10, &index))
217: return ERR_PTR(-ENODEV);
218: devlink = devlinks_xa_lookup_get(net, index);
219: if (!devlink)
220: return ERR_PTR(-ENODEV);
221: goto found;
222: }
223:
224: devlinks_xa_for_each_registered_get(net, index, devlink) {
225: if (strcmp(devlink_bus_name(devlink), busname) == 0 &&
226: strcmp(devlink_dev_name(devlink), devname) == 0)
227: goto found;
228: devlink_put(devlink);
229: }
230:
231: return ERR_PTR(-ENODEV);
232:
233: found:
234: devl_dev_lock(devlink, dev_lock);
235: if (devl_is_registered(devlink))
236: return devlink;
237: devl_dev_unlock(devlink, dev_lock);
238: devlink_put(devlink);
239: return ERR_PTR(-ENODEV);
240: }
SourceFile:net/devlink/netlink.c]
|
| 50/2 |
2026/07/30 00:09 |
llm |
expert |
0m
Model:
Tokens:
input: 55724
output: 26
thoughts: 336
Thoughts: **Devlink, Network Namespaces, and Flash Updates: A Recap**
Okay, so `devlinks_xa_lookup_get(net, index)` is the function that finds a devlink instance, and it uses the network namespace `net`. So, devlink instances *are* linked to network namespaces, that makes sense. If an unprivileged user spins up a new network namespace, there are *no* devlink instances in it initially, obviously. And, since they don't have sysfs access, they can't create a `netdevsim` device there either.
But hold on... can they *move* an existing devlink instance into their new namespace? Thinking about it, moving a devlink instance needs `CAP_NET_ADMIN` in the original namespace or the namespace where the devlink instance is currently residing. So, an unprivileged user can't do that. That means an unprivileged user is completely locked out of accessing *any* devlink instances, which in turn means they can't trigger `DEVLINK_CMD_FLASH_UPDATE`.
Okay, what about the `dev_ethtool` situation? That's an ioctl on a socket, right? And, for `ETHTOOL_FLASHDEV`, it needs `ns_capable(net->user_ns, CAP_NET_ADMIN)`. Hey, they *do* have `CAP_NET_ADMIN` in their new network namespace. So... they *could* call `dev_ethtool` with `ETHTOOL_FLASHDEV` on a network device that resides in their namespace. But what network devices are there in a brand new namespace? The loopback, `lo`. Okay, *does* `lo` support `ETHTOOL_FLASHDEV`? Time to check `loopback_ethtool_ops`.
|
| 51/2 |
2026/07/30 00:09 |
tool |
codesearch-definition-source |
0m
Args: map[Name:loopback_ethtool_ops]
Results: map[SourceCode: 138: static const struct ethtool_ops loopback_ethtool_ops = {
139: .get_link = always_on,
140: .get_ts_info = ethtool_op_get_ts_info,
141: };
SourceFile:drivers/net/loopback.c]
|
| 52/2 |
2026/07/30 00:09 |
llm |
expert |
0m
Model:
Tokens:
input: 56581
output: 25
thoughts: 51
Thoughts: Okay, here's my interpretation of those thoughts, tailored for an expert audience:
**Analyzing Flash Device Support**
Hmm, no, this code path *definitely* doesn't seem to have direct support for a `flash_device` operation. Hold on a second, though... I need to double-check my understanding of how `dev_ethtool` functions. Doesn't that routine indirectly call `dev->ethtool_ops->flash_device`? I'm pretty sure it does. Okay, better to be certain. Let me go back and thoroughly examine how `ethtool_flash_device` is implemented and used within this context. That's the key routine to zero in on.
|
| 53/2 |
2026/07/30 00:09 |
tool |
codesearch-definition-source |
0m
Args: map[Name:ethtool_flash_device]
Results: map[SourceCode:2732: static int
2733: ethtool_flash_device(struct net_device *dev, struct ethtool_devlink_compat *req)
2734: {
2735: if (!dev->ethtool_ops->flash_device) {
2736: req->devlink = netdev_to_devlink_get(dev);
2737: return 0;
2738: }
2739:
2740: return dev->ethtool_ops->flash_device(dev, &req->efl);
2741: }
SourceFile:net/ethtool/ioctl.c]
|
| 54/2 |
2026/07/30 00:09 |
llm |
expert |
1m
Model:
Tokens:
input: 57000
output: 26
thoughts: 146
Thoughts: **My Analysis of the `ethtool_ops` and Devlink Interaction**
Okay, so I'm digging into this code and trying to understand this flashing process. It looks like if the `dev->ethtool_ops->flash_device` function pointer is null, then the code calls `netdev_to_devlink_get(dev)`. This seems like a fallback, which is interesting. If `netdev_to_devlink_get(dev)` *does* return a devlink instance successfully (indicated by a return of 0), then `dev_ethtool` will end up calling `devlink_compat_flash_update`.
Hmm, this triggers a question. Does the loopback interface (`lo`) have a devlink instance? My initial intuition is *no*, since it's a software loopback. I'm pretty sure that's not the kind of thing that has associated hardware with a devlink.
So, the next thought is: what other network devices can an unprivileged user even *create* within their own network namespace? I'm pretty sure `veth` pairs are the answer. They're a common, relatively safe way to get network connectivity in a namespace.
Now, the crucial question: does `veth` have a devlink instance? This is what I need to investigate next. I'll need to check the `veth_ethtool_ops` structure to verify if it is using devlink to handle the flashing process.
|
| 55/2 |
2026/07/30 00:11 |
tool |
codesearch-definition-source |
0m
Args: map[Name:veth_ethtool_ops]
Results: map[SourceCode: 264: static const struct ethtool_ops veth_ethtool_ops = {
265: .get_drvinfo = veth_get_drvinfo,
266: .get_link = ethtool_op_get_link,
267: .get_strings = veth_get_strings,
268: .get_sset_count = veth_get_sset_count,
269: .get_ethtool_stats = veth_get_ethtool_stats,
270: .get_link_ksettings = veth_get_link_ksettings,
271: .get_ts_info = ethtool_op_get_ts_info,
272: .get_channels = veth_get_channels,
273: .set_channels = veth_set_channels,
274: };
SourceFile:drivers/net/veth.c]
|
| 56/2 |
2026/07/30 00:11 |
llm |
expert |
0m
Model:
Tokens:
input: 57765
output: 22
thoughts: 1607
Thoughts: **Analysis of the Devlink Flash Update Deadlock Vulnerability**
Okay, let's break this down. No, there's no way to trigger a `devlink` flash update from a device I can create, like `veth`, `tun`, or similar, that isn't a bus driver or `netdevsim`. An unprivileged user with just `CAP_NET_ADMIN` can create those devices within their own user namespace, but they don't have `devlink` instances. Even if root moved a physical device into their namespace, that requires root intervention to start. So, by default, this doesn't look accessible to the unprivileged.
But wait, this lockdep warning⦠this `syz.3.395/6091` thing? That's a lockdep issue, which isn't enabled in production. Even if it *were* triggered, the core problem is `try_to_freeze` being called while a lock is held, meaning it calls `__refrigerator(false)`. If a process freezes while holding a lock, that's suspend/resume deadlock potential. That's a classic Denial of Service. Now, this `try_to_freeze` is only called if `usermodehelper_disabled` is true, which *is* true during suspend/resume.
So, the attack is, if someone calls `devlink_compat_flash_update` during suspend/resume, they cause a deadlock. Hmm⦠`request_firmware` calls `usermodehelper_read_trylock`, which waits and calls `try_to_freeze` if `usermodehelper_disabled` is true. If the process is frozen, it'll hold the `devlink` lock. Other processes needing that lock will block. That's a real deadlock.
But the `devlink` lock is specific to a `devlink` instance. Does suspend/resume even *need* it? Drivers might, but it depends on the driver. Still, this is a lockdep warning, disabled in production. But, even if it's disabled, the code still *freezes* while holding the lock. Yes, the `try_to_freeze` call still happens, so the process will be frozen while holding the `devlink` lock.
This is bad, freezing while holding a lock is a bad idea, but is it a security vulnerability? If it can be triggered, it's a DoS during suspend. However, unprivileged users can't trigger this because they can't access a `devlink` device. Root can trigger it, but root already has full system control; it's not a privilege escalation. Plus, root can easily reboot with `/proc/sysrq-trigger`.
What about in a VM guest? This is a kernel bug, so root in the VM guest can trigger it, but it only affects the *guest* kernel, which they already control. Not a VM escape. Remote attacker? No, `devlink_compat_flash_update` needs local netlink or ioctl access. Peripheral trigger? Malicious USB device? It could register a `devlink` instance, but the user space command still needs to be sent via ioctl or netlink. So, peripheral trigger is also no.
Wait, can we *really* eliminate unprivileged access? Let's double-check. Ethtool doesn't include the flash update cmd. `ETHTOOL_FLASHDEV` is not in the allowed list, which means it needs `CAP_NET_ADMIN`. Netlink needs `GENL_ADMIN_PERM`, which also requires `CAP_NET_ADMIN`. So both the ioctl and netlink routes require `CAP_NET_ADMIN`.
Can unprivileged users get `CAP_NET_ADMIN`? Yes, via user and network namespaces. But their new network namespace doesn't have `devlink` devices. They can't create one. Specifically, `netdevsim` is the only virtual device, and it's created via `/sys/bus/netdevsim/new_device`. This file is root-owned and has mode 0200 (`--w-------`). So even with `CAP_NET_ADMIN` in a user namespace, I can't write to `/sys/bus/netdevsim/new_device`. Therefore, an unprivileged user cannot create a devlink device. Looks like no way for unprivileged processes, and no peripheral trigger is possible, so this is indeed a bug, but not one that is particularly security-relevant. It requires root access to be triggered, but root already has that level of access.
|
| 57/2 |
2026/07/30 00:12 |
tool |
codesearch-find-references |
0m
Args:
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:dsa_switch_devlink_alloc SourceFile:net/dsa/devlink.c SourceLine:386] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ena_devlink_alloc SourceFile:drivers/net/ethernet/amazon/ena/ena_devlink.c SourceLine:165] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:es58x_init_es58x_dev SourceFile:drivers/net/can/usb/etas_es58x/es58x_core.c SourceLine:2187] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:kvaser_usb_probe SourceFile:drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c SourceLine:943]] TruncatedOutput:false]
|
| 58/2 |
2026/07/30 00:12 |
llm |
expert |
0m
Model:
Tokens:
input: 60654
output: 24
thoughts: 66
Thoughts: Okay, let me break this down.
**My Initial Assessment of `devlink_alloc` Usage**
Right, so I'm looking at how `devlink_alloc` is utilized in the broader system, specifically in the Linux kernel. My initial focus is on where this function is being called directly. The code indicates that `dsa_switch_devlink_alloc`, `ena_devlink_alloc`, `es58x_init_es58x_dev`, and `kvaser_usb_probe` are all leveraging `devlink_alloc`. This suggests they're all core components that need the resource allocation that `devlink` provides. It makes sense, as these seem to relate to diverse network device management, from DSA switches to specific hardware like ENA and Kvaser USB interfaces. I need to understand the connection between all of these components and how devlink helps them, but my priority is tracking down the scope of `devlink_alloc`.
Now, that brings up an important point for further investigation... I need to also consider `devlink_alloc_ns`. Is there an overlap in use cases? Are there cases where I can use `devlink_alloc` when `devlink_alloc_ns` would be more appropriate or vice versa? That is where I will begin my next phase of study.
|
| 59/2 |
2026/07/30 00:12 |
tool |
codesearch-find-references |
0m
Args: map[Name:devlink_alloc_ns]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:devlink_alloc SourceFile:include/net/devlink.h SourceLine:1650] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:nsim_drv_probe SourceFile:drivers/net/netdevsim/dev.c SourceLine:1654] map[ReferenceKind:takes-address-of ReferencingEntityKind:global_variable ReferencingEntityName:__UNIQUE_ID_addressable_devlink_alloc_ns_1045 SourceFile:net/devlink/core.c SourceLine:510] map[ReferenceKind:takes-address-of ReferencingEntityKind:global_variable ReferencingEntityName:__gendwarfksyms_ptr_devlink_alloc_ns SourceFile:net/devlink/core.c SourceLine:510] map[ReferenceKind:takes-address-of ReferencingEntityKind:global_variable ReferencingEntityName:__gendwarfksyms_ptr_devlink_alloc_ns SourceFile:net/devlink/core.c SourceLine:510]] TruncatedOutput:false]
|
| 60/2 |
2026/07/30 00:12 |
llm |
expert |
0m
Model:
Tokens:
input: 61353
output: 22
thoughts: 43
Thoughts: Okay, here's my interpretation of those thoughts, crafted with the perspective of someone deeply familiar with driver development:
**Initial Investigation into a Devlink Allocation Issue**
Right, something's not quite right. I saw the `devlink_alloc` function being called and... hang on a minute. It seems like the output related to the function's execution was truncated, but the `TruncatedOutput:false` flag is set. That doesn't make any sense! The output isn't supposed to be truncated. Something is off with the logging, or perhaps the data itself. I need to dig deeper.
Wait a second, isn't `devlink_alloc` an inline function? That might explain the weirdness. Inline functions can be tricky with debugging output. The compiler might have optimized it away or merged it. Let's start with that assumption.
|
| 61/2 |
2026/07/30 00:12 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:1646: static inline struct devlink *devlink_alloc(const struct devlink_ops *ops,
1647: size_t priv_size,
1648: struct device *dev)
1649: {
1650: return devlink_alloc_ns(ops, priv_size, &init_net, dev);
1651: }
SourceFile:include/net/devlink.h]
|
| 62/2 |
2026/07/30 00:12 |
llm |
expert |
0m
Model:
Tokens:
input: 61730
output: 18
thoughts: 115
Thoughts: **Tracing the Allocation of a Devlink Namespace**
Okay, so I'm diving into this `devlink` code... I see that `devlink_alloc` is defined inline right in `include/net/devlink.h`. That's interesting, usually I'd expect to see a more "real" function there. So, really, the work is done in `devlink_alloc_ns`. Right.
Now, let's see where `devlink_alloc_ns` is being used. Ah, it looks like `nsim_drv_probe` calls it. That's a good starting point. But since `devlink_alloc` is inline, I can't just rely on standard reference searches. The compiler is probably optimizing it away, so tools like `codesearch-find-references` might miss callers if they're in different modules.
I'd better cast a wider net. I'm going to fire up a `grep` for `devlink_alloc` itself, just to make sure I don't miss any direct calls, even if they're inlined. Gotta be thorough.
|
| 63/2 |
2026/07/30 00:12 |
tool |
grepper |
0m
Args: map[Expression:devlink_alloc]
Results: map[Output:drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c=143=int otx2_cpt_register_dl(struct otx2_cptpf_dev *cptpf)
--
drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c-149-
drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c:150: dl = devlink_alloc(&otx2_cpt_devlink_ops,
drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c-151- sizeof(struct otx2_cpt_devlink), dev);
drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c-152- if (!dl) {
drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c:153: dev_warn(dev, "devlink_alloc failed\n");
drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c-154- return -ENOMEM;
--
drivers/dpll/zl3073x/devlink.c=293=struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev)
--
drivers/dpll/zl3073x/devlink.c-298-
drivers/dpll/zl3073x/devlink.c:299: devlink = devlink_alloc(&zl3073x_devlink_ops, sizeof(*zldev), dev);
drivers/dpll/zl3073x/devlink.c-300- if (!devlink)
--
drivers/net/can/kvaser_pciefd/kvaser_pciefd_core.c=1757=static int kvaser_pciefd_probe(struct pci_dev *pdev,
--
drivers/net/can/kvaser_pciefd/kvaser_pciefd_core.c-1765-
drivers/net/can/kvaser_pciefd/kvaser_pciefd_core.c:1766: devlink = devlink_alloc(&kvaser_pciefd_devlink_ops, sizeof(*pcie), dev);
drivers/net/can/kvaser_pciefd/kvaser_pciefd_core.c-1767- if (!devlink)
--
drivers/net/can/usb/etas_es58x/es58x_core.c=2159=static struct es58x_device *es58x_init_es58x_dev(struct usb_interface *intf,
--
drivers/net/can/usb/etas_es58x/es58x_core.c-2186-
drivers/net/can/usb/etas_es58x/es58x_core.c:2187: devlink = devlink_alloc(&es58x_dl_ops, es58x_sizeof_es58x_device(param),
drivers/net/can/usb/etas_es58x/es58x_core.c-2188- dev);
--
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c=929=static int kvaser_usb_probe(struct usb_interface *intf,
--
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c-942-
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c:943: devlink = devlink_alloc(&kvaser_usb_devlink_ops, sizeof(*dev), &intf->dev);
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c-944- if (!devlink)
--
drivers/net/ethernet/amazon/ena/ena_devlink.c=137=static int ena_devlink_configure_params(struct devlink *devlink)
--
drivers/net/ethernet/amazon/ena/ena_devlink.c-159-
drivers/net/ethernet/amazon/ena/ena_devlink.c:160:struct devlink *ena_devlink_alloc(struct ena_adapter *adapter)
drivers/net/ethernet/amazon/ena/ena_devlink.c-161-{
--
drivers/net/ethernet/amazon/ena/ena_devlink.c-164-
drivers/net/ethernet/amazon/ena/ena_devlink.c:165: devlink = devlink_alloc(&ena_devlink_ops,
drivers/net/ethernet/amazon/ena/ena_devlink.c-166- sizeof(struct ena_adapter *),
--
drivers/net/ethernet/amazon/ena/ena_devlink.h-13-
drivers/net/ethernet/amazon/ena/ena_devlink.h:14:struct devlink *ena_devlink_alloc(struct ena_adapter *adapter);
drivers/net/ethernet/amazon/ena/ena_devlink.h-15-void ena_devlink_free(struct devlink *devlink);
--
drivers/net/ethernet/amazon/ena/ena_netdev.c=3896=static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
--
drivers/net/ethernet/amazon/ena/ena_netdev.c-3987- /* Need to do this before ena_device_init */
drivers/net/ethernet/amazon/ena/ena_netdev.c:3988: devlink = ena_devlink_alloc(adapter);
drivers/net/ethernet/amazon/ena/ena_netdev.c-3989- if (!devlink) {
drivers/net/ethernet/amazon/ena/ena_netdev.c:3990: netdev_err(netdev, "ena_devlink_alloc failed\n");
drivers/net/ethernet/amazon/ena/ena_netdev.c-3991- rc = -ENOMEM;
--
drivers/net/ethernet/amd/pds_core/main.c=332=static int pdsc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
--
drivers/net/ethernet/amd/pds_core/main.c-342- ops = is_pf ? &pdsc_dl_ops : &pdsc_dl_vf_ops;
drivers/net/ethernet/amd/pds_core/main.c:343: dl = devlink_alloc(ops, sizeof(struct pdsc), dev);
drivers/net/ethernet/amd/pds_core/main.c-344- if (!dl)
--
drivers/net/ethernet/broadcom/bnge/bnge_core.c=261=static int bnge_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
--
drivers/net/ethernet/broadcom/bnge/bnge_core.c-285-
drivers/net/ethernet/broadcom/bnge/bnge_core.c:286: bd = bnge_devlink_alloc(pdev);
drivers/net/ethernet/broadcom/bnge/bnge_core.c-287- if (!bd) {
--
drivers/net/ethernet/broadcom/bnge/bnge_devlink.c=266=void bnge_devlink_free(struct bnge_dev *bd)
--
drivers/net/ethernet/broadcom/bnge/bnge_devlink.c-272-
drivers/net/ethernet/broadcom/bnge/bnge_devlink.c:273:struct bnge_dev *bnge_devlink_alloc(struct pci_dev *pdev)
drivers/net/ethernet/broadcom/bnge/bnge_devlink.c-274-{
--
drivers/net/ethernet/broadcom/bnge/bnge_devlink.c-277-
drivers/net/ethernet/broadcom/bnge/bnge_devlink.c:278: devlink = devlink_alloc(&bnge_devlink_ops, sizeof(*bd), &pdev->dev);
drivers/net/ethernet/broadcom/bnge/bnge_devlink.c-279- if (!devlink)
--
drivers/net/ethernet/broadcom/bnge/bnge_devlink.h=13=void bnge_devlink_free(struct bnge_dev *bd);
drivers/net/ethernet/broadcom/bnge/bnge_devlink.h:14:struct bnge_dev *bnge_devlink_alloc(struct pci_dev *pdev);
drivers/net/ethernet/broadcom/bnge/bnge_devlink.h-15-void bnge_devlink_register(struct bnge_dev *bd);
--
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c=1263=int bnxt_dl_register(struct bnxt *bp)
--
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c-1275-
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c:1276: dl = devlink_alloc(devlink_ops, sizeof(struct bnxt_dl), &bp->pdev->dev);
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c-1277- if (!dl) {
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c:1278: netdev_warn(bp->dev, "devlink_alloc failed\n");
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c-1279- return -ENOMEM;
--
drivers/net/ethernet/cavium/liquidio/lio_main.c=3322=static int setup_nic_devices(struct octeon_device *octeon_dev)
--
drivers/net/ethernet/cavium/liquidio/lio_main.c-3744- device_lock(&octeon_dev->pci_dev->dev);
drivers/net/ethernet/cavium/liquidio/lio_main.c:3745: devlink = devlink_alloc(&liquidio_devlink_ops,
drivers/net/ethernet/cavium/liquidio/lio_main.c-3746- sizeof(struct lio_devlink_priv),
--
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c=183=int dpaa2_eth_dl_alloc(struct dpaa2_eth_priv *priv)
--
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c-189- priv->devlink =
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c:190: devlink_alloc(&dpaa2_eth_devlink_ops, sizeof(*dl_priv), dev);
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c-191- if (!priv->devlink) {
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c:192: dev_err(dev, "devlink_alloc failed\n");
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c-193- return -ENOMEM;
--
drivers/net/ethernet/fungible/funeth/funeth_devlink.c=6=static const struct devlink_ops fun_dl_ops = {
--
drivers/net/ethernet/fungible/funeth/funeth_devlink.c-8-
drivers/net/ethernet/fungible/funeth/funeth_devlink.c:9:struct devlink *fun_devlink_alloc(struct device *dev)
drivers/net/ethernet/fungible/funeth/funeth_devlink.c-10-{
drivers/net/ethernet/fungible/funeth/funeth_devlink.c:11: return devlink_alloc(&fun_dl_ops, sizeof(struct fun_ethdev), dev);
drivers/net/ethernet/fungible/funeth/funeth_devlink.c-12-}
--
drivers/net/ethernet/fungible/funeth/funeth_devlink.h-7-
drivers/net/ethernet/fungible/funeth/funeth_devlink.h:8:struct devlink *fun_devlink_alloc(struct device *dev);
drivers/net/ethernet/fungible/funeth/funeth_devlink.h-9-void fun_devlink_free(struct devlink *devlink);
--
drivers/net/ethernet/fungible/funeth/funeth_main.c=1984=static int funeth_probe(struct pci_dev *pdev, const struct pci_device_id *id)
--
drivers/net/ethernet/fungible/funeth/funeth_main.c-2000-
drivers/net/ethernet/fungible/funeth/funeth_main.c:2001: devlink = fun_devlink_alloc(&pdev->dev);
drivers/net/ethernet/fungible/funeth/funeth_main.c-2002- if (!devlink) {
--
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c=140=int hclge_devlink_init(struct hclge_dev *hdev)
--
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c-145-
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c:146: devlink = devlink_alloc(&hclge_devlink_ops,
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c-147- sizeof(struct hclge_devlink_priv), &pdev->dev);
--
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_devlink.c=103=int hclgevf_devlink_init(struct hclgevf_dev *hdev)
--
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_devlink.c-109- devlink =
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_devlink.c:110: devlink_alloc(&hclgevf_devlink_ops,
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_devlink.c-111- sizeof(struct hclgevf_devlink_priv), &pdev->dev);
--
drivers/net/ethernet/huawei/hinic/hinic_devlink.c=290=static const struct devlink_ops hinic_devlink_ops = {
--
drivers/net/ethernet/huawei/hinic/hinic_devlink.c-293-
drivers/net/ethernet/huawei/hinic/hinic_devlink.c:294:struct devlink *hinic_devlink_alloc(struct device *dev)
drivers/net/ethernet/huawei/hinic/hinic_devlink.c-295-{
drivers/net/ethernet/huawei/hinic/hinic_devlink.c:296: return devlink_alloc(&hinic_devlink_ops, sizeof(struct hinic_dev), dev);
drivers/net/ethernet/huawei/hinic/hinic_devlink.c-297-}
--
drivers/net/ethernet/huawei/hinic/hinic_devlink.h=101=struct host_image_st {
--
drivers/net/ethernet/huawei/hinic/hinic_devlink.h-110-
drivers/net/ethernet/huawei/hinic/hinic_devlink.h:111:struct devlink *hinic_devlink_alloc(struct device *dev);
drivers/net/ethernet/huawei/hinic/hinic_devlink.h-112-void hinic_devlink_free(struct devlink *devlink);
--
drivers/net/ethernet/huawei/hinic/hinic_main.c=1160=static int nic_dev_init(struct pci_dev *pdev)
--
drivers/net/ethernet/huawei/hinic/hinic_main.c-1169-
drivers/net/ethernet/huawei/hinic/hinic_main.c:1170: devlink = hinic_devlink_alloc(&pdev->dev);
drivers/net/ethernet/huawei/hinic/hinic_main.c-1171- if (!devlink) {
--
drivers/net/ethernet/intel/i40e/i40e_devlink.c=172=struct i40e_pf *i40e_alloc_pf(struct device *dev)
--
drivers/net/ethernet/intel/i40e/i40e_devlink.c-175-
drivers/net/ethernet/intel/i40e/i40e_devlink.c:176: devlink = devlink_alloc(&i40e_devlink_ops, sizeof(struct i40e_pf), dev);
drivers/net/ethernet/intel/i40e/i40e_devlink.c-177- if (!devlink)
--
drivers/net/ethernet/intel/i40e/i40e_devlink.c-186- *
drivers/net/ethernet/intel/i40e/i40e_devlink.c:187: * Free i40e_pf structure and devlink allocated by devlink_alloc.
drivers/net/ethernet/intel/i40e/i40e_devlink.c-188- **/
--
drivers/net/ethernet/intel/ice/devlink/devlink.c=1699=struct ice_pf *ice_allocate_pf(struct device *dev)
--
drivers/net/ethernet/intel/ice/devlink/devlink.c-1702-
drivers/net/ethernet/intel/ice/devlink/devlink.c:1703: devlink = devlink_alloc(&ice_devlink_ops, sizeof(struct ice_pf), dev);
drivers/net/ethernet/intel/ice/devlink/devlink.c-1704- if (!devlink)
--
drivers/net/ethernet/intel/ice/devlink/devlink.c=1723=struct ice_sf_priv *ice_allocate_sf(struct device *dev, struct ice_pf *pf)
--
drivers/net/ethernet/intel/ice/devlink/devlink.c-1727-
drivers/net/ethernet/intel/ice/devlink/devlink.c:1728: devlink = devlink_alloc(&ice_sf_devlink_ops, sizeof(struct ice_sf_priv),
drivers/net/ethernet/intel/ice/devlink/devlink.c-1729- dev);
--
drivers/net/ethernet/intel/ixgbe/devlink/devlink.c=499=struct ixgbe_adapter *ixgbe_allocate_devlink(struct device *dev)
--
drivers/net/ethernet/intel/ixgbe/devlink/devlink.c-503-
drivers/net/ethernet/intel/ixgbe/devlink/devlink.c:504: devlink = devlink_alloc(&ixgbe_devlink_ops, sizeof(*adapter), dev);
drivers/net/ethernet/intel/ixgbe/devlink/devlink.c-505- if (!devlink)
--
drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c=1719=int rvu_register_dl(struct rvu *rvu)
--
drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c-1724-
drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c:1725: dl = devlink_alloc(&rvu_devlink_ops, sizeof(struct rvu_devlink),
drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c-1726- rvu->dev);
drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c-1727- if (!dl) {
drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c:1728: dev_warn(rvu->dev, "devlink_alloc failed\n");
drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c-1729- return -ENOMEM;
--
drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c=199=int otx2_register_dl(struct otx2_nic *pfvf)
--
drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c-204-
drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c:205: dl = devlink_alloc(&otx2_devlink_ops,
drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c-206- sizeof(struct otx2_devlink), pfvf->dev);
drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c-207- if (!dl) {
drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c:208: dev_warn(pfvf->dev, "devlink_alloc failed\n");
drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c-209- return -ENOMEM;
--
drivers/net/ethernet/marvell/prestera/prestera_devlink.c=377=static const struct devlink_ops prestera_dl_ops = {
--
drivers/net/ethernet/marvell/prestera/prestera_devlink.c-383-
drivers/net/ethernet/marvell/prestera/prestera_devlink.c:384:struct prestera_switch *prestera_devlink_alloc(struct prestera_device *dev)
drivers/net/ethernet/marvell/prestera/prestera_devlink.c-385-{
--
drivers/net/ethernet/marvell/prestera/prestera_devlink.c-387-
drivers/net/ethernet/marvell/prestera/prestera_devlink.c:388: dl = devlink_alloc(&prestera_dl_ops, sizeof(struct prestera_switch),
drivers/net/ethernet/marvell/prestera/prestera_devlink.c-389- dev->dev);
--
drivers/net/ethernet/marvell/prestera/prestera_devlink.h-8-
drivers/net/ethernet/marvell/prestera/prestera_devlink.h:9:struct prestera_switch *prestera_devlink_alloc(struct prestera_device *dev);
drivers/net/ethernet/marvell/prestera/prestera_devlink.h-10-void prestera_devlink_free(struct prestera_switch *sw);
--
drivers/net/ethernet/marvell/prestera/prestera_main.c=1470=int prestera_device_register(struct prestera_device *dev)
--
drivers/net/ethernet/marvell/prestera/prestera_main.c-1474-
drivers/net/ethernet/marvell/prestera/prestera_main.c:1475: sw = prestera_devlink_alloc(dev);
drivers/net/ethernet/marvell/prestera/prestera_main.c-1476- if (!sw)
--
drivers/net/ethernet/mellanox/mlx4/main.c=4019=static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
--
drivers/net/ethernet/mellanox/mlx4/main.c-4027-
drivers/net/ethernet/mellanox/mlx4/main.c:4028: devlink = devlink_alloc(&mlx4_devlink_ops, sizeof(*priv), &pdev->dev);
drivers/net/ethernet/mellanox/mlx4/main.c-4029- if (!devlink)
--
drivers/net/ethernet/mellanox/mlx5/core/devlink.c=434=int mlx5_devlink_traps_get_action(struct mlx5_core_dev *dev, int trap_id,
--
drivers/net/ethernet/mellanox/mlx5/core/devlink.c-449-
drivers/net/ethernet/mellanox/mlx5/core/devlink.c:450:struct devlink *mlx5_devlink_alloc(struct device *dev)
drivers/net/ethernet/mellanox/mlx5/core/devlink.c-451-{
drivers/net/ethernet/mellanox/mlx5/core/devlink.c:452: return devlink_alloc(&mlx5_devlink_ops, sizeof(struct mlx5_core_dev),
drivers/net/ethernet/mellanox/mlx5/core/devlink.c-453- dev);
--
drivers/net/ethernet/mellanox/mlx5/core/devlink.h=60=void mlx5_devlink_traps_unregister(struct devlink *devlink);
drivers/net/ethernet/mellanox/mlx5/core/devlink.h-61-
drivers/net/ethernet/mellanox/mlx5/core/devlink.h:62:struct devlink *mlx5_devlink_alloc(struct device *dev);
drivers/net/ethernet/mellanox/mlx5/core/devlink.h-63-void mlx5_devlink_free(struct devlink *devlink);
--
drivers/net/ethernet/mellanox/mlx5/core/en/devlink.c=10=struct mlx5e_dev *mlx5e_create_devlink(struct device *dev,
--
drivers/net/ethernet/mellanox/mlx5/core/en/devlink.c-16-
drivers/net/ethernet/mellanox/mlx5/core/en/devlink.c:17: devlink = devlink_alloc_ns(&mlx5e_devlink_ops, sizeof(*mlx5e_dev),
drivers/net/ethernet/mellanox/mlx5/core/en/devlink.c-18- devlink_net(priv_to_devlink(mdev)), dev);
--
drivers/net/ethernet/mellanox/mlx5/core/main.c=1932=static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
--
drivers/net/ethernet/mellanox/mlx5/core/main.c-1937-
drivers/net/ethernet/mellanox/mlx5/core/main.c:1938: devlink = mlx5_devlink_alloc(&pdev->dev);
drivers/net/ethernet/mellanox/mlx5/core/main.c-1939- if (!devlink) {
--
drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c=25=static int mlx5_sf_dev_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id)
--
drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c-31-
drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c:32: devlink = mlx5_devlink_alloc(&adev->dev);
drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c-33- if (!devlink)
--
drivers/net/ethernet/mellanox/mlxsw/core.c=2095=__mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
--
drivers/net/ethernet/mellanox/mlxsw/core.c-2113- alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size;
drivers/net/ethernet/mellanox/mlxsw/core.c:2114: devlink = devlink_alloc(&mlxsw_devlink_ops, alloc_size,
drivers/net/ethernet/mellanox/mlxsw/core.c-2115- mlxsw_bus_info->dev);
--
drivers/net/ethernet/mellanox/mlxsw/core.c-2117- err = -ENOMEM;
drivers/net/ethernet/mellanox/mlxsw/core.c:2118: goto err_devlink_alloc;
drivers/net/ethernet/mellanox/mlxsw/core.c-2119- }
--
drivers/net/ethernet/mellanox/mlxsw/core.c-2241- }
drivers/net/ethernet/mellanox/mlxsw/core.c:2242:err_devlink_alloc:
drivers/net/ethernet/mellanox/mlxsw/core.c-2243- return err;
--
drivers/net/ethernet/mellanox/mlxsw/core_linecard_dev.c=127=static int mlxsw_linecard_bdev_probe(struct auxiliary_device *adev,
--
drivers/net/ethernet/mellanox/mlxsw/core_linecard_dev.c-136-
drivers/net/ethernet/mellanox/mlxsw/core_linecard_dev.c:137: devlink = devlink_alloc(&mlxsw_linecard_dev_devlink_ops,
drivers/net/ethernet/mellanox/mlxsw/core_linecard_dev.c-138- sizeof(*linecard_dev), &adev->dev);
--
drivers/net/ethernet/meta/fbnic/fbnic.h=173=void fbnic_devlink_free(struct fbnic_dev *fbd);
drivers/net/ethernet/meta/fbnic/fbnic.h:174:struct fbnic_dev *fbnic_devlink_alloc(struct pci_dev *pdev);
drivers/net/ethernet/meta/fbnic/fbnic.h-175-int fbnic_devlink_health_create(struct fbnic_dev *fbd);
--
drivers/net/ethernet/meta/fbnic/fbnic_devlink.c=621=void fbnic_devlink_free(struct fbnic_dev *fbd)
--
drivers/net/ethernet/meta/fbnic/fbnic_devlink.c-627-
drivers/net/ethernet/meta/fbnic/fbnic_devlink.c:628:struct fbnic_dev *fbnic_devlink_alloc(struct pci_dev *pdev)
drivers/net/ethernet/meta/fbnic/fbnic_devlink.c-629-{
--
drivers/net/ethernet/meta/fbnic/fbnic_devlink.c-633-
drivers/net/ethernet/meta/fbnic/fbnic_devlink.c:634: devlink = devlink_alloc(&fbnic_devlink_ops, sizeof(struct fbnic_dev),
drivers/net/ethernet/meta/fbnic/fbnic_devlink.c-635- &pdev->dev);
--
drivers/net/ethernet/meta/fbnic/fbnic_pci.c=259=static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
--
drivers/net/ethernet/meta/fbnic/fbnic_pci.c-292-
drivers/net/ethernet/meta/fbnic/fbnic_pci.c:293: fbd = fbnic_devlink_alloc(pdev);
drivers/net/ethernet/meta/fbnic/fbnic_pci.c-294- if (!fbd) {
--
drivers/net/ethernet/mscc/ocelot_vsc7514.c=236=static int mscc_ocelot_probe(struct platform_device *pdev)
--
drivers/net/ethernet/mscc/ocelot_vsc7514.c-266- devlink =
drivers/net/ethernet/mscc/ocelot_vsc7514.c:267: devlink_alloc(&ocelot_devlink_ops, sizeof(*ocelot), &pdev->dev);
drivers/net/ethernet/mscc/ocelot_vsc7514.c-268- if (!devlink)
--
drivers/net/ethernet/netronome/nfp/nfp_main.c=757=static int nfp_pci_probe(struct pci_dev *pdev,
--
drivers/net/ethernet/netronome/nfp/nfp_main.c-788-
drivers/net/ethernet/netronome/nfp/nfp_main.c:789: devlink = devlink_alloc(&nfp_devlink_ops, sizeof(*pf), &pdev->dev);
drivers/net/ethernet/netronome/nfp/nfp_main.c-790- if (!devlink) {
--
drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c=308=static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
--
drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c-314-
drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c:315: ionic = ionic_devlink_alloc(dev);
drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c-316- if (!ionic)
--
drivers/net/ethernet/pensando/ionic/ionic_devlink.c=54=static const struct devlink_ops ionic_dl_ops = {
--
drivers/net/ethernet/pensando/ionic/ionic_devlink.c-58-
drivers/net/ethernet/pensando/ionic/ionic_devlink.c:59:struct ionic *ionic_devlink_alloc(struct device *dev)
drivers/net/ethernet/pensando/ionic/ionic_devlink.c-60-{
--
drivers/net/ethernet/pensando/ionic/ionic_devlink.c-62-
drivers/net/ethernet/pensando/ionic/ionic_devlink.c:63: dl = devlink_alloc(&ionic_dl_ops, sizeof(struct ionic), dev);
drivers/net/ethernet/pensando/ionic/ionic_devlink.c-64- if (!dl)
--
drivers/net/ethernet/pensando/ionic/ionic_devlink.h=9=int ionic_firmware_update(struct ionic_lif *lif, const struct firmware *fw,
--
drivers/net/ethernet/pensando/ionic/ionic_devlink.h-11-
drivers/net/ethernet/pensando/ionic/ionic_devlink.h:12:struct ionic *ionic_devlink_alloc(struct device *dev);
drivers/net/ethernet/pensando/ionic/ionic_devlink.h-13-void ionic_devlink_free(struct ionic *ionic);
--
drivers/net/ethernet/qlogic/qed/qed_devlink.c=202=struct devlink *qed_devlink_register(struct qed_dev *cdev)
--
drivers/net/ethernet/qlogic/qed/qed_devlink.c-207-
drivers/net/ethernet/qlogic/qed/qed_devlink.c:208: dl = devlink_alloc(&qed_dl_ops, sizeof(struct qed_devlink),
drivers/net/ethernet/qlogic/qed/qed_devlink.c-209- &cdev->pdev->dev);
--
drivers/net/ethernet/sfc/efx_devlink.c=718=int efx_probe_devlink_and_lock(struct efx_nic *efx)
--
drivers/net/ethernet/sfc/efx_devlink.c-724-
drivers/net/ethernet/sfc/efx_devlink.c:725: efx->devlink = devlink_alloc(&sfc_devlink_ops,
drivers/net/ethernet/sfc/efx_devlink.c-726- sizeof(struct efx_devlink),
--
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c=7716=static int stmmac_register_devlink(struct stmmac_priv *priv)
--
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c-7727-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c:7728: priv->devlink = devlink_alloc(&stmmac_devlink_ops, sizeof(*dl_priv),
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c-7729- priv->device);
--
drivers/net/ethernet/ti/am65-cpsw-nuss.c=3249=static int am65_cpsw_nuss_register_devlink(struct am65_cpsw_common *common)
--
drivers/net/ethernet/ti/am65-cpsw-nuss.c-3259- common->devlink =
drivers/net/ethernet/ti/am65-cpsw-nuss.c:3260: devlink_alloc(&am65_cpsw_devlink_ops, sizeof(*dl_priv), dev);
drivers/net/ethernet/ti/am65-cpsw-nuss.c-3261- if (!common->devlink)
--
drivers/net/ethernet/ti/cpsw_new.c=1837=static int cpsw_register_devlink(struct cpsw_common *cpsw)
--
drivers/net/ethernet/ti/cpsw_new.c-1842-
drivers/net/ethernet/ti/cpsw_new.c:1843: cpsw->devlink = devlink_alloc(&cpsw_devlink_ops, sizeof(*dl_priv), dev);
drivers/net/ethernet/ti/cpsw_new.c-1844- if (!cpsw->devlink)
--
drivers/net/netdevsim/dev.c=1648=int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev)
--
drivers/net/netdevsim/dev.c-1653-
drivers/net/netdevsim/dev.c:1654: devlink = devlink_alloc_ns(&nsim_dev_devlink_ops, sizeof(*nsim_dev),
drivers/net/netdevsim/dev.c-1655- nsim_bus_dev->initial_net, &nsim_bus_dev->dev);
--
drivers/net/wwan/iosm/iosm_ipc_devlink.c=241=struct iosm_devlink *ipc_devlink_init(struct iosm_imem *ipc_imem)
--
drivers/net/wwan/iosm/iosm_ipc_devlink.c-247-
drivers/net/wwan/iosm/iosm_ipc_devlink.c:248: devlink_ctx = devlink_alloc(&devlink_flash_ops,
drivers/net/wwan/iosm/iosm_ipc_devlink.c-249- sizeof(struct iosm_devlink),
--
drivers/net/wwan/iosm/iosm_ipc_devlink.c-251- if (!devlink_ctx) {
drivers/net/wwan/iosm/iosm_ipc_devlink.c:252: dev_err(ipc_imem->dev, "devlink_alloc failed");
drivers/net/wwan/iosm/iosm_ipc_devlink.c:253: goto devlink_alloc_fail;
drivers/net/wwan/iosm/iosm_ipc_devlink.c-254- }
--
drivers/net/wwan/iosm/iosm_ipc_devlink.c-298- devlink_free(devlink_ctx);
drivers/net/wwan/iosm/iosm_ipc_devlink.c:299:devlink_alloc_fail:
drivers/net/wwan/iosm/iosm_ipc_devlink.c-300- return NULL;
--
drivers/ptp/ptp_ocp.c=5057=ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
--
drivers/ptp/ptp_ocp.c-5063-
drivers/ptp/ptp_ocp.c:5064: devlink = devlink_alloc(&ptp_ocp_devlink_ops, sizeof(*bp), &pdev->dev);
drivers/ptp/ptp_ocp.c-5065- if (!devlink) {
drivers/ptp/ptp_ocp.c:5066: dev_err(&pdev->dev, "devlink_alloc failed\n");
drivers/ptp/ptp_ocp.c-5067- return -ENOMEM;
--
include/net/devlink.h=1637=struct net *devlink_net(const struct devlink *devlink);
--
include/net/devlink.h-1640- *
include/net/devlink.h:1641: * Drivers that operate on real HW must use devlink_alloc() instead.
include/net/devlink.h-1642- */
include/net/devlink.h:1643:struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
include/net/devlink.h-1644- size_t priv_size, struct net *net,
include/net/devlink.h-1645- struct device *dev);
include/net/devlink.h:1646:static inline struct devlink *devlink_alloc(const struct devlink_ops *ops,
include/net/devlink.h-1647- size_t priv_size,
--
include/net/devlink.h-1649-{
include/net/devlink.h:1650: return devlink_alloc_ns(ops, priv_size, &init_net, dev);
include/net/devlink.h-1651-}
--
net/devlink/core.c=428=EXPORT_SYMBOL_GPL(devlink_unregister);
net/devlink/core.c-429-
net/devlink/core.c:430:struct devlink *__devlink_alloc(const struct devlink_ops *ops, size_t priv_size,
net/devlink/core.c-431- struct net *net, struct device *dev,
--
net/devlink/core.c-491-/**
net/devlink/core.c:492: * devlink_alloc_ns - Allocate new devlink instance resources
net/devlink/core.c-493- * in specific namespace
--
net/devlink/core.c-502- */
net/devlink/core.c:503:struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
net/devlink/core.c-504- size_t priv_size, struct net *net,
--
net/devlink/core.c-507- WARN_ON(!dev);
net/devlink/core.c:508: return __devlink_alloc(ops, priv_size, net, dev, dev->driver);
net/devlink/core.c-509-}
net/devlink/core.c:510:EXPORT_SYMBOL_GPL(devlink_alloc_ns);
net/devlink/core.c-511-
--
net/devlink/devl_internal.h=69=extern struct genl_family devlink_nl_family;
net/devlink/devl_internal.h-70-
net/devlink/devl_internal.h:71:struct devlink *__devlink_alloc(const struct devlink_ops *ops, size_t priv_size,
net/devlink/devl_internal.h-72- struct net *net, struct device *dev,
--
net/devlink/sh_dev.c=34=static struct devlink_shd *devlink_shd_create(const char *id,
--
net/devlink/sh_dev.c-41-
net/devlink/sh_dev.c:42: devlink = __devlink_alloc(ops, sizeof(struct devlink_shd) + priv_size,
net/devlink/sh_dev.c-43- &init_net, NULL, driver);
--
net/dsa/devlink.c=373=void dsa_switch_devlink_unregister(struct dsa_switch *ds)
--
net/dsa/devlink.c-377-
net/dsa/devlink.c:378:int dsa_switch_devlink_alloc(struct dsa_switch *ds)
net/dsa/devlink.c-379-{
--
net/dsa/devlink.c-385- */
net/dsa/devlink.c:386: dl = devlink_alloc(&dsa_devlink_ops, sizeof(*dl_priv), ds->dev);
net/dsa/devlink.c-387- if (!dl)
--
net/dsa/devlink.h=12=void dsa_switch_devlink_unregister(struct dsa_switch *ds);
net/dsa/devlink.h:13:int dsa_switch_devlink_alloc(struct dsa_switch *ds);
net/dsa/devlink.h-14-void dsa_switch_devlink_free(struct dsa_switch *ds);
--
net/dsa/dsa.c=621=static int dsa_switch_setup(struct dsa_switch *ds)
--
net/dsa/dsa.c-634-
net/dsa/dsa.c:635: err = dsa_switch_devlink_alloc(ds);
net/dsa/dsa.c-636- if (err)
]
|
| 64/2 |
2026/07/30 00:12 |
llm |
expert |
0m
Model:
Tokens:
input: 74223
output: 25
thoughts: 118
Thoughts: **Analyzing Devlink Instance Creation**
Okay, so I'm thinking through how a devlink instance gets created. Based on my understanding, all the places I've seen `devlink_alloc` called are firmly within the realm of hardware drivers, like PCI and USB devices, or, you know, `netdevsim`. That's the expected usage. And as far as I can tell, none of these calls can be directly triggered by an unprivileged user to actually *create* a devlink instance within their network namespace. Makes sense β that's a privileged operation, usually reserved for device initialization and management.
But wait a second... I need to be absolutely sure. What about `devlink_shd_create`? I vaguely recall seeing that function in the mix. Let me check the call graph. Ah, yes, itβs called within `devlink_shd_create` in `net/devlink/sh_dev.c`. Right, okay, let's take a closer look at *that* function and see what it's doing.
|
| 65/2 |
2026/07/30 00:12 |
tool |
codesearch-definition-source |
0m
Args: map[Name:devlink_shd_create]
Results: map[SourceCode: 34: static struct devlink_shd *devlink_shd_create(const char *id,
35: const struct devlink_ops *ops,
36: size_t priv_size,
37: const struct device_driver *driver)
38: {
39: struct devlink_shd *shd;
40: struct devlink *devlink;
41:
42: devlink = __devlink_alloc(ops, sizeof(struct devlink_shd) + priv_size,
43: &init_net, NULL, driver);
44: if (!devlink)
45: return NULL;
46: shd = devlink_priv(devlink);
47:
48: shd->id = kstrdup(id, GFP_KERNEL);
49: if (!shd->id)
50: goto err_devlink_free;
51: shd->priv_size = priv_size;
52: refcount_set(&shd->refcount, 1);
53:
54: devl_lock(devlink);
55: devl_register(devlink);
56: devl_unlock(devlink);
57:
58: list_add_tail(&shd->list, &shd_list);
59:
60: return shd;
61:
62: err_devlink_free:
63: devlink_free(devlink);
64: return NULL;
65: }
SourceFile:net/devlink/sh_dev.c]
|
| 66/2 |
2026/07/30 00:12 |
llm |
expert |
0m
Model:
Tokens:
input: 75055
output: 29
thoughts: 2126
Thoughts: **Analysis of the devlink Flash Update Lockdep Warning**
Okay, let's break this down systematically. The core of the issue seems to be a lockdep warning, indicating a lock being held during a freezing operation, specifically related to the `devlink` framework and firmware updates.
Initially, I considered how an unprivileged user or a user within a namespace might trigger this. The creation of a `devlink` instance happens in the initial network namespace, which effectively blocks unprivileged users from directly manipulating these instances. This immediately suggests the vulnerability isn't readily accessible to them. Syzkaller, however, throws a wrench into the works. It can run as UID 0 in a user namespace. The executor creates the `netdevsim` device which is then accessible by the test process. Therefore, even though Syzkaller is operating in a sandboxed environment, its capabilities to set up the execution environment could be the triggering factor.
The critical piece seems to be that syzkaller *can* orchestrate the environment required to make this issue visible, which a normal unprivileged user *cannot*. The lock in question is being held during a `try_to_freeze` operation, likely triggered by a user-mode helper being invoked to load a firmware file. This is a denial-of-service vulnerability. It's a deadlock during suspend/resume, which isn't a privilege escalation or memory corruption. The concern is about system availability.
I need to confirm whether any other methods invoke `devlink_compat_flash_update`, which is a likely candidate for the problem. I checked `dev_ethtool` and `devlink_nl_flash_update_doit`. Both require `CAP_NET_ADMIN`. So, they aren't accessible from unprivileged processes or user namespaces. A thorough search to identify any other callers of `devlink_compat_flash_update` reveals these are the *only* pathways.
Since we are talking about `request_firmware` here, I need to check if there is any condition that may cause a deadlock even without the suspend/resume flow. `request_firmware` does not need the `devlink` lock, as the lockdep warning is specifically from `debug_check_no_locks_held` in `try_to_freeze`, which is called when `request_firmware` falls back to sysfs and needs to invoke a usermode helper (i.e., fallback to `fw_load_from_user_helper` which ends up calling `usermodehelper_read_trylock`). `usermodehelper_read_trylock` calls `try_to_freeze` if `usermodehelper_disabled` is true (like in suspend/resume), resulting in a deadlock. This explains the lockdep warning.
Now I need to verify that `ETHTOOL_FLASHDEV` and `DEVLINK_CMD_FLASH_UPDATE` can't be called by unprivileged users. `ETHTOOL_FLASHDEV` requires `CAP_NET_ADMIN`, ruling out unprivileged access. The same holds for `devlink_nl_flash_update_doit`, which demands `GENL_ADMIN_PERM`, thereby making it inaccessible to unprivileged users, regardless of user namespace creation.
Therefore, the bug is not exploitable by unprivileged users. Even when they've created a user namespace, they cannot get `CAP_NET_ADMIN` on `netdevsim`, or access the `devlink` devices. Syzkaller can, however.
I'm confident in concluding:
* **Exploitable:** No
* **Denial of Service:** Yes
* **Accessible From Unprivileged Processes:** No
* **Accessible From User Namespaces:** No
* All other attack vectors (VM Guest, Host, Network, etc.) are **False**.
One final check. I need to be absolutely certain there are no other indirect paths to trigger `request_firmware` with `devl_lock` held. The only ways it can be triggered are through `devlink_compat_flash_update` or through `devlink_nl_flash_update_doit`. `devlink_nl_flash_update_doit` does not explicitly hold `devl_lock`, but may call functions that eventually do. I need to investigate that code path more carefully to be certain.
|
| 67/2 |
2026/07/30 00:12 |
tool |
codesearch-definition-source |
0m
Args: map[Name:devlink_nl_flash_update_doit]
Results: map[SourceCode:1133: int devlink_nl_flash_update_doit(struct sk_buff *skb, struct genl_info *info)
1134: {
1135: struct nlattr *nla_overwrite_mask, *nla_file_name;
1136: struct devlink_flash_update_params params = {};
1137: struct devlink *devlink = info->user_ptr[0];
1138: const char *file_name;
1139: u32 supported_params;
1140: int ret;
1141:
1142: if (!devlink->ops->flash_update)
1143: return -EOPNOTSUPP;
1144:
1145: if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME))
1146: return -EINVAL;
1147:
1148: ret = devlink_flash_component_get(devlink,
1149: info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT],
1150: ¶ms.component, info->extack);
1151: if (ret)
1152: return ret;
1153:
1154: supported_params = devlink->ops->supported_flash_update_params;
1155:
1156: nla_overwrite_mask = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK];
1157: if (nla_overwrite_mask) {
1158: struct nla_bitfield32 sections;
1159:
1160: if (!(supported_params & DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK)) {
1161: NL_SET_ERR_MSG_ATTR(info->extack, nla_overwrite_mask,
1162: "overwrite settings are not supported by this device");
1163: return -EOPNOTSUPP;
1164: }
1165: sections = nla_get_bitfield32(nla_overwrite_mask);
1166: params.overwrite_mask = sections.value & sections.selector;
1167: }
1168:
1169: nla_file_name = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME];
1170: file_name = nla_data(nla_file_name);
1171: ret = request_firmware(¶ms.fw, file_name, devlink->dev);
1172: if (ret) {
1173: NL_SET_ERR_MSG_ATTR(info->extack, nla_file_name,
1174: "failed to locate the requested firmware file");
1175: return ret;
1176: }
1177:
1178: devlink_flash_update_begin_notify(devlink);
1179: ret = devlink->ops->flash_update(devlink, ¶ms, info->extack);
1180: devlink_flash_update_end_notify(devlink);
1181:
1182: release_firmware(params.fw);
1183:
1184: return ret;
1185: }
SourceFile:net/devlink/dev.c]
|
| 68/2 |
2026/07/30 00:12 |
llm |
expert |
0m
Model:
Tokens:
input: 79054
output: 28
thoughts: 67
Thoughts: **Analyzing the Devlink Netlink Pre-Doit Flow**
Okay, so `devlink_nl_pre_doit` calls `__devlink_nl_pre_doit`. And it's calling it with `flags = 0`. That's interesting, because a flag value of zero always makes me pay attention. It probably means some default behavior is being selected. Let's see... `flags = 0` means that the `dev_lock` is false. This context seems important. I need to understand what happens when that lock isn't acquired. I'll need to dig into the `__devlink_nl_pre_doit` function itself to fully grasp the implications of this.
|
| 69/2 |
2026/07/30 00:12 |
tool |
codesearch-definition-source |
0m
Args: map[Name:__devlink_nl_pre_doit]
Results: map[SourceCode: 242: static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info,
243: u8 flags)
244: {
245: bool dev_lock = flags & DEVLINK_NL_FLAG_NEED_DEV_LOCK;
246: struct devlink_port *devlink_port;
247: struct devlink *devlink;
248: int err;
249:
250: devlink = devlink_get_from_attrs_lock(genl_info_net(info), info->attrs,
251: dev_lock);
252: if (IS_ERR(devlink))
253: return PTR_ERR(devlink);
254:
255: info->user_ptr[0] = devlink;
256: if (flags & DEVLINK_NL_FLAG_NEED_PORT) {
257: devlink_port = devlink_port_get_from_info(devlink, info);
258: if (IS_ERR(devlink_port)) {
259: err = PTR_ERR(devlink_port);
260: goto unlock;
261: }
262: info->user_ptr[1] = devlink_port;
263: } else if (flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
264: devlink_port = devlink_port_get_from_info(devlink, info);
265: if (!IS_ERR(devlink_port))
266: info->user_ptr[1] = devlink_port;
267: }
268: return 0;
269:
270: unlock:
271: devl_dev_unlock(devlink, dev_lock);
272: devlink_put(devlink);
273: return err;
274: }
SourceFile:net/devlink/netlink.c]
|
| 70/2 |
2026/07/30 00:12 |
llm |
expert |
0m
Model:
Tokens:
input: 79881
output: 24
thoughts: 78
Thoughts: Okay, let me break this down.
**Locking Behavior in `devlink_get_from_attrs_lock`**
Alright, so I'm looking at this `devlink_get_from_attrs_lock` function and the way it handles locking, specifically when it calls `devl_dev_lock`. The key is this `dev_lock` variable. If `dev_lock` is *false*, then `devlink_get_from_attrs_lock` is set up to NOT take the lock in the call to `devl_dev_lock(devlink, false)`.
But wait a minute, that's not quite right. My understanding of `devl_dev_lock` is that it *does* take the lock if `dev_lock` is *true*. So I've got to double-check this. There's probably a logical inversion somewhere or I'm missing something in the code path. I need to go look directly at the implementation of `devl_dev_lock` to make sure my assumptions are correct. Something's not quite clicking, so let's get that clarification.
|
| 71/2 |
2026/07/30 00:12 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 121: static inline void devl_dev_lock(struct devlink *devlink, bool dev_lock)
122: {
123: if (dev_lock && devlink->dev)
124: device_lock(devlink->dev);
125: devl_lock(devlink);
126: }
SourceFile:net/devlink/devl_internal.h]
|
| 72/2 |
2026/07/30 00:12 |
llm |
expert |
0m
Model:
Tokens:
input: 80355
output: 29
thoughts: 225
Thoughts: **Analyzing the Firmware Request Security Implications**
Okay, so it's becoming clear how `devl_dev_lock` is structured. It *always* grabs `devl_lock(devlink)`. The `dev_lock` parameter is just about whether it *also* locks the underlying device with `device_lock(devlink->dev)`. This means that `devlink_nl_flash_update_doit` *definitely* holds `devl_lock(devlink)`. And the kicker? It calls `request_firmware`. So both `dev_ethtool` and `devlink_nl_flash_update_doit` share the same locking structure and call the same firmware request function.
Both of these functions are protected by `CAP_NET_ADMIN`. This implies that, as is, this vulnerability isn't exploitable by an unprivileged user. That's good, but it's not the whole story.
I need to dig deeper. Are there *other* ways to trigger `request_firmware` while holding `devl_lock`? I need to consider the broader attack surface of the `devlink` subsystem. Let's look at the `devlink_nl_ops` structure. There are many commands within this structure. My next step is to methodically search through them and identify any other candidates that might call `request_firmware`, while also holding a `devl_lock`. Let's start by grepping the kernel sources within `net/devlink/` for calls to `request_firmware`. It's time to investigate further!
|
| 73/2 |
2026/07/30 00:12 |
tool |
grepper |
0m
Args: map[Expression:request_firmware PathPrefix:net/devlink/]
Results: map[Output:net/devlink/dev.c=1133=int devlink_nl_flash_update_doit(struct sk_buff *skb, struct genl_info *info)
--
net/devlink/dev.c-1170- file_name = nla_data(nla_file_name);
net/devlink/dev.c:1171: ret = request_firmware(¶ms.fw, file_name, devlink->dev);
net/devlink/dev.c-1172- if (ret) {
--
net/devlink/dev.c=1231=int devlink_compat_flash_update(struct devlink *devlink, const char *file_name)
--
net/devlink/dev.c-1246-
net/devlink/dev.c:1247: ret = request_firmware(¶ms.fw, file_name, devlink->dev);
net/devlink/dev.c-1248- if (ret)
]
|
| 74/2 |
2026/07/30 00:12 |
llm |
expert |
0m
Model:
Tokens:
input: 81213
output: 66
thoughts: 56
Thoughts: **My Assessment of the Flash Update Capabilities**
Okay, so I've looked into the mechanisms for handling flash updates. My analysis clearly points to only two relevant functions: `devlink_nl_flash_update_doit` and `devlink_compat_flash_update`. The critical thing here is that *both* of these functions require the `CAP_NET_ADMIN` capability. Given my deep understanding of the kernel security model, that's a *very* strong indicator. This immediately tells me that this functionality is definitively *not* accessible to any unprivileged users. There's no way around that requirement. Therefore, based on this investigation, I'm confident in my conclusions. I'm ready to submit these findings.
|
| 75/2 |
2026/07/30 00:13 |
tool |
set-results |
0m
Args: map[DenialOfService:true Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
Results: map[DenialOfService:true Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
|
| 76/2 |
2026/07/30 00:13 |
llm |
expert |
0m
Model:
Error:
|