| 0/0 |
2026/08/21 00:00 |
flow |
assessment-security |
58m
Results: map[DenialOfService:false Explanation:**Analysis of the Bug Report**
**1. Nature of the Bug:**
The bug report highlights a message: `BUG: Address 2001::1 on device lo is
missing its host route.`
Looking at the kernel source code in `net/ipv6/addrconf.c`, this message is
generated by a `pr_warn()` call inside `__ipv6_ifa_notify()`. This warning was
explicitly added in commit `2d819d250a13` ("ipv6: Handle missing host route in
__ipv6_ifa_notify") to safely handle a known race condition.
The race occurs when a network interface is brought UP (scheduling Duplicate
Address Detection via `addrconf_dad_work`) and then rapidly brought DOWN
(triggering `addrconf_ifdown`, which removes the host route). If the DAD work
executes after the route has been removed, it finds `ifp->rt` as NULL. Before
the commit, this led to a NULL pointer dereference. After the commit, the kernel
safely detects this state, skips the route insertion, and simply logs the
`pr_warn` message.
**2. Exploitability:**
**Not Exploitable.** The issue is purely a logged warning (`pr_warn`). The
kernel correctly handles the unexpected state by skipping the problematic code
path. There is no memory corruption, out-of-bounds access, use-after-free, or
information leak.
**3. Denial of Service (DoS):**
**No.** Because the message is generated via `pr_warn` (and not a `BUG()` or
`WARN()` macro), it does not halt the kernel, nor does it trigger a panic even
if `panic_on_warn` is enabled. It does not cause deadlocks or resource leaks.
The system continues to function normally. Syzbot likely flagged it solely
because the log string starts with the word "BUG: ".
**4. Accessible From Unprivileged Processes:**
**No.** Triggering this race requires the ability to configure IPv6 addresses
and toggle network interface administrative states (UP/DOWN). These operations
require the `CAP_NET_ADMIN` capability. A standard unprivileged user cannot
perform these actions in the initial network namespace.
**5. Accessible From User Namespaces:**
**Yes.** An unprivileged user can create a new user namespace and a new network
namespace (`CLONE_NEWUSER | CLONE_NEWNET`). Within this isolated environment,
the user gains `CAP_NET_ADMIN` over the namespace's virtual network interfaces
(like the loopback device `lo` mentioned in the report). They can then rapidly
toggle the interface state and assign IPv6 addresses to trigger the race
condition and print the warning to the kernel log. Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:true VMGuestTrigger:false VMHostTrigger:false]
|
| 1/1 |
2026/08/21 00:00 |
action |
syz-repro-to-c-repro |
0m
Results:
|
| 2/1 |
2026/08/21 00:00 |
action |
kernel-checkouter |
2m
Results: map[KernelSrc:/app/workdir/cache/src/f5595d388901b5dd08599fb7ce7435287817685d]
|
| 3/1 |
2026/08/21 00:03 |
action |
kernel-builder |
26m
Results: map[KernelObj:/app/workdir/cache/build/2d844afd3ba9c25c40ddca2c1b3389dee3c58d31]
|
| 4/1 |
2026/08/21 00:30 |
action |
codesearch-prepare |
15m
Results: map[Index:codesearch-index]
|
| 5/1 |
2026/08/21 00:45 |
agent |
expert |
14m
Model:
Results: map[DenialOfService:false Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:true VMGuestTrigger:false VMHostTrigger:false]
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:
IPv6: BUG: Address 2001::1 on device lo is missing its host route.
Reply: **Analysis of the Bug Report**
**1. Nature of the Bug:**
The bug report highlights a message: `BUG: Address 2001::1 on device lo is missing its host route.`
Looking at the kernel source code in `net/ipv6/addrconf.c`, this message is generated by a `pr_warn()` call inside `__ipv6_ifa_notify()`. This warning was explicitly added in commit `2d819d250a13` ("ipv6: Handle missing host route in __ipv6_ifa_notify") to safely handle a known race condition.
The race occurs when a network interface is brought UP (scheduling Duplicate Address Detection via `addrconf_dad_work`) and then rapidly brought DOWN (triggering `addrconf_ifdown`, which removes the host route). If the DAD work executes after the route has been removed, it finds `ifp->rt` as NULL. Before the commit, this led to a NULL pointer dereference. After the commit, the kernel safely detects this state, skips the route insertion, and simply logs the `pr_warn` message.
**2. Exploitability:**
**Not Exploitable.** The issue is purely a logged warning (`pr_warn`). The kernel correctly handles the unexpected state by skipping the problematic code path. There is no memory corruption, out-of-bounds access, use-after-free, or information leak.
**3. Denial of Service (DoS):**
**No.** Because the message is generated via `pr_warn` (and not a `BUG()` or `WARN()` macro), it does not halt the kernel, nor does it trigger a panic even if `panic_on_warn` is enabled. It does not cause deadlocks or resource leaks. The system continues to function normally. Syzbot likely flagged it solely because the log string starts with the word "BUG: ".
**4. Accessible From Unprivileged Processes:**
**No.** Triggering this race requires the ability to configure IPv6 addresses and toggle network interface administrative states (UP/DOWN). These operations require the `CAP_NET_ADMIN` capability. A standard unprivileged user cannot perform these actions in the initial network namespace.
**5. Accessible From User Namespaces:**
**Yes.** An unprivileged user can create a new user namespace and a new network namespace (`CLONE_NEWUSER | CLONE_NEWNET`). Within this isolated environment, the user gains `CAP_NET_ADMIN` over the namespace's virtual network interfaces (like the loopback device `lo` mentioned in the report). They can then rapidly toggle the interface state and assign IPv6 addresses to trigger the race condition and print the warning to the kernel log.
|
| 6/2 |
2026/08/21 00:45 |
llm |
expert |
0m
Model:
Tokens:
input: 5841
output: 24
thoughts: 60
Thoughts: Okay, here's my interpretation of that bug report and the initial steps I'd take, presented as a summary of my own thought process:
**Initial Investigation: IPv6 Host Route Missing**
Alright, a new bug report has landed: "IPv6: BUG: Address 2001::1 on device lo is missing its host route." Immediately, alarm bells are going off. An IPv6 address is missing its host route? That's not good, and it could cause all sorts of connectivity problems. My primary concern here is that the loopback interface, 'lo', which is often critical for local networking and testing, is having this issue.
First things first, I need to get a better handle on the root cause. This sounds like an error message originating from the kernel. The first thing I'm doing is to locate the source of that error message in the kernel code. I know I've seen similar diagnostics before, so I'll start by searching the source for that specific string: "Address %pI6c on device %s is missing its host route." That's the key to tracking down where this check is happening, and *why* it's happening. The '%pI6c' and '%s' indicate format specifiers that will let me see the exact IPv6 address and device name involved. Once I find that code, I'll be able to understand the circumstances under which the kernel thinks a route should exist but doesn't. This will allow me to narrow down the possible causes of this bug.
|
| 7/2 |
2026/08/21 00:45 |
tool |
grepper |
0m
Args: map[Expression:Address .* on device .* is missing its host route]
Results: map[Output:net/ipv6/addrconf.c=6298=static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
--
net/ipv6/addrconf.c-6319- } else if (!ifp->rt && (ifp->idev->dev->flags & IFF_UP)) {
net/ipv6/addrconf.c:6320: pr_warn("BUG: Address %pI6c on device %s is missing its host route.\n",
net/ipv6/addrconf.c-6321- &ifp->addr, ifp->idev->dev->name);
]
|
| 8/2 |
2026/08/21 00:45 |
llm |
expert |
0m
Model:
Tokens:
input: 6359
output: 40
thoughts: 85
Thoughts: Here's my summary, as though I'm thinking through this:
**Investigating a Missing Host Route Warning**
Okay, so I've got this warning message popping up: `pr_warn("BUG: Address %pI6c on device %s is missing its host route.\n", &ifp->addr, ifp->idev->dev->name);` in `net/ipv6/addrconf.c`. It's a "BUG", which always warrants a closer look. Something isn't right with an IPv6 address (`%pI6c`, likely the address itself) on a particular network interface (`%s`, the device name). Specifically, it seems a host route is missing for that address.
My immediate thought is to trace the flow, figure out *why* this host route isn't being created. Let's see what calls this `pr_warn` function and what can create an "address missing its host route" situation. I'll start by checking out `__ipv6_ifa_notify` function in `net/ipv6/addrconf.c` because it deals with IPv6 address notifications, which could be the source of the issue. That should be a good place to start digging into the call stack and data flow around this error. I need to understand how IPv6 addresses are configured, routes are established, and where things might be going awry.
|
| 9/2 |
2026/08/21 00:45 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/ipv6/addrconf.c Name:__ipv6_ifa_notify]
Results: map[SourceCode:6298: static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
6299: {
6300: struct net *net = dev_net(ifp->idev->dev);
6301:
6302: if (event)
6303: ASSERT_RTNL();
6304:
6305: inet6_ifa_notify(event ? : RTM_NEWADDR, ifp);
6306:
6307: switch (event) {
6308: case RTM_NEWADDR:
6309: /*
6310: * If the address was optimistic we inserted the route at the
6311: * start of our DAD process, so we don't need to do it again.
6312: * If the device was taken down in the middle of the DAD
6313: * cycle there is a race where we could get here without a
6314: * host route, so nothing to insert. That will be fixed when
6315: * the device is brought up.
6316: */
6317: if (ifp->rt && !rcu_access_pointer(ifp->rt->fib6_node)) {
6318: ip6_ins_rt(net, ifp->rt);
6319: } else if (!ifp->rt && (ifp->idev->dev->flags & IFF_UP)) {
6320: pr_warn("BUG: Address %pI6c on device %s is missing its host route.\n",
6321: &ifp->addr, ifp->idev->dev->name);
6322: }
6323:
6324: if (ifp->idev->cnf.forwarding)
6325: addrconf_join_anycast(ifp);
6326: if (!ipv6_addr_any(&ifp->peer_addr))
6327: addrconf_prefix_route(&ifp->peer_addr, 128,
6328: ifp->rt_priority, ifp->idev->dev,
6329: 0, 0, GFP_ATOMIC);
6330: break;
6331: case RTM_DELADDR:
6332: if (ifp->idev->cnf.forwarding)
6333: addrconf_leave_anycast(ifp);
6334: addrconf_leave_solict(ifp->idev, &ifp->addr);
6335: if (!ipv6_addr_any(&ifp->peer_addr)) {
6336: struct fib6_info *rt;
6337:
6338: rt = addrconf_get_prefix_route(&ifp->peer_addr, 128,
6339: ifp->idev->dev, 0, 0,
6340: false);
6341: if (rt)
6342: ip6_del_rt(net, rt, false);
6343: }
6344: if (ifp->rt) {
6345: ip6_del_rt(net, ifp->rt, false);
6346: ifp->rt = NULL;
6347: }
6348: rt_genid_bump_ipv6(net);
6349: break;
6350: }
6351: atomic_inc(&net->ipv6.dev_addr_genid);
6352: }
SourceFile:net/ipv6/addrconf.c]
|
| 10/2 |
2026/08/21 00:45 |
llm |
expert |
0m
Model:
Tokens:
input: 7661
output: 53
thoughts: 411
Thoughts: **Analyzing a Potential IPv6 Bug**
Okay, so I'm looking at this `pr_warn` in `__ipv6_ifa_notify` within `net/ipv6/addrconf.c`. Right, it's a warning, not a kernel panic β that's the first thing to note. No immediate crash, so the severity is lower. But can it be exploited? It's flagging a missing host route for an IPv6 address. That alone doesn't sound inherently dangerous.
Denial of service? Well, a warning usually doesn't cause a system-wide outage. It *could* mean the address is unreachable, which might be a localized DoS for that specific address, but not a catastrophic one. Hold on, though... it could *potentially* trigger a panic if `panic_on_warn` is enabled. But in a typical production scenario, we're assuming that's not the case. This is an important distinction.
Alright, moving on to privileges. My initial thought is IPv6 address configuration usually necessitates `CAP_NET_ADMIN`. Can unprivileged processes get to this? User namespaces! Yes, with user namespaces, you *can* gain `CAP_NET_ADMIN` and potentially configure IPv6 addresses on devices like loopback or veth.
So, user namespaces open the door. But the prompt specifies, "Assume that user namespaces are not accessible". Okay, so without user namespaces, unprivileged processes *cannot* directly configure IPv6 addresses. Makes sense.
But wait, hold on... Can an unprivileged process trigger this via an indirect method? Could sending some rogue IPv6 packets, like router advertisements, do it? Let's trace how `__ipv6_ifa_notify` is called to figure this out. I have to look deeper to see if something else could be creating a network condition where this warning gets triggered.
|
| 11/2 |
2026/08/21 00:45 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:net/ipv6/addrconf.c IncludeSnippetLines:0 Name:__ipv6_ifa_notify SourceTreePrefix:]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_ifdown SourceFile:net/ipv6/addrconf.c SourceLine:4012] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ipv6_ifa_notify SourceFile:net/ipv6/addrconf.c SourceLine:6357]] TruncatedOutput:false]
|
| 12/2 |
2026/08/21 00:45 |
llm |
expert |
0m
Model:
Tokens:
input: 8235
output: 39
thoughts: 553
Thoughts: **Analyzing a Kernel Warning: Missing Host Route in IPv6**
Okay, so there's a `pr_warn` in `__ipv6_ifa_notify` β specifically, a warning about a missing host route for an IPv6 address. It says: "BUG: Address %pI6c on device %s is missing its host route." Crucially, it's just a warning, not a panic or `BUG_ON`, so it's not immediately catastrophic. But is it indicative of a more serious underlying problem? My immediate focus is on whether this leads to a denial of service, or, even worse, a potential exploit.
The warning itself doesn't crash the kernel, and it's just about a *missing* route, so there's no obvious avenue for memory corruption. It's *just* a missing route.
Is it exploitable? Probably not. Denial of Service? Still, probably not, it's just a missing route, right?
But *can* this be triggered from unprivileged processes? That's the key question. I need to figure out how `__ipv6_ifa_notify` is called. It looks like it's called via `ipv6_ifa_notify` and `addrconf_ifdown`. And `ipv6_ifa_notify` gets called by things like `addrconf_dad_completed`, `addrconf_dad_work`, `ipv6_add_addr`, `ipv6_del_addr`, the usual IPv6 address management routines.
Adding/removing IPv6 addresses generally requires `CAP_NET_ADMIN`. But, ah, a user in a user namespace can have `CAP_NET_ADMIN`, which *does* make it accessible to unprivileged processes, potentially. So, it *is* accessible from user namespaces.
However, typically, an unprivileged user can't trigger this condition directly. *Unless*... wait, what about Stateless Address Autoconfiguration (SLAAC)? Can that be a backdoor? That's it! SLAAC can add IPv6 addresses. Can a remote attacker or even a local unprivileged user trigger SLAAC and exploit this missing route warning?
Yes, they *could* by sending Router Advertisements (RAs). If an unprivileged user can send RAs, they can, in effect, add addresses. Usually, sending raw packets would be required, and that needs `CAP_NET_RAW`. But a remote attacker or someone on the same network... there's an attack vector there.
So, *Ethernet Network Trigger*: *Yes*.
Now, let's nail down the exact conditions for this warning to appear: `if (!ifp->rt && (ifp->idev->dev->flags & IFF_UP))`. Essentially, the route is missing and the device is up. When would `ifp->rt` be null? That route (`ifp->rt`) is the host route for the address and it is allocated in `ipv6_add_addr`. Okay, let's keep digging and find the exact path to trigger this!
|
| 13/2 |
2026/08/21 00:46 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/ipv6/addrconf.c Name:ipv6_add_addr]
Results: map[SourceCode:1073: static struct inet6_ifaddr *
1074: ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg,
1075: bool can_block, struct netlink_ext_ack *extack)
1076: {
1077: gfp_t gfp_flags = can_block ? GFP_KERNEL : GFP_ATOMIC;
1078: int addr_type = ipv6_addr_type(cfg->pfx);
1079: struct net *net = dev_net(idev->dev);
1080: struct inet6_ifaddr *ifa = NULL;
1081: struct fib6_info *f6i = NULL;
1082: int err = 0;
1083:
1084: if (addr_type == IPV6_ADDR_ANY) {
1085: NL_SET_ERR_MSG_MOD(extack, "Invalid address");
1086: return ERR_PTR(-EADDRNOTAVAIL);
1087: } else if (addr_type & IPV6_ADDR_MULTICAST &&
1088: !(cfg->ifa_flags & IFA_F_MCAUTOJOIN)) {
1089: NL_SET_ERR_MSG_MOD(extack, "Cannot assign multicast address without \"IFA_F_MCAUTOJOIN\" flag");
1090: return ERR_PTR(-EADDRNOTAVAIL);
1091: } else if (!(idev->dev->flags & IFF_LOOPBACK) &&
1092: !netif_is_l3_master(idev->dev) &&
1093: addr_type & IPV6_ADDR_LOOPBACK) {
1094: NL_SET_ERR_MSG_MOD(extack, "Cannot assign loopback address on this device");
1095: return ERR_PTR(-EADDRNOTAVAIL);
1096: }
1097:
1098: if (idev->dead) {
1099: NL_SET_ERR_MSG_MOD(extack, "device is going away");
1100: err = -ENODEV;
1101: goto out;
1102: }
1103:
1104: if (idev->cnf.disable_ipv6) {
1105: NL_SET_ERR_MSG_MOD(extack, "IPv6 is disabled on this device");
1106: err = -EACCES;
1107: goto out;
1108: }
1109:
1110: /* validator notifier needs to be blocking;
1111: * do not call in atomic context
1112: */
1113: if (can_block) {
1114: struct in6_validator_info i6vi = {
1115: .i6vi_addr = *cfg->pfx,
1116: .i6vi_dev = idev,
1117: .extack = extack,
1118: };
1119:
1120: err = inet6addr_validator_notifier_call_chain(NETDEV_UP, &i6vi);
1121: err = notifier_to_errno(err);
1122: if (err < 0)
1123: goto out;
1124: }
1125:
1126: ifa = kzalloc_obj(*ifa, gfp_flags | __GFP_ACCOUNT);
1127: if (!ifa) {
1128: err = -ENOBUFS;
1129: goto out;
1130: }
1131:
1132: f6i = addrconf_f6i_alloc(net, idev, cfg->pfx, false, gfp_flags, extack);
1133: if (IS_ERR(f6i)) {
1134: err = PTR_ERR(f6i);
1135: f6i = NULL;
1136: goto out;
1137: }
1138:
1139: neigh_parms_data_state_setall(idev->nd_parms);
1140:
1141: ifa->addr = *cfg->pfx;
1142: if (cfg->peer_pfx)
1143: ifa->peer_addr = *cfg->peer_pfx;
1144:
1145: spin_lock_init(&ifa->lock);
1146: INIT_DELAYED_WORK(&ifa->dad_work, addrconf_dad_work);
1147: INIT_HLIST_NODE(&ifa->addr_lst);
1148: ifa->scope = cfg->scope;
1149: ifa->prefix_len = cfg->plen;
1150: ifa->rt_priority = cfg->rt_priority;
1151: ifa->flags = cfg->ifa_flags;
1152: ifa->ifa_proto = cfg->ifa_proto;
1153: /* No need to add the TENTATIVE flag for addresses with NODAD */
1154: if (!(cfg->ifa_flags & IFA_F_NODAD))
1155: ifa->flags |= IFA_F_TENTATIVE;
1156: ifa->valid_lft = cfg->valid_lft;
1157: ifa->prefered_lft = cfg->preferred_lft;
1158: ifa->cstamp = ifa->tstamp = jiffies;
1159: ifa->tokenized = false;
1160:
1161: ifa->rt = f6i;
1162:
1163: ifa->idev = idev;
1164: in6_dev_hold(idev);
1165:
1166: /* For caller */
1167: refcount_set(&ifa->refcnt, 1);
1168:
1169: rcu_read_lock();
1170:
1171: err = ipv6_add_addr_hash(idev->dev, ifa);
1172: if (err < 0) {
1173: rcu_read_unlock();
1174: goto out;
1175: }
1176:
1177: write_lock_bh(&idev->lock);
1178:
1179: /* Add to inet6_dev unicast addr list. */
1180: ipv6_link_dev_addr(idev, ifa);
1181:
1182: if (ifa->flags&IFA_F_TEMPORARY) {
1183: /* manage_tempaddrs() relies on addresses being added to the head */
1184: list_add(&ifa->tmp_list, &idev->tempaddr_list);
1185: in6_ifa_hold(ifa);
1186: }
1187:
1188: in6_ifa_hold(ifa);
1189: write_unlock_bh(&idev->lock);
1190:
1191: rcu_read_unlock();
1192:
1193: inet6addr_notifier_call_chain(NETDEV_UP, ifa);
1194: out:
1195: if (unlikely(err < 0)) {
1196: fib6_info_release(f6i);
1197:
1198: if (ifa) {
1199: if (ifa->idev)
1200: in6_dev_put(ifa->idev);
1201: kfree(ifa);
1202: }
1203: ifa = ERR_PTR(err);
1204: }
1205:
1206: return ifa;
1207: }
SourceFile:net/ipv6/addrconf.c]
|
| 14/2 |
2026/08/21 00:46 |
llm |
expert |
0m
Model:
Tokens:
input: 11064
output: 52
thoughts: 0
|
| 15/2 |
2026/08/21 00:46 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:net/ipv6/addrconf.c IncludeSnippetLines:0 Name:ipv6_add_addr SourceTreePrefix:]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:add_addr SourceFile:net/ipv6/addrconf.c SourceLine:3224] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_add_linklocal SourceFile:net/ipv6/addrconf.c SourceLine:3334] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_dad_failure SourceFile:net/ipv6/addrconf.c SourceLine:2224] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_prefix_rcv_add_addr SourceFile:net/ipv6/addrconf.c SourceLine:2729] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:inet6_addr_add SourceFile:net/ipv6/addrconf.c SourceLine:3073] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ipv6_create_tempaddr SourceFile:net/ipv6/addrconf.c SourceLine:1491]] TruncatedOutput:false]
|
| 16/2 |
2026/08/21 00:46 |
llm |
expert |
0m
Model:
Tokens:
input: 11458
output: 67
thoughts: 0
|
| 17/2 |
2026/08/21 00:46 |
tool |
git-log |
10m
Error:
Args: map[CodeRegexp:BUG: Address %pI6c on device %s is missing its host route Count:10 MessageRegexps:[] PathPrefix: Since: SourcePath: SymbolName:]
Results:
|
| 18/2 |
2026/08/21 00:56 |
llm |
expert |
0m
Model:
Tokens:
input: 11560
output: 76
thoughts: 0
|
| 19/2 |
2026/08/21 00:56 |
tool |
git-log |
0m
Args: map[CodeRegexp:BUG: Address %pI6c on device %s is missing its host route Count:10 MessageRegexps:[] PathPrefix:net/ipv6/addrconf.c Since: SourcePath: SymbolName:]
Results: map[Output:2d819d250a13 ipv6: Handle missing host route in __ipv6_ifa_notify
]
|
| 20/2 |
2026/08/21 00:56 |
llm |
expert |
0m
Model:
Tokens:
input: 11677
output: 27
thoughts: 0
|
| 21/2 |
2026/08/21 00:56 |
tool |
git-show |
0m
Args:
Results: map[Output:commit 2d819d250a1393a3e725715425ab70a0e0772a71
Author: David Ahern <dsahern@gmail.com>
Date: Fri Oct 4 08:03:09 2019 -0700
ipv6: Handle missing host route in __ipv6_ifa_notify
Rajendra reported a kernel panic when a link was taken down:
[ 6870.263084] BUG: unable to handle kernel NULL pointer dereference at 00000000000000a8
[ 6870.271856] IP: [<ffffffff8efc5764>] __ipv6_ifa_notify+0x154/0x290
<snip>
[ 6870.570501] Call Trace:
[ 6870.573238] [<ffffffff8efc58c6>] ? ipv6_ifa_notify+0x26/0x40
[ 6870.579665] [<ffffffff8efc98ec>] ? addrconf_dad_completed+0x4c/0x2c0
[ 6870.586869] [<ffffffff8efe70c6>] ? ipv6_dev_mc_inc+0x196/0x260
[ 6870.593491] [<ffffffff8efc9c6a>] ? addrconf_dad_work+0x10a/0x430
[ 6870.600305] [<ffffffff8f01ade4>] ? __switch_to_asm+0x34/0x70
[ 6870.606732] [<ffffffff8ea93a7a>] ? process_one_work+0x18a/0x430
[ 6870.613449] [<ffffffff8ea93d6d>] ? worker_thread+0x4d/0x490
[ 6870.619778] [<ffffffff8ea93d20>] ? process_one_work+0x430/0x430
[ 6870.626495] [<ffffffff8ea99dd9>] ? kthread+0xd9/0xf0
[ 6870.632145] [<ffffffff8f01ade4>] ? __switch_to_asm+0x34/0x70
[ 6870.638573] [<ffffffff8ea99d00>] ? kthread_park+0x60/0x60
[ 6870.644707] [<ffffffff8f01ae77>] ? ret_from_fork+0x57/0x70
[ 6870.650936] Code: 31 c0 31 d2 41 b9 20 00 08 02 b9 09 00 00 0
addrconf_dad_work is kicked to be scheduled when a device is brought
up. There is a race between addrcond_dad_work getting scheduled and
taking the rtnl lock and a process taking the link down (under rtnl).
The latter removes the host route from the inet6_addr as part of
addrconf_ifdown which is run for NETDEV_DOWN. The former attempts
to use the host route in __ipv6_ifa_notify. If the down event removes
the host route due to the race to the rtnl, then the BUG listed above
occurs.
Since the DAD sequence can not be aborted, add a check for the missing
host route in __ipv6_ifa_notify. The only way this should happen is due
to the previously mentioned race. The host route is created when the
address is added to an interface; it is only removed on a down event
where the address is kept. Add a warning if the host route is missing
AND the device is up; this is a situation that should never happen.
Fixes: f1705ec197e7 ("net: ipv6: Make address flushing on ifdown optional")
Reported-by: Rajendra Dendukuri <rajendra.dendukuri@broadcom.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 6a576ff92c39..34ccef18b40e 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -5964,13 +5964,20 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
switch (event) {
case RTM_NEWADDR:
/*
- * If the address was optimistic
- * we inserted the route at the start of
- * our DAD process, so we don't need
- * to do it again
+ * If the address was optimistic we inserted the route at the
+ * start of our DAD process, so we don't need to do it again.
+ * If the device was taken down in the middle of the DAD
+ * cycle there is a race where we could get here without a
+ * host route, so nothing to insert. That will be fixed when
+ * the device is brought up.
*/
- if (!rcu_access_pointer(ifp->rt->fib6_node))
+ if (ifp->rt && !rcu_access_pointer(ifp->rt->fib6_node)) {
ip6_ins_rt(net, ifp->rt);
+ } else if (!ifp->rt && (ifp->idev->dev->flags & IFF_UP)) {
+ pr_warn("BUG: Address %pI6c on device %s is missing its host route.\n",
+ &ifp->addr, ifp->idev->dev->name);
+ }
+
if (ifp->idev->cnf.forwarding)
addrconf_join_anycast(ifp);
if (!ipv6_addr_any(&ifp->peer_addr))
]
|
| 22/2 |
2026/08/21 00:56 |
llm |
expert |
0m
Model:
Tokens:
input: 13392
output: 38
thoughts: 1360
Thoughts: **Analysis of IPv6 Host Route Missing Warning**
Okay, so the bug report points to a warning in `net/ipv6/addrconf.c`: "BUG: Address ... is missing its host route." This warning was added in commit `2d819d250a1393a3e725715425ab70a0e0772a71` to address a race condition. The race involves `addrconf_dad_work` (Duplicate Address Detection work) being scheduled while a process might concurrently take the network link down, removing the host route.
The code's intent is clear: it *detects* a situation that "should never happen" β a missing host route for an active interface. Importantly, it's just a `pr_warn`, a kernel print. It doesn't trigger a kernel panic, even if `panic_on_warn` is enabled (because it's just `pr_warn`, not a `WARN_ON`). This is key; it's not a crash or a kernel vulnerability *per se*. It's a diagnostic.
The code checks `ifp->rt` for NULL, and if it's NULL, the warning is printed and the routing lookup for the address is skipped. However, other operations are still done. Specifically, `addrconf_join_anycast` and `addrconf_prefix_route` are called afterwards. Critically, there's no attempt to dereference `ifp->rt` after the warning, so there's no immediate use-after-free or other obvious crash condition.
The next question becomes whether it could lead to a denial of service (DoS) or memory leak. The missing host route means traffic destined to that specific IPv6 address might not be routed correctly. However, this impacts only a single address on a device. Furthermore, to trigger this race, an unprivileged user needs `CAP_NET_ADMIN` to configure IPv6 addresses and toggle interfaces up/down. This could be achieved inside a user namespace.
Can an *unprivileged* user trigger this? No, outside of a user namespace. It requires `CAP_NET_ADMIN`. Can a remote attacker trigger this? Not directly. While an unprivileged user on the same network *could* potentially trigger SLAAC (Stateless Address Autoconfiguration) or RA (Router Advertisement) to add an address, they cannot easily toggle the interface up/down which requires `CAP_NET_ADMIN` required to trigger the race. VMs are also not directly vulnerable.
The vulnerability is therefore localized to local users, or user-namespaces, that could potentially cause a single `printk` that would trigger this race, so the severity is low.
So, let's recap:
* The bug report is a *false positive* essentially.
* It's a warning triggered by a race condition, but is not exploitable.
* It doesn't crash, hang, or leak memory.
* It might cause intermittent routing issues for a *single* IPv6 address on an interface if the host route is missing.
* It can be triggered by a local unprivileged user inside a user namespace that has `CAP_NET_ADMIN`.
* It cannot be triggered remotely.
* It is not a DoS because it's just a `printk`.
* The warning is likely caught by syzbot because of the "BUG: " string in the message, so the report is a false positive.
|
| 23/2 |
2026/08/21 00:56 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/ipv6/addrconf.c Name:addrconf_ifdown]
Results: map[SourceCode:3875: static int addrconf_ifdown(struct net_device *dev, bool unregister)
3876: {
3877: unsigned long event = unregister ? NETDEV_UNREGISTER : NETDEV_DOWN;
3878: struct net *net = dev_net(dev);
3879: struct inet6_dev *idev;
3880: struct inet6_ifaddr *ifa;
3881: LIST_HEAD(tmp_addr_list);
3882: bool keep_addr = false;
3883: bool was_ready;
3884: int state, i;
3885:
3886: ASSERT_RTNL();
3887:
3888: rt6_disable_ip(dev, event);
3889:
3890: idev = __in6_dev_get(dev);
3891: if (!idev)
3892: return -ENODEV;
3893:
3894: /*
3895: * Step 1: remove reference to ipv6 device from parent device.
3896: * Do not dev_put!
3897: */
3898: if (unregister) {
3899: WRITE_ONCE(idev->dead, 1);
3900:
3901: /* protected by rtnl_lock */
3902: RCU_INIT_POINTER(dev->ip6_ptr, NULL);
3903:
3904: /* Step 1.5: remove snmp6 entry */
3905: snmp6_unregister_dev(idev);
3906:
3907: }
3908:
3909: /* combine the user config with event to determine if permanent
3910: * addresses are to be removed from address hash table
3911: */
3912: if (!unregister && !idev->cnf.disable_ipv6) {
3913: /* aggregate the system setting and interface setting */
3914: int _keep_addr = READ_ONCE(net->ipv6.devconf_all->keep_addr_on_down);
3915:
3916: if (!_keep_addr)
3917: _keep_addr = READ_ONCE(idev->cnf.keep_addr_on_down);
3918:
3919: keep_addr = (_keep_addr > 0);
3920: }
3921:
3922: /* Step 2: clear hash table */
3923: for (i = 0; i < IN6_ADDR_HSIZE; i++) {
3924: struct hlist_head *h = &net->ipv6.inet6_addr_lst[i];
3925:
3926: spin_lock_bh(&net->ipv6.addrconf_hash_lock);
3927: restart:
3928: hlist_for_each_entry_rcu(ifa, h, addr_lst) {
3929: if (ifa->idev == idev) {
3930: addrconf_del_dad_work(ifa);
3931: /* combined flag + permanent flag decide if
3932: * address is retained on a down event
3933: */
3934: if (!keep_addr ||
3935: !(ifa->flags & IFA_F_PERMANENT) ||
3936: addr_is_local(&ifa->addr)) {
3937: hlist_del_init_rcu(&ifa->addr_lst);
3938: goto restart;
3939: }
3940: }
3941: }
3942: spin_unlock_bh(&net->ipv6.addrconf_hash_lock);
3943: }
3944:
3945: write_lock_bh(&idev->lock);
3946:
3947: addrconf_del_rs_timer(idev);
3948:
3949: /* Step 2: clear flags for stateless addrconf, repeated down
3950: * detection
3951: */
3952: was_ready = idev->if_flags & IF_READY;
3953: if (!unregister)
3954: idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY);
3955:
3956: /* Step 3: clear tempaddr list */
3957: while (!list_empty(&idev->tempaddr_list)) {
3958: ifa = list_first_entry(&idev->tempaddr_list,
3959: struct inet6_ifaddr, tmp_list);
3960: list_del(&ifa->tmp_list);
3961: write_unlock_bh(&idev->lock);
3962: spin_lock_bh(&ifa->lock);
3963:
3964: if (ifa->ifpub) {
3965: in6_ifa_put(ifa->ifpub);
3966: ifa->ifpub = NULL;
3967: }
3968: spin_unlock_bh(&ifa->lock);
3969: in6_ifa_put(ifa);
3970: write_lock_bh(&idev->lock);
3971: }
3972:
3973: list_for_each_entry(ifa, &idev->addr_list, if_list)
3974: list_add_tail(&ifa->if_list_aux, &tmp_addr_list);
3975: write_unlock_bh(&idev->lock);
3976:
3977: while (!list_empty(&tmp_addr_list)) {
3978: struct fib6_info *rt = NULL;
3979: bool keep;
3980:
3981: ifa = list_first_entry(&tmp_addr_list,
3982: struct inet6_ifaddr, if_list_aux);
3983: list_del(&ifa->if_list_aux);
3984:
3985: addrconf_del_dad_work(ifa);
3986:
3987: keep = keep_addr && (ifa->flags & IFA_F_PERMANENT) &&
3988: !addr_is_local(&ifa->addr);
3989:
3990: spin_lock_bh(&ifa->lock);
3991:
3992: if (keep) {
3993: /* set state to skip the notifier below */
3994: state = INET6_IFADDR_STATE_DEAD;
3995: ifa->state = INET6_IFADDR_STATE_PREDAD;
3996: if (!(ifa->flags & IFA_F_NODAD))
3997: ifa->flags |= IFA_F_TENTATIVE;
3998:
3999: rt = ifa->rt;
4000: ifa->rt = NULL;
4001: } else {
4002: state = ifa->state;
4003: ifa->state = INET6_IFADDR_STATE_DEAD;
4004: }
4005:
4006: spin_unlock_bh(&ifa->lock);
4007:
4008: if (rt)
4009: ip6_del_rt(net, rt, false);
4010:
4011: if (state != INET6_IFADDR_STATE_DEAD) {
4012: __ipv6_ifa_notify(RTM_DELADDR, ifa);
4013: inet6addr_notifier_call_chain(NETDEV_DOWN, ifa);
4014: } else {
4015: if (idev->cnf.forwarding)
4016: addrconf_leave_anycast(ifa);
4017: addrconf_leave_solict(ifa->idev, &ifa->addr);
4018: }
4019:
4020: if (!keep) {
4021: write_lock_bh(&idev->lock);
4022: list_del_rcu(&ifa->if_list);
4023: write_unlock_bh(&idev->lock);
4024: in6_ifa_put(ifa);
4025: }
4026: }
4027:
4028: /* Step 5: Discard anycast and multicast list */
4029: if (unregister) {
4030: ipv6_ac_destroy_dev(idev);
4031: ipv6_mc_destroy_dev(idev);
4032: } else if (was_ready) {
4033: ipv6_mc_down(idev);
4034: }
4035:
4036: WRITE_ONCE(idev->tstamp, jiffies);
4037: idev->ra_mtu = 0;
4038:
4039: /* Last: Shot the device (if unregistered) */
4040: if (unregister) {
4041: addrconf_sysctl_unregister(idev);
4042: neigh_parms_release(&nd_tbl, idev->nd_parms);
4043: neigh_ifdown(&nd_tbl, dev);
4044: in6_dev_put(idev);
4045: }
4046: return 0;
4047: }
SourceFile:net/ipv6/addrconf.c]
|
| 24/2 |
2026/08/21 00:56 |
llm |
expert |
0m
Model:
Tokens:
input: 16784
output: 51
thoughts: 0
|
| 25/2 |
2026/08/21 00:56 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:net/ipv6/addrconf.c IncludeSnippetLines:0 Name:addrconf_ifdown SourceTreePrefix:]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_cleanup SourceFile:net/ipv6/addrconf.c SourceLine:7656] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_cleanup SourceFile:net/ipv6/addrconf.c SourceLine:7658] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_dad_work SourceFile:net/ipv6/addrconf.c SourceLine:4268] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_notify SourceFile:net/ipv6/addrconf.c SourceLine:3694] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_notify SourceFile:net/ipv6/addrconf.c SourceLine:3802] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_notify SourceFile:net/ipv6/addrconf.c SourceLine:3811] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_notify SourceFile:net/ipv6/addrconf.c SourceLine:3842]] TruncatedOutput:false]
|
| 26/2 |
2026/08/21 00:56 |
llm |
expert |
0m
Model:
Tokens:
input: 17214
output: 39
thoughts: 0
|
| 27/2 |
2026/08/21 00:56 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/ipv6/addrconf.c Name:addrconf_dad_work]
Results: map[SourceCode:4211: static void addrconf_dad_work(struct work_struct *w)
4212: {
4213: struct inet6_ifaddr *ifp = container_of(to_delayed_work(w),
4214: struct inet6_ifaddr,
4215: dad_work);
4216: struct inet6_dev *idev = ifp->idev;
4217: bool bump_id, disable_ipv6 = false;
4218: struct in6_addr mcaddr;
4219: struct net *net;
4220:
4221: enum {
4222: DAD_PROCESS,
4223: DAD_BEGIN,
4224: DAD_ABORT,
4225: } action = DAD_PROCESS;
4226:
4227: net = dev_net(idev->dev);
4228:
4229: rtnl_net_lock(net);
4230:
4231: spin_lock_bh(&ifp->lock);
4232: if (ifp->state == INET6_IFADDR_STATE_PREDAD) {
4233: action = DAD_BEGIN;
4234: ifp->state = INET6_IFADDR_STATE_DAD;
4235: } else if (ifp->state == INET6_IFADDR_STATE_ERRDAD) {
4236: action = DAD_ABORT;
4237: ifp->state = INET6_IFADDR_STATE_POSTDAD;
4238:
4239: if ((READ_ONCE(net->ipv6.devconf_all->accept_dad) > 1 ||
4240: READ_ONCE(idev->cnf.accept_dad) > 1) &&
4241: !idev->cnf.disable_ipv6 &&
4242: !(ifp->flags & IFA_F_STABLE_PRIVACY)) {
4243: struct in6_addr addr;
4244:
4245: addr.s6_addr32[0] = htonl(0xfe800000);
4246: addr.s6_addr32[1] = 0;
4247:
4248: if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) &&
4249: ipv6_addr_equal(&ifp->addr, &addr)) {
4250: /* DAD failed for link-local based on MAC */
4251: WRITE_ONCE(idev->cnf.disable_ipv6, 1);
4252:
4253: pr_info("%s: IPv6 being disabled!\n",
4254: ifp->idev->dev->name);
4255: disable_ipv6 = true;
4256: }
4257: }
4258: }
4259: spin_unlock_bh(&ifp->lock);
4260:
4261: if (action == DAD_BEGIN) {
4262: addrconf_dad_begin(ifp);
4263: goto out;
4264: } else if (action == DAD_ABORT) {
4265: in6_ifa_hold(ifp);
4266: addrconf_dad_stop(ifp, 1);
4267: if (disable_ipv6)
4268: addrconf_ifdown(idev->dev, false);
4269: goto out;
4270: }
4271:
4272: if (!ifp->dad_probes && addrconf_dad_end(ifp))
4273: goto out;
4274:
4275: write_lock_bh(&idev->lock);
4276: if (idev->dead || !(idev->if_flags & IF_READY)) {
4277: write_unlock_bh(&idev->lock);
4278: goto out;
4279: }
4280:
4281: spin_lock(&ifp->lock);
4282: if (ifp->state == INET6_IFADDR_STATE_DEAD) {
4283: spin_unlock(&ifp->lock);
4284: write_unlock_bh(&idev->lock);
4285: goto out;
4286: }
4287:
4288: if (ifp->dad_probes == 0) {
4289: bool send_na = false;
4290:
4291: /*
4292: * DAD was successful
4293: */
4294:
4295: if (ifp->flags & IFA_F_TENTATIVE &&
4296: !(ifp->flags & IFA_F_OPTIMISTIC))
4297: send_na = true;
4298: bump_id = ifp->flags & IFA_F_TENTATIVE;
4299: ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
4300: spin_unlock(&ifp->lock);
4301: write_unlock_bh(&idev->lock);
4302:
4303: addrconf_dad_completed(ifp, bump_id, send_na);
4304:
4305: goto out;
4306: }
4307:
4308: ifp->dad_probes--;
4309: addrconf_mod_dad_work(ifp,
4310: max(NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME),
4311: HZ/100));
4312: spin_unlock(&ifp->lock);
4313: write_unlock_bh(&idev->lock);
4314:
4315: /* send a neighbour solicitation for our addr */
4316: addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
4317: ndisc_send_ns(ifp->idev->dev, &ifp->addr, &mcaddr, &in6addr_any,
4318: ifp->dad_nonce);
4319: out:
4320: in6_ifa_put(ifp);
4321: rtnl_net_unlock(net);
4322: }
SourceFile:net/ipv6/addrconf.c]
|
| 28/2 |
2026/08/21 00:56 |
llm |
expert |
0m
Model:
Tokens:
input: 19045
output: 52
thoughts: 0
|
| 29/2 |
2026/08/21 00:56 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:net/ipv6/addrconf.c IncludeSnippetLines:0 Name:addrconf_dad_work SourceTreePrefix:]
Results: map[References:[map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:ipv6_add_addr SourceFile:net/ipv6/addrconf.c SourceLine:1146]] TruncatedOutput:false]
|
| 30/2 |
2026/08/21 00:56 |
llm |
expert |
0m
Model:
Tokens:
input: 19174
output: 39
thoughts: 0
|
| 31/2 |
2026/08/21 00:56 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/ipv6/addrconf.c Name:addrconf_dad_completed]
Results: map[SourceCode:4342: static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id,
4343: bool send_na)
4344: {
4345: struct net_device *dev = ifp->idev->dev;
4346: struct in6_addr lladdr;
4347: bool send_rs, send_mld;
4348:
4349: addrconf_del_dad_work(ifp);
4350:
4351: /*
4352: * Configure the address for reception. Now it is valid.
4353: */
4354:
4355: ipv6_ifa_notify(RTM_NEWADDR, ifp);
4356:
4357: /* If added prefix is link local and we are prepared to process
4358: router advertisements, start sending router solicitations.
4359: */
4360:
4361: read_lock_bh(&ifp->idev->lock);
4362: send_mld = ifp->scope == IFA_LINK && ipv6_lonely_lladdr(ifp);
4363: send_rs = send_mld &&
4364: ipv6_accept_ra(ifp->idev) &&
4365: READ_ONCE(ifp->idev->cnf.rtr_solicits) != 0 &&
4366: (dev->flags & IFF_LOOPBACK) == 0 &&
4367: (dev->type != ARPHRD_TUNNEL) &&
4368: !netif_is_team_port(dev);
4369: read_unlock_bh(&ifp->idev->lock);
4370:
4371: /* While dad is in progress mld report's source address is in6_addrany.
4372: * Resend with proper ll now.
4373: */
4374: if (send_mld)
4375: ipv6_mc_dad_complete(ifp->idev);
4376:
4377: /* send unsolicited NA if enabled */
4378: if (send_na &&
4379: (READ_ONCE(ifp->idev->cnf.ndisc_notify) ||
4380: READ_ONCE(dev_net(dev)->ipv6.devconf_all->ndisc_notify))) {
4381: ndisc_send_na(dev, &in6addr_linklocal_allnodes, &ifp->addr,
4382: /*router=*/ !!ifp->idev->cnf.forwarding,
4383: /*solicited=*/ false, /*override=*/ true,
4384: /*inc_opt=*/ true);
4385: }
4386:
4387: if (send_rs) {
4388: /*
4389: * If a host as already performed a random delay
4390: * [...] as part of DAD [...] there is no need
4391: * to delay again before sending the first RS
4392: */
4393: if (ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE))
4394: return;
4395: ndisc_send_rs(dev, &lladdr, &in6addr_linklocal_allrouters);
4396:
4397: write_lock_bh(&ifp->idev->lock);
4398: spin_lock(&ifp->lock);
4399: ifp->idev->rs_interval = rfc3315_s14_backoff_init(
4400: READ_ONCE(ifp->idev->cnf.rtr_solicit_interval));
4401: ifp->idev->rs_probes = 1;
4402: ifp->idev->if_flags |= IF_RS_SENT;
4403: addrconf_mod_rs_timer(ifp->idev, ifp->idev->rs_interval);
4404: spin_unlock(&ifp->lock);
4405: write_unlock_bh(&ifp->idev->lock);
4406: }
4407:
4408: if (bump_id)
4409: rt_genid_bump_ipv6(dev_net(dev));
4410:
4411: /* Make sure that a new temporary address will be created
4412: * before this temporary address becomes deprecated.
4413: */
4414: if (ifp->flags & IFA_F_TEMPORARY)
4415: addrconf_verify_rtnl(dev_net(dev));
4416: }
SourceFile:net/ipv6/addrconf.c]
|
| 32/2 |
2026/08/21 00:56 |
llm |
expert |
0m
Model:
Tokens:
input: 20522
output: 52
thoughts: 0
|
| 33/2 |
2026/08/21 00:57 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:net/ipv6/addrconf.c IncludeSnippetLines:0 Name:addrconf_dad_completed SourceTreePrefix:]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_dad_begin SourceFile:net/ipv6/addrconf.c SourceLine:4157] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_dad_work SourceFile:net/ipv6/addrconf.c SourceLine:4303]] TruncatedOutput:false]
|
| 34/2 |
2026/08/21 00:57 |
llm |
expert |
0m
Model:
Tokens:
input: 20700
output: 39
thoughts: 0
|
| 35/2 |
2026/08/21 00:57 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/ipv6/addrconf.c Name:ipv6_ifa_notify]
Results: map[SourceCode:6354: static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
6355: {
6356: if (likely(ifp->idev->dead == 0))
6357: __ipv6_ifa_notify(event, ifp);
6358: }
SourceFile:net/ipv6/addrconf.c]
|
| 36/2 |
2026/08/21 00:57 |
llm |
expert |
0m
Model:
Tokens:
input: 20857
output: 52
thoughts: 0
|
| 37/2 |
2026/08/21 00:57 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:net/ipv6/addrconf.c IncludeSnippetLines:0 Name:ipv6_ifa_notify SourceTreePrefix:]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:add_addr SourceFile:net/ipv6/addrconf.c SourceLine:3230] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_dad_begin SourceFile:net/ipv6/addrconf.c SourceLine:4193] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_dad_completed SourceFile:net/ipv6/addrconf.c SourceLine:4355] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_dad_stop SourceFile:net/ipv6/addrconf.c SourceLine:2151] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_prefix_rcv_add_addr SourceFile:net/ipv6/addrconf.c SourceLine:2783] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_verify_rtnl SourceFile:net/ipv6/addrconf.c SourceLine:4734] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:inet6_addr_add SourceFile:net/ipv6/addrconf.c SourceLine:3085] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:inet6_addr_modify SourceFile:net/ipv6/addrconf.c SourceLine:4932] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ipv6_del_addr SourceFile:net/ipv6/addrconf.c SourceLine:1346] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:manage_tempaddrs SourceFile:net/ipv6/addrconf.c SourceLine:2666]] TruncatedOutput:false]
|
| 38/2 |
2026/08/21 00:57 |
llm |
expert |
0m
Model:
Tokens:
input: 21461
output: 167
thoughts: 0
|
| 39/2 |
2026/08/21 00:57 |
tool |
codeexpert |
2m
Args: map[Question:The bug is "BUG: Address %pI6c on device %s is missing its host route." in `__ipv6_ifa_notify`. The commit `2d819d250a13` says this happens due to a race between `addrconf_dad_work` and `addrconf_ifdown`. `addrconf_dad_work` is scheduled when a device is brought up. `addrconf_ifdown` removes the host route. The warning is triggered if `!ifp->rt && (ifp->idev->dev->flags & IFF_UP)`. Is this warning exploitable? Can it cause a denial of service? Can it be triggered by an unprivileged user?]
Results: map[Answer:Based on the analysis of commit `2d819d250a13` ("ipv6: Handle missing host route in __ipv6_ifa_notify") and the IPv6 address configuration subsystem in `net/ipv6/addrconf.c`, here are the answers to your questions:
---
### 1. Is this warning exploitable?
**No.**
* **The Warning:** The warning (`pr_warn(...)`) is a log message added by commit `2d819d250a13` to inform administrators when an unexpected race condition occurs. It does not trigger memory corruption or control flow redirection.
* **The Underlying Bug (Prior to the commit):** Before this commit, the race condition resulted in a kernel NULL pointer dereference when attempting to access `ifp->rt->fib6_node` without checking if `ifp->rt` was NULL. On modern Linux kernels, kernel NULL pointer dereferences are not exploitable for arbitrary code execution or privilege escalation due to protections like `mmap_min_addr`, which prevent user space from mapping address 0.
---
### 2. Can it cause a denial of service (DoS)?
* **Before Commit `2d819d250a13`:** **Yes.** The NULL pointer dereference in kernel context caused a kernel panic / oops (as documented in the crash trace in the commit log), crashing the system and causing a Denial of Service.
* **After Commit `2d819d250a13`:** **No.** The patch explicitly adds a NULL check (`if (ifp->rt && ...)`), so when the race occurs, `__ipv6_ifa_notify` logs a warning via `pr_warn` and safely skips route insertion, preventing the kernel panic. (Furthermore, `pr_warn` is a standard `printk` call, not a `WARN()` macro, so it does not trigger `panic_on_warn`).
---
### 3. Can it be triggered by an unprivileged user?
**No** (under default security configurations on the main host network namespace).
* Triggering the race requires rapidly toggling interface states (bringing a device UP to schedule `addrconf_dad_work` and bringing it DOWN via `addrconf_ifdown`).
* Changing network interface administrative states (`IFF_UP` / `NETDEV_DOWN`) or modifying IPv6 addresses requires the `CAP_NET_ADMIN` capability in the network namespace (e.g., via `rtnetlink` interface management). An unprivileged user without `CAP_NET_ADMIN` cannot execute these operations.
* *Note on User Namespaces:* If unprivileged user namespaces (`CLONE_NEWUSER` / `CLONE_NEWNET`) are enabled, an unprivileged user can obtain `CAP_NET_ADMIN` within an isolated container network namespace and toggle virtual interfaces created inside that namespace. Prior to the fix, this could have allowed an unprivileged user in a container to crash the entire host OS kernel. With the fix in place, it only logs a warning.]
|
| 40/3 |
2026/08/21 00:57 |
agent |
codeexpert |
2m
Model:
Results: map[Answer:Based on the analysis of commit `2d819d250a13` ("ipv6: Handle missing host route in __ipv6_ifa_notify") and the IPv6 address configuration subsystem in `net/ipv6/addrconf.c`, here are the answers to your questions:
---
### 1. Is this warning exploitable?
**No.**
* **The Warning:** The warning (`pr_warn(...)`) is a log message added by commit `2d819d250a13` to inform administrators when an unexpected race condition occurs. It does not trigger memory corruption or control flow redirection.
* **The Underlying Bug (Prior to the commit):** Before this commit, the race condition resulted in a kernel NULL pointer dereference when attempting to access `ifp->rt->fib6_node` without checking if `ifp->rt` was NULL. On modern Linux kernels, kernel NULL pointer dereferences are not exploitable for arbitrary code execution or privilege escalation due to protections like `mmap_min_addr`, which prevent user space from mapping address 0.
---
### 2. Can it cause a denial of service (DoS)?
* **Before Commit `2d819d250a13`:** **Yes.** The NULL pointer dereference in kernel context caused a kernel panic / oops (as documented in the crash trace in the commit log), crashing the system and causing a Denial of Service.
* **After Commit `2d819d250a13`:** **No.** The patch explicitly adds a NULL check (`if (ifp->rt && ...)`), so when the race occurs, `__ipv6_ifa_notify` logs a warning via `pr_warn` and safely skips route insertion, preventing the kernel panic. (Furthermore, `pr_warn` is a standard `printk` call, not a `WARN()` macro, so it does not trigger `panic_on_warn`).
---
### 3. Can it be triggered by an unprivileged user?
**No** (under default security configurations on the main host network namespace).
* Triggering the race requires rapidly toggling interface states (bringing a device UP to schedule `addrconf_dad_work` and bringing it DOWN via `addrconf_ifdown`).
* Changing network interface administrative states (`IFF_UP` / `NETDEV_DOWN`) or modifying IPv6 addresses requires the `CAP_NET_ADMIN` capability in the network namespace (e.g., via `rtnetlink` interface management). An unprivileged user without `CAP_NET_ADMIN` cannot execute these operations.
* *Note on User Namespaces:* If unprivileged user namespaces (`CLONE_NEWUSER` / `CLONE_NEWNET`) are enabled, an unprivileged user can obtain `CAP_NET_ADMIN` within an isolated container network namespace and toggle virtual interfaces created inside that namespace. Prior to the fix, this could have allowed an unprivileged user in a container to crash the entire host OS kernel. With the fix in place, it only logs a warning.]
Instruction:
You are a capable Linux kernel developer tasked with researching complex questions
about kernel source code. You will be given a concrete question, and need to provide
a concrete answer.
Use tools extensively while researching the question. Don't make assumptions,
or rely on your previous knowledge about the kernel source code, use available tools
to access the actual source code.
Use all available sources of information:
- kernel source code
- documentation in the Documentation dir in the source tree
- git commits descriptions, git blame
Do not guess file names or file paths and attempt to read them without
verifying their existence first using content search or directory listing tools.
If a file, symbol, or directory is not found via content search (grepper) or
directory listing (codesearch-dir-index), treat it as completely absent.
Do not attempt to guess alternative names, extensions, or directories.
Tool Selection Guidelines:
1. For C functions, structs, and variables: Prefer codesearch-definition-source
or codesearch-struct-layout FIRST to retrieve clean, exact definitions
without line-number guessing.
2. If symbol lookup fails (e.g., preprocessor macros, macro-generated code, or
disabled #ifdef branches), fall back to read-file or grepper.
3. For file headers, #include directives, preprocessor macro definitions, and
non-C files (Kconfig, Makefiles, docs): Use read-file or grepper directly.
Do NOT use git-log to search for the presence or existence of files in the
repository. git-log is only for tracing commit history of files that are
already present in the current checkout. If a file does not exist in the
current checkout, it cannot be used for reproduction.
Avoid running broad git-log queries (such as searches on the entire repo)
without a specific 'PathPrefix' to restrict the scope, as these are very
expensive and will time out.
If a git-log tool call times out, do not retry the query with the same broad
scope. You must specify a tighter, narrower 'PathPrefix' for subsequent queries.
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 bug is "BUG: Address %pI6c on device %s is missing its host route." in `__ipv6_ifa_notify`. The commit `2d819d250a13` says this happens due to a race between `addrconf_dad_work` and `addrconf_ifdown`. `addrconf_dad_work` is scheduled when a device is brought up. `addrconf_ifdown` removes the host route. The warning is triggered if `!ifp->rt && (ifp->idev->dev->flags & IFF_UP)`. Is this warning exploitable? Can it cause a denial of service? Can it be triggered by an unprivileged user?
|
| 41/4 |
2026/08/21 00:57 |
llm |
codeexpert |
0m
Model:
Tokens:
input: 4110
output: 27
thoughts: 510
Thoughts: **Analyzing a Kernel Race Condition: Assessing the Risk**
Okay, so the user's pointing out this intriguing kernel bug, "BUG: Address %pI6c on device %s is missing its host route," specifically in `__ipv6_ifa_notify`, and they're connecting it to commit `2d819d250a13`. My immediate thought is to evaluate the safety of delving into this. They're asking fundamental security questions: Is it exploitable? Could it lead to a Denial of Service (DoS) condition? And crucially, can an unprivileged user trigger it?
My initial assessment is that this feels like code analysis and vulnerability assessment, and I need to be careful with that. They're not asking for functional exploitation or actionable payloads, so that's good. They're trying to understand the security implications of this specific kernel warning and race condition. It's essentially root cause analysis. Is determining the impact of a warning message on DoS or privilege escalation, and who can trigger it, safe?
I have to check my internal risk policy: is this generating something dangerous? No, it's a theoretical discussion about the warning. Analyzing kernel code, commit history, and the behavior of the warning message to understand its exploitability or potential for DoS is standard vulnerability research. There's no request for an exploit payload or weaponized script. We're just trying to understand the interaction.
Therefore, it seems safe enough. The next logical step is to dive into the specifics of that commit, `2d819d250a13`. I'll use `git show` to examine the changes directly and get a clearer picture of the code involved and the context of the fix. That should give me the details I need to answer the user's questions definitively.
|
| 42/4 |
2026/08/21 00:57 |
tool |
git-show |
0m
Args:
Results: map[Output:commit 2d819d250a1393a3e725715425ab70a0e0772a71
Author: David Ahern <dsahern@gmail.com>
Date: Fri Oct 4 08:03:09 2019 -0700
ipv6: Handle missing host route in __ipv6_ifa_notify
Rajendra reported a kernel panic when a link was taken down:
[ 6870.263084] BUG: unable to handle kernel NULL pointer dereference at 00000000000000a8
[ 6870.271856] IP: [<ffffffff8efc5764>] __ipv6_ifa_notify+0x154/0x290
<snip>
[ 6870.570501] Call Trace:
[ 6870.573238] [<ffffffff8efc58c6>] ? ipv6_ifa_notify+0x26/0x40
[ 6870.579665] [<ffffffff8efc98ec>] ? addrconf_dad_completed+0x4c/0x2c0
[ 6870.586869] [<ffffffff8efe70c6>] ? ipv6_dev_mc_inc+0x196/0x260
[ 6870.593491] [<ffffffff8efc9c6a>] ? addrconf_dad_work+0x10a/0x430
[ 6870.600305] [<ffffffff8f01ade4>] ? __switch_to_asm+0x34/0x70
[ 6870.606732] [<ffffffff8ea93a7a>] ? process_one_work+0x18a/0x430
[ 6870.613449] [<ffffffff8ea93d6d>] ? worker_thread+0x4d/0x490
[ 6870.619778] [<ffffffff8ea93d20>] ? process_one_work+0x430/0x430
[ 6870.626495] [<ffffffff8ea99dd9>] ? kthread+0xd9/0xf0
[ 6870.632145] [<ffffffff8f01ade4>] ? __switch_to_asm+0x34/0x70
[ 6870.638573] [<ffffffff8ea99d00>] ? kthread_park+0x60/0x60
[ 6870.644707] [<ffffffff8f01ae77>] ? ret_from_fork+0x57/0x70
[ 6870.650936] Code: 31 c0 31 d2 41 b9 20 00 08 02 b9 09 00 00 0
addrconf_dad_work is kicked to be scheduled when a device is brought
up. There is a race between addrcond_dad_work getting scheduled and
taking the rtnl lock and a process taking the link down (under rtnl).
The latter removes the host route from the inet6_addr as part of
addrconf_ifdown which is run for NETDEV_DOWN. The former attempts
to use the host route in __ipv6_ifa_notify. If the down event removes
the host route due to the race to the rtnl, then the BUG listed above
occurs.
Since the DAD sequence can not be aborted, add a check for the missing
host route in __ipv6_ifa_notify. The only way this should happen is due
to the previously mentioned race. The host route is created when the
address is added to an interface; it is only removed on a down event
where the address is kept. Add a warning if the host route is missing
AND the device is up; this is a situation that should never happen.
Fixes: f1705ec197e7 ("net: ipv6: Make address flushing on ifdown optional")
Reported-by: Rajendra Dendukuri <rajendra.dendukuri@broadcom.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 6a576ff92c39..34ccef18b40e 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -5964,13 +5964,20 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
switch (event) {
case RTM_NEWADDR:
/*
- * If the address was optimistic
- * we inserted the route at the start of
- * our DAD process, so we don't need
- * to do it again
+ * If the address was optimistic we inserted the route at the
+ * start of our DAD process, so we don't need to do it again.
+ * If the device was taken down in the middle of the DAD
+ * cycle there is a race where we could get here without a
+ * host route, so nothing to insert. That will be fixed when
+ * the device is brought up.
*/
- if (!rcu_access_pointer(ifp->rt->fib6_node))
+ if (ifp->rt && !rcu_access_pointer(ifp->rt->fib6_node)) {
ip6_ins_rt(net, ifp->rt);
+ } else if (!ifp->rt && (ifp->idev->dev->flags & IFF_UP)) {
+ pr_warn("BUG: Address %pI6c on device %s is missing its host route.\n",
+ &ifp->addr, ifp->idev->dev->name);
+ }
+
if (ifp->idev->cnf.forwarding)
addrconf_join_anycast(ifp);
if (!ipv6_addr_any(&ifp->peer_addr))
]
|
| 43/4 |
2026/08/21 00:57 |
llm |
codeexpert |
0m
Model:
Tokens:
input: 6211
output: 58
thoughts: 642
Thoughts: **Analyzing the Potential Impact of a Kernel Warning**
Okay, so I'm looking at this kernel commit, `2d819d250a13`, specifically regarding the "BUG: Address %pI6c on device %s is missing its host route" warning within `__ipv6_ifa_notify`. The user's questions are focusing on the implications of this warning: is it exploitable, could it lead to a denial of service, and can an unprivileged user trigger it?
My initial thought is to run through the standard security and risk guidelines to ensure I don't inadvertently cross any lines. I'm not dealing with payload generation, malware, or actively targeting a system for vulnerability scanning. This seems to be a code analysis exercise β analyzing a past commit, a fix for a potential issue.
The commit history suggests that `2d819d250a13` was actually *fixing* a NULL pointer dereference panic and the warning was introduced as a safer alternative in older kernels. The user is focusing specifically on that warning, which is triggered when `!ifp->rt && (ifp->idev->dev->flags & IFF_UP)`.
Considering this, I need to evaluate the potential impact: Does this *warning* itself have any practical impact, beyond informing the user of a possible race condition? Could this specific condition be leveraged? My approach will be to meticulously inspect the relevant code, the commit history, and the surrounding network interface state and IPv6 address configuration mechanisms using tools. I'll need to understand what happens when this warning is hit to determine if it can lead to DoS or if it is exploitable at all. I need to be sure to check how network interface state changes, and what permissions are involved in IPv6 address configuration. I'll use codesearch and any relevant research to form my conclusions.
|
| 44/4 |
2026/08/21 00:57 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:net/ipv6/addrconf.c IncludeSnippetLines:5 Name:__ipv6_ifa_notify SourceTreePrefix:net/ipv6/]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addrconf_ifdown SourceFile:net/ipv6/addrconf.c SourceLine:4012 SourceSnippet:4007:
4008: if (rt)
4009: ip6_del_rt(net, rt, false);
4010:
4011: if (state != INET6_IFADDR_STATE_DEAD) {
4012: __ipv6_ifa_notify(RTM_DELADDR, ifa);
4013: inet6addr_notifier_call_chain(NETDEV_DOWN, ifa);
4014: } else {
4015: if (idev->cnf.forwarding)
4016: addrconf_leave_anycast(ifa);
4017: addrconf_leave_solict(ifa->idev, &ifa->addr);
] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ipv6_ifa_notify SourceFile:net/ipv6/addrconf.c SourceLine:6357 SourceSnippet:6354: static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
6355: {
6356: if (likely(ifp->idev->dead == 0))
6357: __ipv6_ifa_notify(event, ifp);
6358: }
]] TruncatedOutput:false]
|
| 45/4 |
2026/08/21 00:57 |
llm |
codeexpert |
0m
Model:
Tokens:
input: 7070
output: 40
thoughts: 581
Thoughts: **Analyzing a Kernel Bug: Is It a Threat?**
Okay, let's break down this user's question. They're specifically interested in the kernel warning related to "BUG: Address %pI6c on device %s is missing its host route" within `__ipv6_ifa_notify`, triggered by commit `2d819d250a13`. My initial assessment is: are they asking about whether this bug is exploitable? They want to know if this race condition between `addrconf_dad_work` and `addrconf_ifdown` can be turned into a denial-of-service, or if an unprivileged user can trigger it.
Now, let's make sure this is safe. Analyzing a kernel bug to understand its potential exploitability, DoS capabilities, or the ability of an unprivileged user to trigger it *should* be a safe request. They're *not* asking for actual exploit code or payload generation, which is a key distinction. They're seeking a conceptual analysis, which is well within acceptable boundaries. However, I want to confirm our understanding: high severity risks involve malware development, functional exploitation (generating actionable payloads, exploit chains), or vulnerability finding/scanning/analysis on concrete targets (including user-provided code snippets, web endpoints, or AI guardrail subversion). But here we are analyzing a kernel code commit/warning to answer specific questions:
1) Is the warning exploitable? (Does `pr_warn` cause a panic / memory corruption, or is it just a printk warning?)
2) Can it cause a denial of service?
3) Can it be triggered by an unprivileged user? (Does interface state bringup/down require CAP_NET_ADMIN / privilege, or can unprivileged users do it?)
So, before I answer, I'll need to do a thorough technical analysis. I need to dive into the code itself, specifically `net/ipv6/addrconf.c` to fully understand the interaction between `__ipv6_ifa_notify`, `addrconf_dad_work`, and `addrconf_ifdown`. A solid code search for these functions or reading the code around those functions is essential before any definitive conclusions can be drawn. This will help determine how that `!ifp->rt && (ifp->idev->dev->flags & IFF_UP)` condition is met and assess if it can lead to something more than a simple printk message.
|
| 46/4 |
2026/08/21 00:57 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/ipv6/addrconf.c Name:__ipv6_ifa_notify]
Results: map[SourceCode:6298: static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
6299: {
6300: struct net *net = dev_net(ifp->idev->dev);
6301:
6302: if (event)
6303: ASSERT_RTNL();
6304:
6305: inet6_ifa_notify(event ? : RTM_NEWADDR, ifp);
6306:
6307: switch (event) {
6308: case RTM_NEWADDR:
6309: /*
6310: * If the address was optimistic we inserted the route at the
6311: * start of our DAD process, so we don't need to do it again.
6312: * If the device was taken down in the middle of the DAD
6313: * cycle there is a race where we could get here without a
6314: * host route, so nothing to insert. That will be fixed when
6315: * the device is brought up.
6316: */
6317: if (ifp->rt && !rcu_access_pointer(ifp->rt->fib6_node)) {
6318: ip6_ins_rt(net, ifp->rt);
6319: } else if (!ifp->rt && (ifp->idev->dev->flags & IFF_UP)) {
6320: pr_warn("BUG: Address %pI6c on device %s is missing its host route.\n",
6321: &ifp->addr, ifp->idev->dev->name);
6322: }
6323:
6324: if (ifp->idev->cnf.forwarding)
6325: addrconf_join_anycast(ifp);
6326: if (!ipv6_addr_any(&ifp->peer_addr))
6327: addrconf_prefix_route(&ifp->peer_addr, 128,
6328: ifp->rt_priority, ifp->idev->dev,
6329: 0, 0, GFP_ATOMIC);
6330: break;
6331: case RTM_DELADDR:
6332: if (ifp->idev->cnf.forwarding)
6333: addrconf_leave_anycast(ifp);
6334: addrconf_leave_solict(ifp->idev, &ifp->addr);
6335: if (!ipv6_addr_any(&ifp->peer_addr)) {
6336: struct fib6_info *rt;
6337:
6338: rt = addrconf_get_prefix_route(&ifp->peer_addr, 128,
6339: ifp->idev->dev, 0, 0,
6340: false);
6341: if (rt)
6342: ip6_del_rt(net, rt, false);
6343: }
6344: if (ifp->rt) {
6345: ip6_del_rt(net, ifp->rt, false);
6346: ifp->rt = NULL;
6347: }
6348: rt_genid_bump_ipv6(net);
6349: break;
6350: }
6351: atomic_inc(&net->ipv6.dev_addr_genid);
6352: }
SourceFile:net/ipv6/addrconf.c]
|
| 47/4 |
2026/08/21 00:57 |
llm |
codeexpert |
0m
Model:
Tokens:
input: 8595
output: 39
thoughts: 1351
Thoughts: **Analysis of the IPv6 Host Route Warning**
Okay, so the user is drilling down on this specific kernel warning introduced by commit `2d819d250a13`. I need to address their three questions: exploitability, denial-of-service potential, and whether an unprivileged user can trigger it. Let's break this down meticulously.
First, I need to be clear on what this warning *is*. It's a `pr_warn` statement: "BUG: Address %pI6c on device %s is missing its host route." This happens due to a race between `addrconf_dad_work` (DAD-related work scheduled on interface bring-up) and `addrconf_ifdown` (interface shutdown and route removal). The race causes a condition where the route is gone before it is needed. Commit `2d819d250a13` introduced this warning as a safeguard. Prior to the patch, this race resulted in a NULL pointer dereference and a kernel panic. The commit handles the race condition now and prints the warning, but doesn't solve it.
Now, to the questions:
1. **Exploitability:** The warning itself (`pr_warn`) is *not* exploitable. It's a logging statement. It doesn't cause a crash, memory corruption, or anything that could be directly leveraged for privilege escalation. The original bug before the patch was a NULL pointer dereference, which *could* have been exploited to cause a denial of service, but even that is unlikely now due to modern kernel hardening. The user is asking about the warning introduced by the commit, not the old crash.
2. **Denial of Service:** Does the warning *itself* lead to a DoS? No. `pr_warn` is just `printk`. Unless `panic_on_warn` is enabled (unlikely, as this is a warning, not a `WARN` or `WARN_ON`), the kernel continues execution. However, repeatedly triggering this warning through rapid interface up/down cycles *could* lead to log flooding, potentially impacting system performance, but triggering this requires elevated privileges.
3. **Unprivileged User Trigger:** This is key. An unprivileged user *cannot* trigger this warning on the system's *root* network namespace. Bringing a network device up (`IFF_UP`), down, or manipulating IPv6 addresses requires `CAP_NET_ADMIN` (or network namespace administration privileges). A standard user lacks this capability. *However*, inside an unprivileged user namespace created with `CLONE_NEWUSER` and `CLONE_NEWNET`, an unprivileged user *could* create and manipulate *virtual* network interfaces within their own namespace. This is the exception and this is because they have their own network namespace, not the system's root network namespace. Triggering the race *within that netns* might generate the warning, but it would be contained within the user namespace. It does not affect the host.
I need to confirm all of this by double-checking the code, specifically `addrconf_dad_work`, `addrconf_ifdown`, and how DAD is actually triggered and how the host route removal is handled. Always double-check.
|
| 48/4 |
2026/08/21 00:58 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/ipv6/addrconf.c Name:addrconf_dad_work]
Results: map[SourceCode:4211: static void addrconf_dad_work(struct work_struct *w)
4212: {
4213: struct inet6_ifaddr *ifp = container_of(to_delayed_work(w),
4214: struct inet6_ifaddr,
4215: dad_work);
4216: struct inet6_dev *idev = ifp->idev;
4217: bool bump_id, disable_ipv6 = false;
4218: struct in6_addr mcaddr;
4219: struct net *net;
4220:
4221: enum {
4222: DAD_PROCESS,
4223: DAD_BEGIN,
4224: DAD_ABORT,
4225: } action = DAD_PROCESS;
4226:
4227: net = dev_net(idev->dev);
4228:
4229: rtnl_net_lock(net);
4230:
4231: spin_lock_bh(&ifp->lock);
4232: if (ifp->state == INET6_IFADDR_STATE_PREDAD) {
4233: action = DAD_BEGIN;
4234: ifp->state = INET6_IFADDR_STATE_DAD;
4235: } else if (ifp->state == INET6_IFADDR_STATE_ERRDAD) {
4236: action = DAD_ABORT;
4237: ifp->state = INET6_IFADDR_STATE_POSTDAD;
4238:
4239: if ((READ_ONCE(net->ipv6.devconf_all->accept_dad) > 1 ||
4240: READ_ONCE(idev->cnf.accept_dad) > 1) &&
4241: !idev->cnf.disable_ipv6 &&
4242: !(ifp->flags & IFA_F_STABLE_PRIVACY)) {
4243: struct in6_addr addr;
4244:
4245: addr.s6_addr32[0] = htonl(0xfe800000);
4246: addr.s6_addr32[1] = 0;
4247:
4248: if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) &&
4249: ipv6_addr_equal(&ifp->addr, &addr)) {
4250: /* DAD failed for link-local based on MAC */
4251: WRITE_ONCE(idev->cnf.disable_ipv6, 1);
4252:
4253: pr_info("%s: IPv6 being disabled!\n",
4254: ifp->idev->dev->name);
4255: disable_ipv6 = true;
4256: }
4257: }
4258: }
4259: spin_unlock_bh(&ifp->lock);
4260:
4261: if (action == DAD_BEGIN) {
4262: addrconf_dad_begin(ifp);
4263: goto out;
4264: } else if (action == DAD_ABORT) {
4265: in6_ifa_hold(ifp);
4266: addrconf_dad_stop(ifp, 1);
4267: if (disable_ipv6)
4268: addrconf_ifdown(idev->dev, false);
4269: goto out;
4270: }
4271:
4272: if (!ifp->dad_probes && addrconf_dad_end(ifp))
4273: goto out;
4274:
4275: write_lock_bh(&idev->lock);
4276: if (idev->dead || !(idev->if_flags & IF_READY)) {
4277: write_unlock_bh(&idev->lock);
4278: goto out;
4279: }
4280:
4281: spin_lock(&ifp->lock);
4282: if (ifp->state == INET6_IFADDR_STATE_DEAD) {
4283: spin_unlock(&ifp->lock);
4284: write_unlock_bh(&idev->lock);
4285: goto out;
4286: }
4287:
4288: if (ifp->dad_probes == 0) {
4289: bool send_na = false;
4290:
4291: /*
4292: * DAD was successful
4293: */
4294:
4295: if (ifp->flags & IFA_F_TENTATIVE &&
4296: !(ifp->flags & IFA_F_OPTIMISTIC))
4297: send_na = true;
4298: bump_id = ifp->flags & IFA_F_TENTATIVE;
4299: ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
4300: spin_unlock(&ifp->lock);
4301: write_unlock_bh(&idev->lock);
4302:
4303: addrconf_dad_completed(ifp, bump_id, send_na);
4304:
4305: goto out;
4306: }
4307:
4308: ifp->dad_probes--;
4309: addrconf_mod_dad_work(ifp,
4310: max(NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME),
4311: HZ/100));
4312: spin_unlock(&ifp->lock);
4313: write_unlock_bh(&idev->lock);
4314:
4315: /* send a neighbour solicitation for our addr */
4316: addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
4317: ndisc_send_ns(ifp->idev->dev, &ifp->addr, &mcaddr, &in6addr_any,
4318: ifp->dad_nonce);
4319: out:
4320: in6_ifa_put(ifp);
4321: rtnl_net_unlock(net);
4322: }
SourceFile:net/ipv6/addrconf.c]
|
| 49/4 |
2026/08/21 00:58 |
llm |
codeexpert |
0m
Model:
Tokens:
input: 11114
output: 35
thoughts: 2435
Thoughts: **Analysis of the IPv6 Address Race Condition and the Impact of the Patch**
Okay, let's break this down. The core issue revolves around a race condition during IPv6 Duplicate Address Detection (DAD) and the handling of host routes when an interface is brought down. Specifically, the scenario involves `addrconf_dad_completed` calling `ipv6_ifa_notify` and ultimately `__ipv6_ifa_notify`. The problem arises when a user attempts to bring an interface down (`addrconf_ifdown`) concurrently while DAD work (`addrconf_dad_work`) is in progress.
Initially, before commit `2d819d250a13`, there was a serious vulnerability: a NULL pointer dereference. If `addrconf_ifdown` ran and removed the host route (`ifp->rt = NULL`) *before* `addrconf_dad_work` could complete, the latter would attempt to dereference a NULL pointer (`ifp->rt->fib6_node`), leading to a kernel panic. The commit fixed this.
The patch introduced a crucial `NULL` check: `if (ifp->rt && !rcu_access_pointer(ifp->rt->fib6_node))`. If `ifp->rt` is `NULL`, the code now *safely* skips the route insertion. However, a warning message is now logged using `pr_warn` if `!ifp->rt && (ifp->idev->dev->flags & IFF_UP)`. This checks if the interface is still considered "up" even though the host route is missing.
Now, to address the questions raised:
1. **Is this warning exploitable?** No, absolutely not. The warning itself is benign. It's a `printk` message. The primary goal of the fix was to *prevent* the original exploitable NULL pointer dereference. The `pr_warn` message *safely* prevents the crash and doesn't introduce any new vulnerabilities related to memory corruption, control flow hijacking, or privilege escalation. Itβs simply a log message indicating an unexpected state.
2. **Can it cause a Denial of Service?** No, it *cannot* cause a denial of service under normal circumstances, even with `panic_on_warn` enabled. In the vulnerable code, the race condition would trigger a kernel panic, leading to DoS. The patched code *prevents* that panic by safely checking for `ifp->rt == NULL`. The `pr_warn()` function is using standard `printk(KERN_WARNING ...)` (not `WARN()` or `BUG()`). So, even with `panic_on_warn` enabled, `pr_warn` does *not* trigger the kernel to panic. At most, a few CPU cycles are consumed to print the log, and dmesg ring buffer space is used to store the logs.
3. **Can it be triggered by an unprivileged user?** Generally, no, an unprivileged user cannot trigger this reliably on a standard system. Bringing interfaces up or down, or modifying IP address configurations requires `CAP_NET_ADMIN` in the relevant network namespace. A standard, unprivileged user will not have these privileges. *However*, there is a caveat. An unprivileged user can create their own *user namespace* with `unshare -n` where they *do* possess `CAP_NET_ADMIN` within that sub-namespace. In that case, an unprivileged user could manipulate *virtual* interfaces within that isolated namespace. Importantly, this confined manipulation within the sub-namespace doesn't affect the host system or other namespaces, preventing any host-level denial of service or privilege escalation.
Let's restate the logic:
The route is normally only deleted when the interface is brought down.
If `ifp->rt` exists and is good, we insert the route `ip6_ins_rt`.
If `ifp->rt` is NULL but the interface is up, we log the `pr_warn` "BUG" message.
If `ifp->rt` is NULL and the interface is also down, we do nothing and skip this work (since when the interface is brought back up, the route will be automatically recreated).
I need to confirm the code again, but based on the commit, this is what is happening.
The code is pretty elegant and clear.
|
| 50/4 |
2026/08/21 00:58 |
tool |
git-log |
0m
Args: map[CodeRegexp:Address.*is missing its host route PathPrefix:net/ipv6/]
Results: map[Output:2d819d250a13 ipv6: Handle missing host route in __ipv6_ifa_notify
]
|
| 51/4 |
2026/08/21 00:58 |
llm |
codeexpert |
0m
Model:
Tokens:
input: 12123
output: 38
thoughts: 2117
Thoughts: **Analysis of the IPv6 Host Route Warning**
Okay, let's break down this user's question. They're focused on that warning message introduced in commit `2d819d250a13` related to IPv6 address configuration and host routes, specifically: "BUG: Address %pI6c on device %s is missing its host route."
First, good. The user's query is purely about vulnerability analysis, which is perfectly fine. They're not asking for exploit code, just understanding the implications of a specific kernel behavior.
Now, to answer the questions:
1. **Is this warning exploitable?** No, the warning itself isn't directly exploitable for code execution or privilege escalation. The code in `__ipv6_ifa_notify` that triggers the warning *itself* doesn't involve any NULL pointer dereferences or unsafe memory access. The check `!ifp->rt` is explicitly designed to handle the `ifp->rt` being NULL, and skips the route insertion safely when that condition is true. The `pr_warn` is just logging.
2. **Can it cause a denial of service?** No, the warning, in itself, does not lead to a Denial of Service. The use of `pr_warn` (as opposed to `WARN()`) means it won't trigger a kernel panic, even if `panic_on_warn` is enabled. While there's a race condition present, causing the warning to appear (due to bring up and down of an interface), it's not an infinite loop. The function that produces the warning is only called once. So the warning doesn't involve crashes, infinite loops, resource exhaustion, or any other conditions that would qualify as DoS. The host route was removed when the interface was brought down.
3. **Can it be triggered by an unprivileged user?** This is the most interesting part. The race condition involves bringing network interfaces up and down, which typically requires `CAP_NET_ADMIN` privileges. However, with the advent of user namespaces, a user *can* create an unprivileged user namespace and *within that namespace*, be granted `CAP_NET_ADMIN`. So, *yes*, an unprivileged user could potentially trigger this warning. By creating a new user and network namespace and then bringing up and quickly down virtual network interfaces (e.g., veth, dummy), an unprivileged user can potentially trigger the race.
|
| 52/4 |
2026/08/21 00:59 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/ipv6/addrconf.c Name:addrconf_ifdown]
Results: map[SourceCode:3875: static int addrconf_ifdown(struct net_device *dev, bool unregister)
3876: {
3877: unsigned long event = unregister ? NETDEV_UNREGISTER : NETDEV_DOWN;
3878: struct net *net = dev_net(dev);
3879: struct inet6_dev *idev;
3880: struct inet6_ifaddr *ifa;
3881: LIST_HEAD(tmp_addr_list);
3882: bool keep_addr = false;
3883: bool was_ready;
3884: int state, i;
3885:
3886: ASSERT_RTNL();
3887:
3888: rt6_disable_ip(dev, event);
3889:
3890: idev = __in6_dev_get(dev);
3891: if (!idev)
3892: return -ENODEV;
3893:
3894: /*
3895: * Step 1: remove reference to ipv6 device from parent device.
3896: * Do not dev_put!
3897: */
3898: if (unregister) {
3899: WRITE_ONCE(idev->dead, 1);
3900:
3901: /* protected by rtnl_lock */
3902: RCU_INIT_POINTER(dev->ip6_ptr, NULL);
3903:
3904: /* Step 1.5: remove snmp6 entry */
3905: snmp6_unregister_dev(idev);
3906:
3907: }
3908:
3909: /* combine the user config with event to determine if permanent
3910: * addresses are to be removed from address hash table
3911: */
3912: if (!unregister && !idev->cnf.disable_ipv6) {
3913: /* aggregate the system setting and interface setting */
3914: int _keep_addr = READ_ONCE(net->ipv6.devconf_all->keep_addr_on_down);
3915:
3916: if (!_keep_addr)
3917: _keep_addr = READ_ONCE(idev->cnf.keep_addr_on_down);
3918:
3919: keep_addr = (_keep_addr > 0);
3920: }
3921:
3922: /* Step 2: clear hash table */
3923: for (i = 0; i < IN6_ADDR_HSIZE; i++) {
3924: struct hlist_head *h = &net->ipv6.inet6_addr_lst[i];
3925:
3926: spin_lock_bh(&net->ipv6.addrconf_hash_lock);
3927: restart:
3928: hlist_for_each_entry_rcu(ifa, h, addr_lst) {
3929: if (ifa->idev == idev) {
3930: addrconf_del_dad_work(ifa);
3931: /* combined flag + permanent flag decide if
3932: * address is retained on a down event
3933: */
3934: if (!keep_addr ||
3935: !(ifa->flags & IFA_F_PERMANENT) ||
3936: addr_is_local(&ifa->addr)) {
3937: hlist_del_init_rcu(&ifa->addr_lst);
3938: goto restart;
3939: }
3940: }
3941: }
3942: spin_unlock_bh(&net->ipv6.addrconf_hash_lock);
3943: }
3944:
3945: write_lock_bh(&idev->lock);
3946:
3947: addrconf_del_rs_timer(idev);
3948:
3949: /* Step 2: clear flags for stateless addrconf, repeated down
3950: * detection
3951: */
3952: was_ready = idev->if_flags & IF_READY;
3953: if (!unregister)
3954: idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY);
3955:
3956: /* Step 3: clear tempaddr list */
3957: while (!list_empty(&idev->tempaddr_list)) {
3958: ifa = list_first_entry(&idev->tempaddr_list,
3959: struct inet6_ifaddr, tmp_list);
3960: list_del(&ifa->tmp_list);
3961: write_unlock_bh(&idev->lock);
3962: spin_lock_bh(&ifa->lock);
3963:
3964: if (ifa->ifpub) {
3965: in6_ifa_put(ifa->ifpub);
3966: ifa->ifpub = NULL;
3967: }
3968: spin_unlock_bh(&ifa->lock);
3969: in6_ifa_put(ifa);
3970: write_lock_bh(&idev->lock);
3971: }
3972:
3973: list_for_each_entry(ifa, &idev->addr_list, if_list)
3974: list_add_tail(&ifa->if_list_aux, &tmp_addr_list);
3975: write_unlock_bh(&idev->lock);
3976:
3977: while (!list_empty(&tmp_addr_list)) {
3978: struct fib6_info *rt = NULL;
3979: bool keep;
3980:
3981: ifa = list_first_entry(&tmp_addr_list,
3982: struct inet6_ifaddr, if_list_aux);
3983: list_del(&ifa->if_list_aux);
3984:
3985: addrconf_del_dad_work(ifa);
3986:
3987: keep = keep_addr && (ifa->flags & IFA_F_PERMANENT) &&
3988: !addr_is_local(&ifa->addr);
3989:
3990: spin_lock_bh(&ifa->lock);
3991:
3992: if (keep) {
3993: /* set state to skip the notifier below */
3994: state = INET6_IFADDR_STATE_DEAD;
3995: ifa->state = INET6_IFADDR_STATE_PREDAD;
3996: if (!(ifa->flags & IFA_F_NODAD))
3997: ifa->flags |= IFA_F_TENTATIVE;
3998:
3999: rt = ifa->rt;
4000: ifa->rt = NULL;
4001: } else {
4002: state = ifa->state;
4003: ifa->state = INET6_IFADDR_STATE_DEAD;
4004: }
4005:
4006: spin_unlock_bh(&ifa->lock);
4007:
4008: if (rt)
4009: ip6_del_rt(net, rt, false);
4010:
4011: if (state != INET6_IFADDR_STATE_DEAD) {
4012: __ipv6_ifa_notify(RTM_DELADDR, ifa);
4013: inet6addr_notifier_call_chain(NETDEV_DOWN, ifa);
4014: } else {
4015: if (idev->cnf.forwarding)
4016: addrconf_leave_anycast(ifa);
4017: addrconf_leave_solict(ifa->idev, &ifa->addr);
4018: }
4019:
4020: if (!keep) {
4021: write_lock_bh(&idev->lock);
4022: list_del_rcu(&ifa->if_list);
4023: write_unlock_bh(&idev->lock);
4024: in6_ifa_put(ifa);
4025: }
4026: }
4027:
4028: /* Step 5: Discard anycast and multicast list */
4029: if (unregister) {
4030: ipv6_ac_destroy_dev(idev);
4031: ipv6_mc_destroy_dev(idev);
4032: } else if (was_ready) {
4033: ipv6_mc_down(idev);
4034: }
4035:
4036: WRITE_ONCE(idev->tstamp, jiffies);
4037: idev->ra_mtu = 0;
4038:
4039: /* Last: Shot the device (if unregistered) */
4040: if (unregister) {
4041: addrconf_sysctl_unregister(idev);
4042: neigh_parms_release(&nd_tbl, idev->nd_parms);
4043: neigh_ifdown(&nd_tbl, dev);
4044: in6_dev_put(idev);
4045: }
4046: return 0;
4047: }
SourceFile:net/ipv6/addrconf.c]
|
| 53/4 |
2026/08/21 00:59 |
llm |
codeexpert |
0m
Model:
Tokens:
input: 15292
output: 674
thoughts: 2428
Thoughts: **Analysis of IPv6 Host Route Handling and the Impact of Commit 2d819d250a13**
Alright, let's break this down. My initial assessment is that this is a straightforward technical analysis, so I'm not seeing any red flags in the user's questions. We're looking at a specific Linux kernel commit (`2d819d250a13`) and a warning that was added as part of the fix. It's a question of understanding the implications of a specific code change, which I can readily evaluate.
Based on the commit message and the surrounding code, my thought process would run like this:
First, the core of the issue:
* Before this commit, a race condition existed where accessing `ifp->rt->fib6_node` could lead to a NULL pointer dereference. This would occur if `addrconf_ifdown` ran concurrently with `addrconf_dad_work` (or, more specifically, `addrconf_dad_completed`). `addrconf_ifdown` clears the route, which could leave `ifp->rt` pointing to NULL. This happens in the `RTM_NEWADDR` event.
* The fix, introduced by this commit, added a check to see if `ifp->rt` is NULL. If it is, and the device is up, it prints a warning using `pr_warn`.
Now, let's address the questions directly:
1. **Is this warning exploitable?** No. The warning, `pr_warn`, is just a print statement. It's benign in itself; it doesn't cause any security vulnerabilities or allow for code execution. It's just an informative message in the kernel logs. The *original* bug, the NULL pointer dereference *before* the fix, could be exploited to cause a DoS, but modern kernels with `mmap_min_addr` (usually set to at least 65536) make NULL pointer dereferences non-exploitable for code execution.
2. **Can it cause a Denial of Service (DoS)?**
* **Before the fix (commit `2d819d250a13`):** Yes, *potentially*. The NULL pointer dereference would lead to a kernel panic, effectively crashing the system and causing a denial of service.
* **After the fix (with the warning):** No. The added check handles the NULL pointer gracefully. The `pr_warn` is a warning, not a panic. Even if `panic_on_warn` is enabled (which is rare), `pr_warn` is a `printk` warning level, not a `WARN` macro, so it wouldn't even trigger the panic.
3. **Can it be triggered by an unprivileged user?** No (with a very limited caveat on the role of namespaces). To trigger the race, you'd need to manipulate network interface states (bring them up or down) or IPv6 address configurations. This would involve things like `ip link set dev <if> down` or IPv6 address changes. Such operations require the `CAP_NET_ADMIN` capability. An unprivileged user on the host system, without `CAP_NET_ADMIN` in the network namespace, cannot perform these actions.
* *Caveat:* An unprivileged user *inside* an unprivileged user namespace *with* a network namespace can, potentially, trigger state changes within *that* namespace. However, this is isolated to *their* namespace, but this would depend on the configuration.
In summary, the questions are about standard technical vulnerability analysis, and the answers are straightforward: the *warning* itself is not exploitable and doesn't cause a DoS. The *original* bug *before* the patch could lead to a DoS. Triggering either of those requires `CAP_NET_ADMIN`.
|
| 54/4 |
2026/08/21 00:59 |
tool |
set-results |
0m
Args: map[Answer:Based on the analysis of commit `2d819d250a13` ("ipv6: Handle missing host route in __ipv6_ifa_notify") and the IPv6 address configuration subsystem in `net/ipv6/addrconf.c`, here are the answers to your questions:
---
### 1. Is this warning exploitable?
**No.**
* **The Warning:** The warning (`pr_warn(...)`) is a log message added by commit `2d819d250a13` to inform administrators when an unexpected race condition occurs. It does not trigger memory corruption or control flow redirection.
* **The Underlying Bug (Prior to the commit):** Before this commit, the race condition resulted in a kernel NULL pointer dereference when attempting to access `ifp->rt->fib6_node` without checking if `ifp->rt` was NULL. On modern Linux kernels, kernel NULL pointer dereferences are not exploitable for arbitrary code execution or privilege escalation due to protections like `mmap_min_addr`, which prevent user space from mapping address 0.
---
### 2. Can it cause a denial of service (DoS)?
* **Before Commit `2d819d250a13`:** **Yes.** The NULL pointer dereference in kernel context caused a kernel panic / oops (as documented in the crash trace in the commit log), crashing the system and causing a Denial of Service.
* **After Commit `2d819d250a13`:** **No.** The patch explicitly adds a NULL check (`if (ifp->rt && ...)`), so when the race occurs, `__ipv6_ifa_notify` logs a warning via `pr_warn` and safely skips route insertion, preventing the kernel panic. (Furthermore, `pr_warn` is a standard `printk` call, not a `WARN()` macro, so it does not trigger `panic_on_warn`).
---
### 3. Can it be triggered by an unprivileged user?
**No** (under default security configurations on the main host network namespace).
* Triggering the race requires rapidly toggling interface states (bringing a device UP to schedule `addrconf_dad_work` and bringing it DOWN via `addrconf_ifdown`).
* Changing network interface administrative states (`IFF_UP` / `NETDEV_DOWN`) or modifying IPv6 addresses requires the `CAP_NET_ADMIN` capability in the network namespace (e.g., via `rtnetlink` interface management). An unprivileged user without `CAP_NET_ADMIN` cannot execute these operations.
* *Note on User Namespaces:* If unprivileged user namespaces (`CLONE_NEWUSER` / `CLONE_NEWNET`) are enabled, an unprivileged user can obtain `CAP_NET_ADMIN` within an isolated container network namespace and toggle virtual interfaces created inside that namespace. Prior to the fix, this could have allowed an unprivileged user in a container to crash the entire host OS kernel. With the fix in place, it only logs a warning.]
Results: map[Answer:Based on the analysis of commit `2d819d250a13` ("ipv6: Handle missing host route in __ipv6_ifa_notify") and the IPv6 address configuration subsystem in `net/ipv6/addrconf.c`, here are the answers to your questions:
---
### 1. Is this warning exploitable?
**No.**
* **The Warning:** The warning (`pr_warn(...)`) is a log message added by commit `2d819d250a13` to inform administrators when an unexpected race condition occurs. It does not trigger memory corruption or control flow redirection.
* **The Underlying Bug (Prior to the commit):** Before this commit, the race condition resulted in a kernel NULL pointer dereference when attempting to access `ifp->rt->fib6_node` without checking if `ifp->rt` was NULL. On modern Linux kernels, kernel NULL pointer dereferences are not exploitable for arbitrary code execution or privilege escalation due to protections like `mmap_min_addr`, which prevent user space from mapping address 0.
---
### 2. Can it cause a denial of service (DoS)?
* **Before Commit `2d819d250a13`:** **Yes.** The NULL pointer dereference in kernel context caused a kernel panic / oops (as documented in the crash trace in the commit log), crashing the system and causing a Denial of Service.
* **After Commit `2d819d250a13`:** **No.** The patch explicitly adds a NULL check (`if (ifp->rt && ...)`), so when the race occurs, `__ipv6_ifa_notify` logs a warning via `pr_warn` and safely skips route insertion, preventing the kernel panic. (Furthermore, `pr_warn` is a standard `printk` call, not a `WARN()` macro, so it does not trigger `panic_on_warn`).
---
### 3. Can it be triggered by an unprivileged user?
**No** (under default security configurations on the main host network namespace).
* Triggering the race requires rapidly toggling interface states (bringing a device UP to schedule `addrconf_dad_work` and bringing it DOWN via `addrconf_ifdown`).
* Changing network interface administrative states (`IFF_UP` / `NETDEV_DOWN`) or modifying IPv6 addresses requires the `CAP_NET_ADMIN` capability in the network namespace (e.g., via `rtnetlink` interface management). An unprivileged user without `CAP_NET_ADMIN` cannot execute these operations.
* *Note on User Namespaces:* If unprivileged user namespaces (`CLONE_NEWUSER` / `CLONE_NEWNET`) are enabled, an unprivileged user can obtain `CAP_NET_ADMIN` within an isolated container network namespace and toggle virtual interfaces created inside that namespace. Prior to the fix, this could have allowed an unprivileged user in a container to crash the entire host OS kernel. With the fix in place, it only logs a warning.]
|
| 55/2 |
2026/08/21 00:59 |
llm |
expert |
0m
Model:
Tokens:
input: 22299
output: 66
thoughts: 0
|
| 56/2 |
2026/08/21 00:59 |
tool |
set-results |
0m
Args: map[DenialOfService:false Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:true VMGuestTrigger:false VMHostTrigger:false]
Results: map[DenialOfService:false Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:true VMGuestTrigger:false VMHostTrigger:false]
|
| 57/2 |
2026/08/21 00:59 |
llm |
expert |
0m
Model:
Tokens:
input: 22429
output: 578
thoughts: 804
Thoughts: **Analyzing the "BUG: Address ... missing its host route" Warning**
Okay, so the report points to a `pr_warn` (or maybe just a `WARN`? No, it's definitely a `pr_warn`) in `__ipv6_ifa_notify` related to a missing host route for an IPv6 address. Specifically, the message is "BUG: Address ... is missing its host route." Right, I remember that `pr_warn` being added β it was commit `2d819d250a13`.
The initial alarm bells were the "BUG:" prefix that syzbot flagged, even though this isn't a true kernel panic or `BUG()`. I've seen this before β syzbot keying off the literal string. Let's not get ahead of ourselves. Is it a denial-of-service? No. It's just a warning message to the console. It doesn't halt execution. No memory corruption involved.
Now, syzbot flagging it as a bug warrants a closer look, even though it's just a `pr_warn`. The commit message explains the warning: it's a safety net for an unexpected state where the host route is missing while the device is up. It should never happen under normal circumstances, so it is an unexpected state, but it is handled gracefully β the code avoids the problematic route insertion.
Can this be triggered in a user namespace? That's the real question. It looks like toggling the interface up and down, which can trigger the race condition, can be done in a user namespace. But, does it require any special privileges? Yes, it needs CAP_NET_ADMIN. So, while an unprivileged user in the initial namespace *can't* trigger it, an unprivileged user *can* trigger it by creating a new user and network namespace.
So, let's nail down these attributes:
* Exploitable: No.
* DenialOfService: No.
* Unprivileged: No (requires CAP_NET_ADMIN in the initial namespace, but can be done unprivileged in a user namespace).
* UserNamespace: Yes.
* VMGuestTrigger: No.
* VMHostTrigger: No.
* NetworkTrigger: No.
* RemoteTrigger: No.
* PeripheralTrigger: No.
* FilesystemTrigger: No.
This warning won't trigger any kind of panic, even with `panic_on_warn` enabled, because it only applies to `WARN()` and `WARN_ON()`, not `pr_warn()`. It's just a log message. I need to make sure syzbot doesn't misinterpret this going forward, even though the warning is helpful.
Let's summarize the reasoning for this. The "bug" is a `pr_warn` message, which handles a race between `addrconf_dad_work` and `addrconf_ifdown`. Because it is just a `pr_warn` and not `BUG()` and the code handles the missing route gracefully, it's not a memory corruption, panic or DoS. Triggering the race requires `CAP_NET_ADMIN`, so it's not unprivileged in the initial namespace, but it is in a user namespace.
|
| 58/1 |
2026/08/21 00:59 |
action |
format-explanation |
0m
Results: map[Explanation:**Analysis of the Bug Report**
**1. Nature of the Bug:**
The bug report highlights a message: `BUG: Address 2001::1 on device lo is
missing its host route.`
Looking at the kernel source code in `net/ipv6/addrconf.c`, this message is
generated by a `pr_warn()` call inside `__ipv6_ifa_notify()`. This warning was
explicitly added in commit `2d819d250a13` ("ipv6: Handle missing host route in
__ipv6_ifa_notify") to safely handle a known race condition.
The race occurs when a network interface is brought UP (scheduling Duplicate
Address Detection via `addrconf_dad_work`) and then rapidly brought DOWN
(triggering `addrconf_ifdown`, which removes the host route). If the DAD work
executes after the route has been removed, it finds `ifp->rt` as NULL. Before
the commit, this led to a NULL pointer dereference. After the commit, the kernel
safely detects this state, skips the route insertion, and simply logs the
`pr_warn` message.
**2. Exploitability:**
**Not Exploitable.** The issue is purely a logged warning (`pr_warn`). The
kernel correctly handles the unexpected state by skipping the problematic code
path. There is no memory corruption, out-of-bounds access, use-after-free, or
information leak.
**3. Denial of Service (DoS):**
**No.** Because the message is generated via `pr_warn` (and not a `BUG()` or
`WARN()` macro), it does not halt the kernel, nor does it trigger a panic even
if `panic_on_warn` is enabled. It does not cause deadlocks or resource leaks.
The system continues to function normally. Syzbot likely flagged it solely
because the log string starts with the word "BUG: ".
**4. Accessible From Unprivileged Processes:**
**No.** Triggering this race requires the ability to configure IPv6 addresses
and toggle network interface administrative states (UP/DOWN). These operations
require the `CAP_NET_ADMIN` capability. A standard unprivileged user cannot
perform these actions in the initial network namespace.
**5. Accessible From User Namespaces:**
**Yes.** An unprivileged user can create a new user namespace and a new network
namespace (`CLONE_NEWUSER | CLONE_NEWNET`). Within this isolated environment,
the user gains `CAP_NET_ADMIN` over the namespace's virtual network interfaces
(like the loopback device `lo` mentioned in the report). They can then rapidly
toggle the interface state and assign IPv6 addresses to trigger the race
condition and print the warning to the kernel log.]
|