syzbot


ID Workflow Result Correct Bug Created Started Finished Revision Error
7f41a836-7ace-4115-b883-8cf71dde2303 assessment-kcsan Benign: ✅  KCSAN: data-race in ndisc_router_discovery / ndisc_router_discovery 2026/01/09 18:55 2026/01/09 18:55 2026/01/09 19:16 7519916073b761ced56a7b15fdeeb4674e8dc125
Benign: ✅   

Explanation:
The data race reported by KCSAN is **benign**.

**Analysis:**

1.  **Race Location:** The race occurs in `ndisc_router_discovery` in `net/ipv6/ndisc.c`. The conflicting accesses are on the field `in6_dev->ra_mtu` of `struct inet6_dev`.
    *   **Read (CPU 1):** `if (in6_dev->ra_mtu != mtu)`
    *   **Write (CPU 0):** `in6_dev->ra_mtu = mtu;`

2.  **Field Usage:** The `ra_mtu` field stores the MTU value received in the last Router Advertisement (RA) message. Code search confirms that this field is primarily used for reporting status to userspace via Netlink (in `inet6_fill_ifla6_attrs` inside `net/ipv6/addrconf.c`). The actual kernel network device MTU and IPv6 configuration (`cnf.mtu6`) are handled separately in a subsequent block, which performs validation checks (e.g., `mtu < IPV6_MIN_MTU`) and uses `READ_ONCE`/`WRITE_ONCE` for the configuration field `cnf.mtu6`.

3.  **Concurrency:** When multiple RA packets are received concurrently (e.g., from different routers or a fuzzing tool), multiple CPUs may race to update `in6_dev->ra_mtu`.
    *   If the values are different, the "last winner" is arbitrary, which is acceptable for a "last received" informational field.
    *   The write is a simple assignment of a `u32` value. On aligned architectures (like x86_64), this is atomic, preventing tearing (creating a mixed value).
    *   The read side in `addrconf.c` (`inet6_fill_ifla6_attrs`) already uses `READ_ONCE(idev->ra_mtu)`, suggesting the developers anticipated concurrent access for the reader.

4.  **Impact:**
    *   **Data Integrity:** The race is on a scalar primitive (`u32`). There is no complex structure (like a list or tree) being corrupted.
    *   **Kernel Stability:** The potentially racy value in `ra_mtu` does not affect the kernel's routing decisions or packet handling limits, as those use the validated `cnf.mtu6` and `dev->mtu` fields. Even if `ra_mtu` holds an invalid value (like the `0xe5400659` seen in the report, likely from the fuzzer), it is merely reported to userspace, while the kernel's actual MTU remains safe due to the validation logic that follows the racy update.

**Conclusion:**
The race is on a statistics/informational field used for reporting the last received RA MTU to userspace. It does not compromise kernel memory safety or critical network logic. While the use of `WRITE_ONCE` would be strictly better to annotate the concurrent access, the current plain access is harmless in this context.

Crash report:
==================================================================
BUG: KCSAN: data-race in ndisc_router_discovery / ndisc_router_discovery

read to 0xffff888119809c20 of 4 bytes by task 25817 on cpu 1:
 ndisc_router_discovery+0x151d/0x1c90 net/ipv6/ndisc.c:1558
 ndisc_rcv+0x2ad/0x3d0 net/ipv6/ndisc.c:1841
 icmpv6_rcv+0xe5a/0x12f0 net/ipv6/icmp.c:989
 ip6_protocol_deliver_rcu+0xb2a/0x10d0 net/ipv6/ip6_input.c:438
 ip6_input_finish+0xf0/0x1d0 net/ipv6/ip6_input.c:489
 NF_HOOK include/linux/netfilter.h:318 [inline]
 ip6_input+0x5e/0x140 net/ipv6/ip6_input.c:500
 ip6_mc_input+0x27c/0x470 net/ipv6/ip6_input.c:590
 dst_input include/net/dst.h:474 [inline]
 ip6_rcv_finish+0x336/0x340 net/ipv6/ip6_input.c:79
 NF_HOOK include/linux/netfilter.h:318 [inline]
 ipv6_rcv+0x72/0x150 net/ipv6/ip6_input.c:311
 __netif_receive_skb_one_core net/core/dev.c:6079 [inline]
 __netif_receive_skb+0x9e/0x270 net/core/dev.c:6192
 netif_receive_skb_internal net/core/dev.c:6278 [inline]
 netif_receive_skb+0x4b/0x2e0 net/core/dev.c:6337
 tun_rx_batched+0xfc/0x430 drivers/net/tun.c:1485
 tun_get_user+0x1f36/0x26e0 drivers/net/tun.c:1953
 tun_chr_write_iter+0x15e/0x210 drivers/net/tun.c:1999
 new_sync_write fs/read_write.c:593 [inline]
 vfs_write+0x52a/0x960 fs/read_write.c:686
 ksys_write+0xda/0x1a0 fs/read_write.c:738
 __do_sys_write fs/read_write.c:749 [inline]
 __se_sys_write fs/read_write.c:746 [inline]
 __x64_sys_write+0x40/0x50 fs/read_write.c:746
 x64_sys_call+0x2802/0x3000 arch/x86/include/generated/asm/syscalls_64.h:2
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xd2/0x200 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

write to 0xffff888119809c20 of 4 bytes by task 25816 on cpu 0:
 ndisc_router_discovery+0x155a/0x1c90 net/ipv6/ndisc.c:1559
 ndisc_rcv+0x2ad/0x3d0 net/ipv6/ndisc.c:1841
 icmpv6_rcv+0xe5a/0x12f0 net/ipv6/icmp.c:989
 ip6_protocol_deliver_rcu+0xb2a/0x10d0 net/ipv6/ip6_input.c:438
 ip6_input_finish+0xf0/0x1d0 net/ipv6/ip6_input.c:489
 NF_HOOK include/linux/netfilter.h:318 [inline]
 ip6_input+0x5e/0x140 net/ipv6/ip6_input.c:500
 ip6_mc_input+0x27c/0x470 net/ipv6/ip6_input.c:590
 dst_input include/net/dst.h:474 [inline]
 ip6_rcv_finish+0x336/0x340 net/ipv6/ip6_input.c:79
 NF_HOOK include/linux/netfilter.h:318 [inline]
 ipv6_rcv+0x72/0x150 net/ipv6/ip6_input.c:311
 __netif_receive_skb_one_core net/core/dev.c:6079 [inline]
 __netif_receive_skb+0x9e/0x270 net/core/dev.c:6192
 netif_receive_skb_internal net/core/dev.c:6278 [inline]
 netif_receive_skb+0x4b/0x2e0 net/core/dev.c:6337
 tun_rx_batched+0xfc/0x430 drivers/net/tun.c:1485
 tun_get_user+0x1f36/0x26e0 drivers/net/tun.c:1953
 tun_chr_write_iter+0x15e/0x210 drivers/net/tun.c:1999
 new_sync_write fs/read_write.c:593 [inline]
 vfs_write+0x52a/0x960 fs/read_write.c:686
 ksys_write+0xda/0x1a0 fs/read_write.c:738
 __do_sys_write fs/read_write.c:749 [inline]
 __se_sys_write fs/read_write.c:746 [inline]
 __x64_sys_write+0x40/0x50 fs/read_write.c:746
 x64_sys_call+0x2802/0x3000 arch/x86/include/generated/asm/syscalls_64.h:2
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xd2/0x200 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

value changed: 0x00000000 -> 0xe5400659

Reported by Kernel Concurrency Sanitizer on:
CPU: 0 UID: 0 PID: 25816 Comm: syz.7.4303 Not tainted syzkaller #0 PREEMPT(voluntary) 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/02/2025
==================================================================

Trajectory:
Seq Timestamp Type Name Duration
0/0 2026/01/09 18:55 flow assessment-kcsan
21m Model:
unknown

Results:
map[Benign:true Explanation:The data race reported by KCSAN is **benign**.

**Analysis:**

1.  **Race Location:** The race occurs in `ndisc_router_discovery` in `net/ipv6/ndisc.c`. The conflicting accesses are on the field `in6_dev->ra_mtu` of `struct inet6_dev`.
    *   **Read (CPU 1):** `if (in6_dev->ra_mtu != mtu)`
    *   **Write (CPU 0):** `in6_dev->ra_mtu = mtu;`

2.  **Field Usage:** The `ra_mtu` field stores the MTU value received in the last Router Advertisement (RA) message. Code search confirms that this field is primarily used for reporting status to userspace via Netlink (in `inet6_fill_ifla6_attrs` inside `net/ipv6/addrconf.c`). The actual kernel network device MTU and IPv6 configuration (`cnf.mtu6`) are handled separately in a subsequent block, which performs validation checks (e.g., `mtu < IPV6_MIN_MTU`) and uses `READ_ONCE`/`WRITE_ONCE` for the configuration field `cnf.mtu6`.

3.  **Concurrency:** When multiple RA packets are received concurrently (e.g., from different routers or a fuzzing tool), multiple CPUs may race to update `in6_dev->ra_mtu`.
    *   If the values are different, the "last winner" is arbitrary, which is acceptable for a "last received" informational field.
    *   The write is a simple assignment of a `u32` value. On aligned architectures (like x86_64), this is atomic, preventing tearing (creating a mixed value).
    *   The read side in `addrconf.c` (`inet6_fill_ifla6_attrs`) already uses `READ_ONCE(idev->ra_mtu)`, suggesting the developers anticipated concurrent access for the reader.

4.  **Impact:**
    *   **Data Integrity:** The race is on a scalar primitive (`u32`). There is no complex structure (like a list or tree) being corrupted.
    *   **Kernel Stability:** The potentially racy value in `ra_mtu` does not affect the kernel's routing decisions or packet handling limits, as those use the validated `cnf.mtu6` and `dev->mtu` fields. Even if `ra_mtu` holds an invalid value (like the `0xe5400659` seen in the report, likely from the fuzzer), it is merely reported to userspace, while the kernel's actual MTU remains safe due to the validation logic that follows the racy update.

**Conclusion:**
The race is on a statistics/informational field used for reporting the last received RA MTU to userspace. It does not compromise kernel memory safety or critical network logic. While the use of `WRITE_ONCE` would be strictly better to annotate the concurrent access, the current plain access is harmless in this context.]

1/1 2026/01/09 18:55 action kernel-checkouter
0m Model:
unknown

Results:
map[KernelSrc:/usr/local/google/home/dvyukov/syzkaller/agent/workdir/cache/src/95f6015e502468c7b88a4d5b68cecc63fccd5032]

2/1 2026/01/09 18:56 action kernel-builder
3m Model:
unknown

Results:
map[KernelObj:/usr/local/google/home/dvyukov/syzkaller/agent/workdir/cache/build/f644e979037a40f8c304f0cbdadb36140c6bc2cc]

3/1 2026/01/09 19:00 action codesearch-prepare
13m Model:
unknown

Results:
map[Index:codesearch-index]

4/1 2026/01/09 19:14 agent expert
2m Model:
unknown

Results:
map[Benign:true]

Instruction:
You are an experienced Linux kernel developer tasked with determining if the given kernel
data race is benign or not. The data race report is from KCSAN tool.
It contains 2 stack traces of the memory accesses that constitute a data race.

The report would be non-actionable, if the underlysing data race is "benign".
That is, the race is on a simple int/bool or similar field, and the accesses
are not supposed to be protected by any mutual exclusion primitives.
Common examples of such "benign" data races are accesses to various flags fields,
statistics counters, and similar.
An actionable race is "harmful", that is can lead to corruption/crash even with
a conservative compiler that compiles memory accesses to primitive types
effectively as atomic. A common example of a "harmful" data races is race on
a complex container (list/hashmap/etc), where accesses are supposed to be protected
by a mutual exclusion primitive.
In the final reply explain why you think the report is consistent and the data race is harmful.

Use the provided tools to confirm any assumptions, what variables/fields being accessed, etc.
In particular, don't make assumptions about the kernel source code,
use codesearch tools to read the actual source code.


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 data race report is:

==================================================================
BUG: KCSAN: data-race in ndisc_router_discovery / ndisc_router_discovery

read to 0xffff888119809c20 of 4 bytes by task 25817 on cpu 1:
 ndisc_router_discovery+0x151d/0x1c90 net/ipv6/ndisc.c:1558
 ndisc_rcv+0x2ad/0x3d0 net/ipv6/ndisc.c:1841
 icmpv6_rcv+0xe5a/0x12f0 net/ipv6/icmp.c:989
 ip6_protocol_deliver_rcu+0xb2a/0x10d0 net/ipv6/ip6_input.c:438
 ip6_input_finish+0xf0/0x1d0 net/ipv6/ip6_input.c:489
 NF_HOOK include/linux/netfilter.h:318 [inline]
 ip6_input+0x5e/0x140 net/ipv6/ip6_input.c:500
 ip6_mc_input+0x27c/0x470 net/ipv6/ip6_input.c:590
 dst_input include/net/dst.h:474 [inline]
 ip6_rcv_finish+0x336/0x340 net/ipv6/ip6_input.c:79
 NF_HOOK include/linux/netfilter.h:318 [inline]
 ipv6_rcv+0x72/0x150 net/ipv6/ip6_input.c:311
 __netif_receive_skb_one_core net/core/dev.c:6079 [inline]
 __netif_receive_skb+0x9e/0x270 net/core/dev.c:6192
 netif_receive_skb_internal net/core/dev.c:6278 [inline]
 netif_receive_skb+0x4b/0x2e0 net/core/dev.c:6337
 tun_rx_batched+0xfc/0x430 drivers/net/tun.c:1485
 tun_get_user+0x1f36/0x26e0 drivers/net/tun.c:1953
 tun_chr_write_iter+0x15e/0x210 drivers/net/tun.c:1999
 new_sync_write fs/read_write.c:593 [inline]
 vfs_write+0x52a/0x960 fs/read_write.c:686
 ksys_write+0xda/0x1a0 fs/read_write.c:738
 __do_sys_write fs/read_write.c:749 [inline]
 __se_sys_write fs/read_write.c:746 [inline]
 __x64_sys_write+0x40/0x50 fs/read_write.c:746
 x64_sys_call+0x2802/0x3000 arch/x86/include/generated/asm/syscalls_64.h:2
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xd2/0x200 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

write to 0xffff888119809c20 of 4 bytes by task 25816 on cpu 0:
 ndisc_router_discovery+0x155a/0x1c90 net/ipv6/ndisc.c:1559
 ndisc_rcv+0x2ad/0x3d0 net/ipv6/ndisc.c:1841
 icmpv6_rcv+0xe5a/0x12f0 net/ipv6/icmp.c:989
 ip6_protocol_deliver_rcu+0xb2a/0x10d0 net/ipv6/ip6_input.c:438
 ip6_input_finish+0xf0/0x1d0 net/ipv6/ip6_input.c:489
 NF_HOOK include/linux/netfilter.h:318 [inline]
 ip6_input+0x5e/0x140 net/ipv6/ip6_input.c:500
 ip6_mc_input+0x27c/0x470 net/ipv6/ip6_input.c:590
 dst_input include/net/dst.h:474 [inline]
 ip6_rcv_finish+0x336/0x340 net/ipv6/ip6_input.c:79
 NF_HOOK include/linux/netfilter.h:318 [inline]
 ipv6_rcv+0x72/0x150 net/ipv6/ip6_input.c:311
 __netif_receive_skb_one_core net/core/dev.c:6079 [inline]
 __netif_receive_skb+0x9e/0x270 net/core/dev.c:6192
 netif_receive_skb_internal net/core/dev.c:6278 [inline]
 netif_receive_skb+0x4b/0x2e0 net/core/dev.c:6337
 tun_rx_batched+0xfc/0x430 drivers/net/tun.c:1485
 tun_get_user+0x1f36/0x26e0 drivers/net/tun.c:1953
 tun_chr_write_iter+0x15e/0x210 drivers/net/tun.c:1999
 new_sync_write fs/read_write.c:593 [inline]
 vfs_write+0x52a/0x960 fs/read_write.c:686
 ksys_write+0xda/0x1a0 fs/read_write.c:738
 __do_sys_write fs/read_write.c:749 [inline]
 __se_sys_write fs/read_write.c:746 [inline]
 __x64_sys_write+0x40/0x50 fs/read_write.c:746
 x64_sys_call+0x2802/0x3000 arch/x86/include/generated/asm/syscalls_64.h:2
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xd2/0x200 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

value changed: 0x00000000 -> 0xe5400659

Reported by Kernel Concurrency Sanitizer on:
CPU: 0 UID: 0 PID: 25816 Comm: syz.7.4303 Not tainted syzkaller #0 PREEMPT(voluntary) 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/02/2025
==================================================================


Reply:
The data race reported by KCSAN is **benign**.

**Analysis:**

1.  **Race Location:** The race occurs in `ndisc_router_discovery` in `net/ipv6/ndisc.c`. The conflicting accesses are on the field `in6_dev->ra_mtu` of `struct inet6_dev`.
    *   **Read (CPU 1):** `if (in6_dev->ra_mtu != mtu)`
    *   **Write (CPU 0):** `in6_dev->ra_mtu = mtu;`

2.  **Field Usage:** The `ra_mtu` field stores the MTU value received in the last Router Advertisement (RA) message. Code search confirms that this field is primarily used for reporting status to userspace via Netlink (in `inet6_fill_ifla6_attrs` inside `net/ipv6/addrconf.c`). The actual kernel network device MTU and IPv6 configuration (`cnf.mtu6`) are handled separately in a subsequent block, which performs validation checks (e.g., `mtu < IPV6_MIN_MTU`) and uses `READ_ONCE`/`WRITE_ONCE` for the configuration field `cnf.mtu6`.

3.  **Concurrency:** When multiple RA packets are received concurrently (e.g., from different routers or a fuzzing tool), multiple CPUs may race to update `in6_dev->ra_mtu`.
    *   If the values are different, the "last winner" is arbitrary, which is acceptable for a "last received" informational field.
    *   The write is a simple assignment of a `u32` value. On aligned architectures (like x86_64), this is atomic, preventing tearing (creating a mixed value).
    *   The read side in `addrconf.c` (`inet6_fill_ifla6_attrs`) already uses `READ_ONCE(idev->ra_mtu)`, suggesting the developers anticipated concurrent access for the reader.

4.  **Impact:**
    *   **Data Integrity:** The race is on a scalar primitive (`u32`). There is no complex structure (like a list or tree) being corrupted.
    *   **Kernel Stability:** The potentially racy value in `ra_mtu` does not affect the kernel's routing decisions or packet handling limits, as those use the validated `cnf.mtu6` and `dev->mtu` fields. Even if `ra_mtu` holds an invalid value (like the `0xe5400659` seen in the report, likely from the fuzzer), it is merely reported to userspace, while the kernel's actual MTU remains safe due to the validation logic that follows the racy update.

**Conclusion:**
The race is on a statistics/informational field used for reporting the last received RA MTU to userspace. It does not compromise kernel memory safety or critical network logic. While the use of `WRITE_ONCE` would be strictly better to annotate the concurrent access, the current plain access is harmless in this context.

5/2 2026/01/09 19:14 llm expert
0m Model:
unknown

Thoughts:
**Analyzing a KCSAN Data Race in `ndisc_router_discovery`**

Okay, so I've got a KCSAN data race report, and it's pointing to `ndisc_router_discovery` in the Linux kernel's IPv6 neighbor discovery code. My job is to dig into this. I see the report identifies a read and a write access occurring at lines 1558 and 1559 of `net/ipv6/ndisc.c`, both within the `ndisc_router_discovery` function itself. The call stack indicates this function is reached via the typical networking receive path: `ndisc_rcv` -> `icmpv6_rcv` and so on, suggesting we are dealing with Router Advertisement (RA) packet processing.

The value that's changed, `0x00000000 -> 0xe5400659`, looks like a timestamp, a counter, or perhaps some kind of timer value. My immediate thought is that these are likely two different RAs, arriving around the same time and being processed concurrently. It could also be some kind of loopback or multicast scenario, but that's less likely.

My first step is to dive right into the source code, specifically `net/ipv6/ndisc.c`, around those crucial lines 1558 and 1559. I need to understand what variable is being accessed at those locations. Is it updating a statistic, a timer, or a critical flag? Based on the callstack, there is nothing obviously problematic that is standing out.

Once I have the context of the code, I'll analyze the logic. Is the race benign – say, a slightly racy statistic update that won't cause major problems, or perhaps a timer update where minor inaccuracies are acceptable? Or is it a critical race, potentially leading to corruption of a data structure, or an update that is missed, causing issues down the line?

I'll start by skipping the listing of entities in `ndisc.c`. Just reading the source will be quicker and more effective. I'm going to look at the relevant code and work from there.



6/2 2026/01/09 19:14 tool codesearch-definition-source
0m Model:
unknown

Args:
map[IncludeLines:true Name:ndisc_router_discovery SourceFile:net/ipv6/ndisc.c]

Results:
map[Missing:false SourceCode:1228:	static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb)
1229:	{
1230:		struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
1231:		bool send_ifinfo_notify = false;
1232:		struct neighbour *neigh = NULL;
1233:		struct ndisc_options ndopts;
1234:		struct fib6_info *rt = NULL;
1235:		struct inet6_dev *in6_dev;
1236:		struct fib6_table *table;
1237:		u32 defrtr_usr_metric;
1238:		unsigned int pref = 0;
1239:		__u32 old_if_flags;
1240:		struct net *net;
1241:		SKB_DR(reason);
1242:		int lifetime;
1243:		int optlen;
1244:	
1245:		__u8 *opt = (__u8 *)(ra_msg + 1);
1246:	
1247:		optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
1248:			sizeof(struct ra_msg);
1249:	
1250:		net_dbg_ratelimited("RA: %s, dev: %s\n", __func__, skb->dev->name);
1251:		if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
1252:			net_dbg_ratelimited("RA: source address is not link-local\n");
1253:			return reason;
1254:		}
1255:		if (optlen < 0)
1256:			return SKB_DROP_REASON_PKT_TOO_SMALL;
1257:	
1258:	#ifdef CONFIG_IPV6_NDISC_NODETYPE
1259:		if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
1260:			net_dbg_ratelimited("RA: from host or unauthorized router\n");
1261:			return reason;
1262:		}
1263:	#endif
1264:	
1265:		in6_dev = __in6_dev_get(skb->dev);
1266:		if (!in6_dev) {
1267:			net_err_ratelimited("RA: can't find inet6 device for %s\n", skb->dev->name);
1268:			return reason;
1269:		}
1270:	
1271:		if (!ndisc_parse_options(skb->dev, opt, optlen, &ndopts))
1272:			return SKB_DROP_REASON_IPV6_NDISC_BAD_OPTIONS;
1273:	
1274:		if (!ipv6_accept_ra(in6_dev)) {
1275:			net_dbg_ratelimited("RA: %s, did not accept ra for dev: %s\n", __func__,
1276:					    skb->dev->name);
1277:			goto skip_linkparms;
1278:		}
1279:	
1280:	#ifdef CONFIG_IPV6_NDISC_NODETYPE
1281:		/* skip link-specific parameters from interior routers */
1282:		if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1283:			net_dbg_ratelimited("RA: %s, nodetype is NODEFAULT, dev: %s\n", __func__,
1284:					    skb->dev->name);
1285:			goto skip_linkparms;
1286:		}
1287:	#endif
1288:	
1289:		if (in6_dev->if_flags & IF_RS_SENT) {
1290:			/*
1291:			 *	flag that an RA was received after an RS was sent
1292:			 *	out on this interface.
1293:			 */
1294:			in6_dev->if_flags |= IF_RA_RCVD;
1295:		}
1296:	
1297:		/*
1298:		 * Remember the managed/otherconf flags from most recently
1299:		 * received RA message (RFC 2462) -- yoshfuji
1300:		 */
1301:		old_if_flags = in6_dev->if_flags;
1302:		in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1303:					IF_RA_OTHERCONF)) |
1304:					(ra_msg->icmph.icmp6_addrconf_managed ?
1305:						IF_RA_MANAGED : 0) |
1306:					(ra_msg->icmph.icmp6_addrconf_other ?
1307:						IF_RA_OTHERCONF : 0);
1308:	
1309:		if (old_if_flags != in6_dev->if_flags)
1310:			send_ifinfo_notify = true;
1311:	
1312:		if (!READ_ONCE(in6_dev->cnf.accept_ra_defrtr)) {
1313:			net_dbg_ratelimited("RA: %s, defrtr is false for dev: %s\n", __func__,
1314:					    skb->dev->name);
1315:			goto skip_defrtr;
1316:		}
1317:	
1318:		lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1319:		if (lifetime != 0 &&
1320:		    lifetime < READ_ONCE(in6_dev->cnf.accept_ra_min_lft)) {
1321:			net_dbg_ratelimited("RA: router lifetime (%ds) is too short: %s\n", lifetime,
1322:					    skb->dev->name);
1323:			goto skip_defrtr;
1324:		}
1325:	
1326:		/* Do not accept RA with source-addr found on local machine unless
1327:		 * accept_ra_from_local is set to true.
1328:		 */
1329:		net = dev_net(in6_dev->dev);
1330:		if (!READ_ONCE(in6_dev->cnf.accept_ra_from_local) &&
1331:		    ipv6_chk_addr(net, &ipv6_hdr(skb)->saddr, in6_dev->dev, 0)) {
1332:			net_dbg_ratelimited("RA from local address detected on dev: %s: default router ignored\n",
1333:					    skb->dev->name);
1334:			goto skip_defrtr;
1335:		}
1336:	
1337:	#ifdef CONFIG_IPV6_ROUTER_PREF
1338:		pref = ra_msg->icmph.icmp6_router_pref;
1339:		/* 10b is handled as if it were 00b (medium) */
1340:		if (pref == ICMPV6_ROUTER_PREF_INVALID ||
1341:		    !READ_ONCE(in6_dev->cnf.accept_ra_rtr_pref))
1342:			pref = ICMPV6_ROUTER_PREF_MEDIUM;
1343:	#endif
1344:		/* routes added from RAs do not use nexthop objects */
1345:		rt = rt6_get_dflt_router(net, &ipv6_hdr(skb)->saddr, skb->dev);
1346:		if (rt) {
1347:			neigh = ip6_neigh_lookup(&rt->fib6_nh->fib_nh_gw6,
1348:						 rt->fib6_nh->fib_nh_dev, NULL,
1349:						  &ipv6_hdr(skb)->saddr);
1350:			if (!neigh) {
1351:				net_err_ratelimited("RA: %s got default router without neighbour\n",
1352:						    __func__);
1353:				fib6_info_release(rt);
1354:				return reason;
1355:			}
1356:		}
1357:		/* Set default route metric as specified by user */
1358:		defrtr_usr_metric = in6_dev->cnf.ra_defrtr_metric;
1359:		/* delete the route if lifetime is 0 or if metric needs change */
1360:		if (rt && (lifetime == 0 || rt->fib6_metric != defrtr_usr_metric)) {
1361:			ip6_del_rt(net, rt, false);
1362:			rt = NULL;
1363:		}
1364:	
1365:		net_dbg_ratelimited("RA: rt: %p  lifetime: %d, metric: %d, for dev: %s\n", rt, lifetime,
1366:				    defrtr_usr_metric, skb->dev->name);
1367:		if (!rt && lifetime) {
1368:			net_dbg_ratelimited("RA: adding default router\n");
1369:	
1370:			if (neigh)
1371:				neigh_release(neigh);
1372:	
1373:			rt = rt6_add_dflt_router(net, &ipv6_hdr(skb)->saddr,
1374:						 skb->dev, pref, defrtr_usr_metric,
1375:						 lifetime);
1376:			if (!rt) {
1377:				net_err_ratelimited("RA: %s failed to add default route\n", __func__);
1378:				return reason;
1379:			}
1380:	
1381:			neigh = ip6_neigh_lookup(&rt->fib6_nh->fib_nh_gw6,
1382:						 rt->fib6_nh->fib_nh_dev, NULL,
1383:						  &ipv6_hdr(skb)->saddr);
1384:			if (!neigh) {
1385:				net_err_ratelimited("RA: %s got default router without neighbour\n",
1386:						    __func__);
1387:				fib6_info_release(rt);
1388:				return reason;
1389:			}
1390:			neigh->flags |= NTF_ROUTER;
1391:		} else if (rt && IPV6_EXTRACT_PREF(rt->fib6_flags) != pref) {
1392:			struct nl_info nlinfo = {
1393:				.nl_net = net,
1394:			};
1395:			rt->fib6_flags = (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
1396:			inet6_rt_notify(RTM_NEWROUTE, rt, &nlinfo, NLM_F_REPLACE);
1397:		}
1398:	
1399:		if (rt) {
1400:			table = rt->fib6_table;
1401:			spin_lock_bh(&table->tb6_lock);
1402:	
1403:			fib6_set_expires(rt, jiffies + (HZ * lifetime));
1404:			fib6_add_gc_list(rt);
1405:	
1406:			spin_unlock_bh(&table->tb6_lock);
1407:		}
1408:		if (READ_ONCE(in6_dev->cnf.accept_ra_min_hop_limit) < 256 &&
1409:		    ra_msg->icmph.icmp6_hop_limit) {
1410:			if (READ_ONCE(in6_dev->cnf.accept_ra_min_hop_limit) <=
1411:			    ra_msg->icmph.icmp6_hop_limit) {
1412:				WRITE_ONCE(in6_dev->cnf.hop_limit,
1413:					   ra_msg->icmph.icmp6_hop_limit);
1414:				fib6_metric_set(rt, RTAX_HOPLIMIT,
1415:						ra_msg->icmph.icmp6_hop_limit);
1416:			} else {
1417:				net_dbg_ratelimited("RA: Got route advertisement with lower hop_limit than minimum\n");
1418:			}
1419:		}
1420:	
1421:	skip_defrtr:
1422:	
1423:		/*
1424:		 *	Update Reachable Time and Retrans Timer
1425:		 */
1426:	
1427:		if (in6_dev->nd_parms) {
1428:			unsigned long rtime = ntohl(ra_msg->retrans_timer);
1429:	
1430:			if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1431:				rtime = (rtime*HZ)/1000;
1432:				if (rtime < HZ/100)
1433:					rtime = HZ/100;
1434:				NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
1435:				in6_dev->tstamp = jiffies;
1436:				send_ifinfo_notify = true;
1437:			}
1438:	
1439:			rtime = ntohl(ra_msg->reachable_time);
1440:			if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1441:				rtime = (rtime*HZ)/1000;
1442:	
1443:				if (rtime < HZ/10)
1444:					rtime = HZ/10;
1445:	
1446:				if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) {
1447:					NEIGH_VAR_SET(in6_dev->nd_parms,
1448:						      BASE_REACHABLE_TIME, rtime);
1449:					NEIGH_VAR_SET(in6_dev->nd_parms,
1450:						      GC_STALETIME, 3 * rtime);
1451:					in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1452:					in6_dev->tstamp = jiffies;
1453:					send_ifinfo_notify = true;
1454:				}
1455:			}
1456:		}
1457:	
1458:	skip_linkparms:
1459:	
1460:		/*
1461:		 *	Process options.
1462:		 */
1463:	
1464:		if (!neigh)
1465:			neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
1466:					       skb->dev, 1);
1467:		if (neigh) {
1468:			u8 *lladdr = NULL;
1469:			if (ndopts.nd_opts_src_lladdr) {
1470:				lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1471:							     skb->dev);
1472:				if (!lladdr) {
1473:					net_dbg_ratelimited("RA: invalid link-layer address length\n");
1474:					goto out;
1475:				}
1476:			}
1477:			ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
1478:				     NEIGH_UPDATE_F_WEAK_OVERRIDE|
1479:				     NEIGH_UPDATE_F_OVERRIDE|
1480:				     NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1481:				     NEIGH_UPDATE_F_ISROUTER,
1482:				     NDISC_ROUTER_ADVERTISEMENT, &ndopts);
1483:			reason = SKB_CONSUMED;
1484:		}
1485:	
1486:		if (!ipv6_accept_ra(in6_dev)) {
1487:			net_dbg_ratelimited("RA: %s, accept_ra is false for dev: %s\n", __func__,
1488:					    skb->dev->name);
1489:			goto out;
1490:		}
1491:	
1492:	#ifdef CONFIG_IPV6_ROUTE_INFO
1493:		if (!READ_ONCE(in6_dev->cnf.accept_ra_from_local) &&
1494:		    ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1495:				  in6_dev->dev, 0)) {
1496:			net_dbg_ratelimited("RA from local address detected on dev: %s: router info ignored.\n",
1497:					    skb->dev->name);
1498:			goto skip_routeinfo;
1499:		}
1500:	
1501:		if (READ_ONCE(in6_dev->cnf.accept_ra_rtr_pref) && ndopts.nd_opts_ri) {
1502:			struct nd_opt_hdr *p;
1503:			for (p = ndopts.nd_opts_ri;
1504:			     p;
1505:			     p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
1506:				struct route_info *ri = (struct route_info *)p;
1507:	#ifdef CONFIG_IPV6_NDISC_NODETYPE
1508:				if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1509:				    ri->prefix_len == 0)
1510:					continue;
1511:	#endif
1512:				if (ri->prefix_len == 0 &&
1513:				    !READ_ONCE(in6_dev->cnf.accept_ra_defrtr))
1514:					continue;
1515:				if (ri->lifetime != 0 &&
1516:				    ntohl(ri->lifetime) < READ_ONCE(in6_dev->cnf.accept_ra_min_lft))
1517:					continue;
1518:				if (ri->prefix_len < READ_ONCE(in6_dev->cnf.accept_ra_rt_info_min_plen))
1519:					continue;
1520:				if (ri->prefix_len > READ_ONCE(in6_dev->cnf.accept_ra_rt_info_max_plen))
1521:					continue;
1522:				rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3,
1523:					      &ipv6_hdr(skb)->saddr);
1524:			}
1525:		}
1526:	
1527:	skip_routeinfo:
1528:	#endif
1529:	
1530:	#ifdef CONFIG_IPV6_NDISC_NODETYPE
1531:		/* skip link-specific ndopts from interior routers */
1532:		if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
1533:			net_dbg_ratelimited("RA: %s, nodetype is NODEFAULT (interior routes), dev: %s\n",
1534:					    __func__, skb->dev->name);
1535:			goto out;
1536:		}
1537:	#endif
1538:	
1539:		if (READ_ONCE(in6_dev->cnf.accept_ra_pinfo) && ndopts.nd_opts_pi) {
1540:			struct nd_opt_hdr *p;
1541:			for (p = ndopts.nd_opts_pi;
1542:			     p;
1543:			     p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
1544:				addrconf_prefix_rcv(skb->dev, (u8 *)p,
1545:						    (p->nd_opt_len) << 3,
1546:						    ndopts.nd_opts_src_lladdr != NULL);
1547:			}
1548:		}
1549:	
1550:		if (ndopts.nd_opts_mtu && READ_ONCE(in6_dev->cnf.accept_ra_mtu)) {
1551:			__be32 n;
1552:			u32 mtu;
1553:	
1554:			memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
1555:			mtu = ntohl(n);
1556:	
1557:			if (in6_dev->ra_mtu != mtu) {
1558:				in6_dev->ra_mtu = mtu;
1559:				send_ifinfo_notify = true;
1560:			}
1561:	
1562:			if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
1563:				net_dbg_ratelimited("RA: invalid mtu: %d\n", mtu);
1564:			} else if (READ_ONCE(in6_dev->cnf.mtu6) != mtu) {
1565:				WRITE_ONCE(in6_dev->cnf.mtu6, mtu);
1566:				fib6_metric_set(rt, RTAX_MTU, mtu);
1567:				rt6_mtu_change(skb->dev, mtu);
1568:			}
1569:		}
1570:	
1571:		if (ndopts.nd_useropts) {
1572:			struct nd_opt_hdr *p;
1573:			for (p = ndopts.nd_useropts;
1574:			     p;
1575:			     p = ndisc_next_useropt(skb->dev, p,
1576:						    ndopts.nd_useropts_end)) {
1577:				ndisc_ra_useropt(skb, p);
1578:			}
1579:		}
1580:	
1581:		if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
1582:			net_dbg_ratelimited("RA: invalid RA options\n");
1583:		}
1584:	out:
1585:		/* Send a notify if RA changed managed/otherconf flags or
1586:		 * timer settings or ra_mtu value
1587:		 */
1588:		if (send_ifinfo_notify)
1589:			inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1590:	
1591:		fib6_info_release(rt);
1592:		if (neigh)
1593:			neigh_release(neigh);
1594:		return reason;
1595:	}
 SourceFile:net/ipv6/ndisc.c]

7/2 2026/01/09 19:14 llm expert
0m Model:
unknown

Thoughts:
**Analyzing the Reported Race Condition**

Okay, so I've been given a report that points to a potential race condition within the `ndisc_router_discovery` function, specifically around lines 1558 and 1559. The report flags a read and a write to `in6_dev->ra_mtu` at those respective lines. Let's see if I can match this to the source code that I have on hand.

Right, looking at the code, I see the following snippet:

```c
1557:			if (in6_dev->ra_mtu != mtu) {
1558:				in6_dev->ra_mtu = mtu;
1559:				send_ifinfo_notify = true;
1560:			}
```

The context seems to line up perfectly. Line 1558 shows the write to `in6_dev->ra_mtu` and 1557 shows the read of `in6_dev->ra_mtu`. The code checks if the existing `ra_mtu` doesn't match the new MTU value (`mtu`), and if so, it updates it. So, we're definitely looking at the right spot.

The race is likely on `in6_dev->ra_mtu`. Since `in6_dev` is a `struct inet6_dev *`, `ra_mtu` is most likely a field in that struct. This implies that this `ra_mtu` variable holds the MTU value that's received through Router Advertisements. This makes sense - the router is advertising a new MTU, and we need to update our local configuration to match.

My next step is to examine the `struct inet6_dev` definition to confirm the exact type and how this field is accessed and used.



8/2 2026/01/09 19:14 tool codesearch-definition-source
0m Model:
unknown

Args:
map[IncludeLines:true Name:inet6_dev SourceFile:include/net/if_inet6.h]

Results:
map[Missing:true SourceCode: SourceFile:]

9/2 2026/01/09 19:14 llm expert
0m Model:
unknown

Thoughts:
Okay, here's my thought process on this, from my perspective:

**Debugging the `inet6_dev` Structure Definition**

Alright, so I'm trying to track down the definition of `struct inet6_dev`. My initial hunch is that it's in `include/net/if_inet6.h`, but I'm having a nagging feeling that I might be mistaken about the exact file, or perhaps the naming is slightly off. Happens to the best of us when you're jumping around in kernel source! It’s also often defined in `include/linux/ipv6.h`.

Given that uncertainty, I think the next logical step is to quickly verify if it's in `include/linux/ipv6.h`. It’s a common location and worth a quick look before diving deeper into the include paths. Let me check that.



10/2 2026/01/09 19:14 tool codesearch-definition-source
0m Model:
unknown

Args:
map[IncludeLines:true Name:inet6_dev SourceFile:include/linux/ipv6.h]

Results:
map[Missing:true SourceCode: SourceFile:]

11/2 2026/01/09 19:14 llm expert
0m Model:
unknown

12/2 2026/01/09 19:14 tool codesearch-file-index
0m Model:
unknown

Args:
map[SourceFile:include/net/if_inet6.h]

Results:
map[Entities:[map[Kind:function Name:ipv6_arcnet_mc_map] map[Kind:function Name:ipv6_eth_mc_map] map[Kind:function Name:ipv6_ib_mc_map] map[Kind:function Name:ipv6_ipgre_mc_map]] Missing:false]

13/2 2026/01/09 19:14 llm expert
0m Model:
unknown

Thoughts:
**Analyzing a Potential Race Condition in IPv6 Router Advertisement Processing**

Okay, this is interesting. I was initially thrown off because the indexer wasn't immediately finding `struct inet6_dev`, but I've traced it to `ndisc.c` and know it's a core structure. I'm now pretty sure it's defined in one of the include files, likely `include/net/if_inet6.h` or something similar, though the search tool didn't readily locate it.

Based on the code in `ndisc.c`, it looks like `ra_mtu` within the `inet6_dev` structure is the target of the investigation, specifically within the `ndisc_router_discovery` function, and my initial hunch is that we might have a concurrency issue.

The code reads `in6_dev->ra_mtu` to check if the advertised MTU (`mtu`) differs. If it does, `in6_dev->ra_mtu` is updated with the new `mtu`, and a notification is sent. The race is that a CPU could be interrupted between the read and write operations.

If multiple Router Advertisements (RAs) arrive concurrently, all with different MTUs, the `ra_mtu` value could become out-of-sync. The field is shared across packets and attached to the net_device. Multiple reads and writes could happen without proper locking.

I see that `ndisc_router_discovery` is called in the RX path and there is a `spin_lock_bh` being held, but it's not the initial lock for the whole function.

The code checks if `in6_dev->ra_mtu` differs from the incoming `mtu`. If the incoming MTUs from RAs are different, then a race could occur where the final `ra_mtu` gets set to either of the two, while `send_ifinfo_notify` is set to true for both.
This sends `RTM_NEWLINK` notifications to userspace. In that notification, userspace can get the MTU. If `ra_mtu` is modified, the userspace gets different MTUs.

The code then checks `in6_dev->cnf.mtu6`. This value is accessed with `READ_ONCE` and `WRITE_ONCE`, suggesting the developers were aware of concurrency issues for that field. However, `ra_mtu` is accessed without these atomics.
This looks like an oversight.

I will need to verify where `ra_mtu` is used, and what effect this race has, as it is used to report to userspace and the consequences of inaccurate updates.



14/2 2026/01/09 19:15 tool codesearch-file-index
0m Model:
unknown

Args:
map[SourceFile:net/ipv6/addrconf.c]

Results:
map[Entities:[map[Kind:function Name:__addrconf_sysctl_register] map[Kind:function Name:__addrconf_sysctl_unregister] map[Kind:function Name:__ipv6_chk_addr_and_flags] map[Kind:function Name:__ipv6_dev_get_saddr] map[Kind:function Name:__ipv6_get_lladdr] map[Kind:function Name:__ipv6_ifa_notify] map[Kind:function Name:__ipv6_ifa_notify] map[Kind:function Name:__ipv6_isatap_ifid] map[Kind:function Name:__snmp6_fill_stats64] map[Kind:function Name:__snmp6_fill_statsdev] map[Kind:function Name:add_addr] map[Kind:function Name:add_v4_addrs] map[Kind:function Name:addr_is_local] map[Kind:function Name:addrconf_add_dev] map[Kind:function Name:addrconf_add_ifaddr] map[Kind:function Name:addrconf_add_linklocal] map[Kind:function Name:addrconf_add_linklocal] map[Kind:function Name:addrconf_add_mroute] map[Kind:function Name:addrconf_addr_gen] map[Kind:function Name:addrconf_cleanup] map[Kind:function Name:addrconf_dad_begin] map[Kind:function Name:addrconf_dad_completed] map[Kind:function Name:addrconf_dad_completed] map[Kind:function Name:addrconf_dad_end] map[Kind:function Name:addrconf_dad_failure] map[Kind:function Name:addrconf_dad_kick] map[Kind:function Name:addrconf_dad_run] map[Kind:function Name:addrconf_dad_run] map[Kind:function Name:addrconf_dad_start] map[Kind:function Name:addrconf_dad_start] map[Kind:function Name:addrconf_dad_stop] map[Kind:function Name:addrconf_dad_work] map[Kind:function Name:addrconf_dad_work] map[Kind:function Name:addrconf_del_dad_work] map[Kind:function Name:addrconf_del_ifaddr] map[Kind:function Name:addrconf_del_rs_timer] map[Kind:function Name:addrconf_dev_config] map[Kind:function Name:addrconf_disable_change] map[Kind:function Name:addrconf_disable_ipv6] map[Kind:function Name:addrconf_disable_policy] map[Kind:function Name:addrconf_disable_policy_idev] map[Kind:function Name:addrconf_exit_net] map[Kind:function Name:addrconf_fixup_forwarding] map[Kind:function Name:addrconf_fixup_linkdown] map[Kind:function Name:addrconf_force_forward_change] map[Kind:function Name:addrconf_forward_change] map[Kind:function Name:addrconf_get_prefix_route] map[Kind:function Name:addrconf_get_prefix_route] map[Kind:function Name:addrconf_gre_config] map[Kind:function Name:addrconf_ifdown] map[Kind:function Name:addrconf_ifdown] map[Kind:function Name:addrconf_ifid_6lowpan] map[Kind:function Name:addrconf_ifid_arcnet] map[Kind:function Name:addrconf_ifid_gre] map[Kind:function Name:addrconf_ifid_ieee1394] map[Kind:function Name:addrconf_ifid_infiniband] map[Kind:function Name:addrconf_ifid_ip6tnl] map[Kind:function Name:addrconf_ifid_sit] map[Kind:function Name:addrconf_init] map[Kind:function Name:addrconf_init_auto_addrs] map[Kind:function Name:addrconf_init_net] map[Kind:function Name:addrconf_join_anycast] map[Kind:function Name:addrconf_join_anycast] map[Kind:function Name:addrconf_join_solict] map[Kind:function Name:addrconf_leave_anycast] map[Kind:function Name:addrconf_leave_anycast] map[Kind:function Name:addrconf_leave_solict] map[Kind:function Name:addrconf_link_ready] map[Kind:function Name:addrconf_linkdown_change] map[Kind:function Name:addrconf_mod_dad_work] map[Kind:function Name:addrconf_mod_rs_timer] map[Kind:function Name:addrconf_notify] map[Kind:function Name:addrconf_permanent_addr] map[Kind:function Name:addrconf_prefix_rcv] map[Kind:function Name:addrconf_prefix_rcv_add_addr] map[Kind:function Name:addrconf_prefix_rcv_add_addr] map[Kind:function Name:addrconf_prefix_route] map[Kind:function Name:addrconf_rs_timer] map[Kind:function Name:addrconf_rs_timer] map[Kind:function Name:addrconf_set_dstaddr] map[Kind:function Name:addrconf_set_nopolicy] map[Kind:function Name:addrconf_set_sit_dstaddr] map[Kind:function Name:addrconf_sit_config] map[Kind:function Name:addrconf_sysctl_addr_gen_mode] map[Kind:function Name:addrconf_sysctl_disable] map[Kind:function Name:addrconf_sysctl_disable_policy] map[Kind:function Name:addrconf_sysctl_force_forwarding] map[Kind:function Name:addrconf_sysctl_forward] map[Kind:function Name:addrconf_sysctl_ignore_routes_with_linkdown] map[Kind:function Name:addrconf_sysctl_mtu] map[Kind:function Name:addrconf_sysctl_proxy_ndp] map[Kind:function Name:addrconf_sysctl_register] map[Kind:function Name:addrconf_sysctl_register] map[Kind:function Name:addrconf_sysctl_stable_secret] map[Kind:function Name:addrconf_sysctl_unregister] map[Kind:function Name:addrconf_sysctl_unregister] map[Kind:function Name:addrconf_type_change] map[Kind:function Name:addrconf_type_change] map[Kind:function Name:addrconf_verify] map[Kind:function Name:addrconf_verify] map[Kind:function Name:addrconf_verify_rtnl] map[Kind:function Name:addrconf_verify_rtnl] map[Kind:function Name:addrconf_verify_work] map[Kind:function Name:check_addr_gen_mode] map[Kind:function Name:check_cleanup_prefix_route] map[Kind:function Name:check_stable_privacy] map[Kind:function Name:cleanup_prefix_route] map[Kind:function Name:cstamp_delta] map[Kind:function Name:delete_tempaddrs] map[Kind:function Name:dev_disable_change] map[Kind:function Name:dev_forward_change] map[Kind:function Name:extract_addr] map[Kind:function Name:fixup_permanent_addr] map[Kind:function Name:if6_get_first] map[Kind:function Name:if6_get_next] map[Kind:function Name:if6_proc_exit] map[Kind:function Name:if6_proc_init] map[Kind:function Name:if6_proc_net_exit] map[Kind:function Name:if6_proc_net_init] map[Kind:function Name:if6_seq_next] map[Kind:function Name:if6_seq_show] map[Kind:function Name:if6_seq_start] map[Kind:function Name:if6_seq_stop] map[Kind:function Name:in6_dump_addrs] map[Kind:function Name:inet6_addr_add] map[Kind:function Name:inet6_addr_del] map[Kind:function Name:inet6_addr_hash] map[Kind:function Name:inet6_addr_modify] map[Kind:function Name:inet6_base_seq] map[Kind:function Name:inet6_dump_addr] map[Kind:function Name:inet6_dump_ifacaddr] map[Kind:function Name:inet6_dump_ifaddr] map[Kind:function Name:inet6_dump_ifinfo] map[Kind:function Name:inet6_dump_ifmcaddr] map[Kind:function Name:inet6_fill_ifacaddr] map[Kind:function Name:inet6_fill_ifaddr] map[Kind:function Name:inet6_fill_ifinfo] map[Kind:function Name:inet6_fill_ifla6_attrs] map[Kind:function Name:inet6_fill_ifla6_stats_attrs] map[Kind:function Name:inet6_fill_ifmcaddr] map[Kind:function Name:inet6_fill_link_af] map[Kind:function Name:inet6_fill_prefix] map[Kind:function Name:inet6_get_link_af_size] map[Kind:function Name:inet6_if_nlmsg_size] map[Kind:function Name:inet6_ifa_finish_destroy] map[Kind:function Name:inet6_ifa_notify] map[Kind:function Name:inet6_ifaddr_msgsize] map[Kind:function Name:inet6_ifinfo_notify] map[Kind:function Name:inet6_ifla6_size] map[Kind:function Name:inet6_netconf_dump_devconf] map[Kind:function Name:inet6_netconf_fill_devconf] map[Kind:function Name:inet6_netconf_get_devconf] map[Kind:function Name:inet6_netconf_msgsize_devconf] map[Kind:function Name:inet6_netconf_notify_devconf] map[Kind:function Name:inet6_netconf_valid_get_req] map[Kind:function Name:inet6_prefix_nlmsg_size] map[Kind:function Name:inet6_prefix_notify] map[Kind:function Name:inet6_prefix_notify] map[Kind:function Name:inet6_rtm_deladdr] map[Kind:function Name:inet6_rtm_getaddr] map[Kind:function Name:inet6_rtm_newaddr] map[Kind:function Name:inet6_rtm_valid_getaddr_req] map[Kind:function Name:inet6_set_iftoken] map[Kind:function Name:inet6_set_link_af] map[Kind:function Name:inet6_valid_dump_ifaddr_req] map[Kind:function Name:inet6_valid_dump_ifinfo] map[Kind:function Name:inet6_validate_link_af] map[Kind:function Name:init_loopback] map[Kind:function Name:ipv6_add_addr] map[Kind:function Name:ipv6_add_addr_hash] map[Kind:function Name:ipv6_add_dev] map[Kind:function Name:ipv6_allow_optimistic_dad] map[Kind:function Name:ipv6_chk_addr] map[Kind:function Name:ipv6_chk_addr] map[Kind:function Name:ipv6_chk_addr_and_flags] map[Kind:function Name:ipv6_chk_addr_and_flags] map[Kind:function Name:ipv6_chk_custom_prefix] map[Kind:function Name:ipv6_chk_custom_prefix] map[Kind:function Name:ipv6_chk_home_addr] map[Kind:function Name:ipv6_chk_prefix] map[Kind:function Name:ipv6_chk_prefix] map[Kind:function Name:ipv6_chk_rpl_srh_loop] map[Kind:function Name:ipv6_chk_same_addr] map[Kind:function Name:ipv6_count_addresses] map[Kind:function Name:ipv6_count_addresses] map[Kind:function Name:ipv6_create_tempaddr] map[Kind:function Name:ipv6_del_addr] map[Kind:function Name:ipv6_dev_find] map[Kind:function Name:ipv6_dev_find] map[Kind:function Name:ipv6_dev_get_saddr] map[Kind:function Name:ipv6_dev_get_saddr] map[Kind:function Name:ipv6_find_idev] map[Kind:function Name:ipv6_gen_mode_random_init] map[Kind:function Name:ipv6_gen_rnd_iid] map[Kind:function Name:ipv6_gen_rnd_iid] map[Kind:function Name:ipv6_generate_eui64] map[Kind:function Name:ipv6_generate_eui64] map[Kind:function Name:ipv6_generate_stable_address] map[Kind:function Name:ipv6_generate_stable_address] map[Kind:function Name:ipv6_get_ifaddr] map[Kind:function Name:ipv6_get_lladdr] map[Kind:function Name:ipv6_get_regen_advance] map[Kind:function Name:ipv6_get_saddr_eval] map[Kind:function Name:ipv6_get_saddr_master] map[Kind:function Name:ipv6_ifa_notify] map[Kind:function Name:ipv6_ifa_notify] map[Kind:function Name:ipv6_inherit_eui64] map[Kind:function Name:ipv6_link_dev_addr] map[Kind:function Name:ipv6_lonely_lladdr] map[Kind:function Name:ipv6_mc_config] map[Kind:function Name:ipv6_reserved_interfaceid] map[Kind:function Name:ipv6_saddr_preferred] map[Kind:function Name:ipv6_store_devconf] map[Kind:function Name:ipv6_use_optimistic_addr] map[Kind:function Name:is_addr_mode_generate_stable] map[Kind:function Name:manage_tempaddrs] map[Kind:function Name:modify_prefix_route] map[Kind:function Name:put_cacheinfo] map[Kind:function Name:put_ifaddrmsg] map[Kind:function Name:rfc3315_s14_backoff_init] map[Kind:function Name:rfc3315_s14_backoff_update] map[Kind:function Name:rt_scope] map[Kind:function Name:snmp6_alloc_dev] map[Kind:function Name:snmp6_fill_stats]] Missing:false]

15/2 2026/01/09 19:15 llm expert
0m Model:
unknown

Thoughts:
Okay, here's my thought process as I delve into this:

**Investigating `inet6_fill_ifinfo` and `ra_mtu` in IPv6 Address Configuration**

Alright, let's get down to brass tacks. I need to understand how the system populates interface information, specifically in the IPv6 context. The question is whether the `ra_mtu` (Router Advertisement MTU) value is being correctly integrated during address configuration. So, my initial approach is to go straight to the source. I'll zero in on `inet6_fill_ifinfo` within `net/ipv6/addrconf.c`. This is the core function likely responsible for assembling the interface details, and therefore, the prime suspect for handling `ra_mtu`. I need to confirm whether `ra_mtu` is directly consumed or if there's an indirect derivation process. The devil's always in the details, so I need to carefully scrutinize the code path that executes during address configuration events. I'm looking for the moment when this value from the RA is effectively used and if any assumptions are being made during processing. This should give me a solid answer.



16/2 2026/01/09 19:15 tool codesearch-definition-source
0m Model:
unknown

Args:
map[IncludeLines:true Name:inet6_fill_ifinfo SourceFile:net/ipv6/addrconf.c]

Results:
map[Missing:false SourceCode:6061:	static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
6062:				     u32 portid, u32 seq, int event, unsigned int flags)
6063:	{
6064:		struct net_device *dev = idev->dev;
6065:		struct ifinfomsg *hdr;
6066:		struct nlmsghdr *nlh;
6067:		int ifindex, iflink;
6068:		void *protoinfo;
6069:	
6070:		nlh = nlmsg_put(skb, portid, seq, event, sizeof(*hdr), flags);
6071:		if (!nlh)
6072:			return -EMSGSIZE;
6073:	
6074:		hdr = nlmsg_data(nlh);
6075:		hdr->ifi_family = AF_INET6;
6076:		hdr->__ifi_pad = 0;
6077:		hdr->ifi_type = dev->type;
6078:		ifindex = READ_ONCE(dev->ifindex);
6079:		hdr->ifi_index = ifindex;
6080:		hdr->ifi_flags = netif_get_flags(dev);
6081:		hdr->ifi_change = 0;
6082:	
6083:		iflink = dev_get_iflink(dev);
6084:		if (nla_put_string(skb, IFLA_IFNAME, dev->name) ||
6085:		    (dev->addr_len &&
6086:		     nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) ||
6087:		    nla_put_u32(skb, IFLA_MTU, READ_ONCE(dev->mtu)) ||
6088:		    (ifindex != iflink &&
6089:		     nla_put_u32(skb, IFLA_LINK, iflink)) ||
6090:		    nla_put_u8(skb, IFLA_OPERSTATE,
6091:			       netif_running(dev) ? READ_ONCE(dev->operstate) : IF_OPER_DOWN))
6092:			goto nla_put_failure;
6093:		protoinfo = nla_nest_start_noflag(skb, IFLA_PROTINFO);
6094:		if (!protoinfo)
6095:			goto nla_put_failure;
6096:	
6097:		if (inet6_fill_ifla6_attrs(skb, idev, 0) < 0)
6098:			goto nla_put_failure;
6099:	
6100:		nla_nest_end(skb, protoinfo);
6101:		nlmsg_end(skb, nlh);
6102:		return 0;
6103:	
6104:	nla_put_failure:
6105:		nlmsg_cancel(skb, nlh);
6106:		return -EMSGSIZE;
6107:	}
 SourceFile:net/ipv6/addrconf.c]

17/2 2026/01/09 19:15 llm expert
0m Model:
unknown

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience, and presented as if it were my own internal monologue:

**Navigating the IPv6 Attribute Filling**

Right, so I've been tracing the execution flow and I've just hit `inet6_fill_ifla6_attrs` at line 6097. That's a critical point. I know this function is responsible for populating the IPv6-specific attributes within the ifla6 structure, which is then used in the Netlink messages for interface configuration.

Let me quickly recap what's happening at this point: We're likely in the midst of either an `RTNL_GETLINK`, `RTNL_NEWLINK`, or possibly even a route operation affecting an IPv6 interface. My immediate concern is what kind of `struct nlmsghdr` this is associated with.

I should verify which attributes we are setting. I am keen to understand what the key fields being populated are:
*   **Address:** IP Address, of course.
*   **Prefix:** Prefix length, a crucial one!
*   **Scope:** Is it link-local, global, or something else?
*   **Flags:** This has to be checked, what flags are set by this function?

A quick glance at the implementation of this function will quickly reveal if there are any subtle bugs or non-obvious default behavior. I need to ensure it correctly handles things like duplicate address detection, router advertisements, and any configured IPv6 address policies. It also needs to be thread safe.

Essentially, I need to make sure this function is producing the right data in the right format for the kernel's IPv6 networking stack, and for any user space tools that are going to read that configuration. Any mistake here, and we're looking at broken IPv6 connectivity. Let's see how well it handles errors and potential race conditions.



18/2 2026/01/09 19:15 tool codesearch-definition-source
0m Model:
unknown

Args:
map[IncludeLines:true Name:inet6_fill_ifla6_attrs SourceFile:net/ipv6/addrconf.c]

Results:
map[Missing:false SourceCode:5815:	static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev,
5816:					  u32 ext_filter_mask)
5817:	{
5818:		struct ifla_cacheinfo ci;
5819:		struct nlattr *nla;
5820:		u32 ra_mtu;
5821:	
5822:		if (nla_put_u32(skb, IFLA_INET6_FLAGS, READ_ONCE(idev->if_flags)))
5823:			goto nla_put_failure;
5824:		ci.max_reasm_len = IPV6_MAXPLEN;
5825:		ci.tstamp = cstamp_delta(READ_ONCE(idev->tstamp));
5826:		ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time);
5827:		ci.retrans_time = jiffies_to_msecs(NEIGH_VAR(idev->nd_parms, RETRANS_TIME));
5828:		if (nla_put(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci))
5829:			goto nla_put_failure;
5830:		nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
5831:		if (!nla)
5832:			goto nla_put_failure;
5833:		ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla));
5834:	
5835:		/* XXX - MC not implemented */
5836:	
5837:		if (!(ext_filter_mask & RTEXT_FILTER_SKIP_STATS)) {
5838:			if (inet6_fill_ifla6_stats_attrs(skb, idev) < 0)
5839:				goto nla_put_failure;
5840:		}
5841:	
5842:		nla = nla_reserve(skb, IFLA_INET6_TOKEN, sizeof(struct in6_addr));
5843:		if (!nla)
5844:			goto nla_put_failure;
5845:		read_lock_bh(&idev->lock);
5846:		memcpy(nla_data(nla), idev->token.s6_addr, nla_len(nla));
5847:		read_unlock_bh(&idev->lock);
5848:	
5849:		if (nla_put_u8(skb, IFLA_INET6_ADDR_GEN_MODE,
5850:			       READ_ONCE(idev->cnf.addr_gen_mode)))
5851:			goto nla_put_failure;
5852:	
5853:		ra_mtu = READ_ONCE(idev->ra_mtu);
5854:		if (ra_mtu && nla_put_u32(skb, IFLA_INET6_RA_MTU, ra_mtu))
5855:			goto nla_put_failure;
5856:	
5857:		return 0;
5858:	
5859:	nla_put_failure:
5860:		return -EMSGSIZE;
5861:	}
 SourceFile:net/ipv6/addrconf.c]

19/2 2026/01/09 19:15 llm expert
0m Model:
unknown

Thoughts:
**Investigating a Potential Data Race in IPv6 Router Advertisement (RA) MTU Handling**

Okay, so I'm looking at this IPv6 code, specifically around how the Router Advertisement MTU (`ra_mtu`) is handled. It seems like at line 5853, I see `ra_mtu` being read with `READ_ONCE`, which is good practice for concurrency. This read happens within `inet6_fill_ifla6_attrs`, which is ultimately called when `RTM_NEWLINK` messages are generated. That makes sense; it's retrieving the current state.

However, things get interesting in `ndisc_router_discovery`. I see `ra_mtu` being *updated* with a plain assignment, like `in6_dev->ra_mtu = mtu;` and also read plainly (`if (in6_dev->ra_mtu != mtu)`). This smells like a data race if two concurrent Router Advertisements come in, which seems plausible. I'm assuming the RAs are coming in from different routers, maybe?

So, is it *actually* harmful? Let's break it down:

First, **Read Tearing:** Given that `ra_mtu` is a `u32`, which is likely an atomic size on most modern architectures, it's *unlikely* we'll see a torn value. But, technically, it's possible.

Second, **Logic Error:** The more concerning issue is a logic error. Suppose two threads (T1 and T2) are updating `ra_mtu` with different values. Here's how it could play out:

*   T1 reads `ra_mtu` (old value), sees a difference with its update value.
*   T2 reads `ra_mtu` (old value), sees a difference with its update value.
*   T1 writes its value (val1) to `ra_mtu`.
*   T2 writes its value (val2) to `ra_mtu`.

The end result? `ra_mtu` is `val2`. The key thing is that the `send_ifinfo_notify` condition, based on the *old* value, would have been true for both T1 and T2.

Now, those notifications! Both T1 and T2 will later call `inet6_ifinfo_notify`. What does that do? I need to check. It looks like `inet6_ifinfo_notify` is going to queue a Netlink message, but I need to understand *when* the message is actually generated. Aha, it's in `rtnl_notify` -> `rtnl_fill_ifinfo`. Wait, `inet6_ifinfo_notify` calls `rtmsg_ifinfo`. Ok, so I'll go check `inet6_ifinfo_notify` itself to understand the path for those queued messages.



20/2 2026/01/09 19:15 tool codesearch-definition-source
0m Model:
unknown

Args:
map[IncludeLines:true Name:inet6_ifinfo_notify SourceFile:net/ipv6/addrconf.c]

Results:
map[Missing:false SourceCode:6172:	void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
6173:	{
6174:		struct sk_buff *skb;
6175:		struct net *net = dev_net(idev->dev);
6176:		int err = -ENOBUFS;
6177:	
6178:		skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC);
6179:		if (!skb)
6180:			goto errout;
6181:	
6182:		err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0);
6183:		if (err < 0) {
6184:			/* -EMSGSIZE implies BUG in inet6_if_nlmsg_size() */
6185:			WARN_ON(err == -EMSGSIZE);
6186:			kfree_skb(skb);
6187:			goto errout;
6188:		}
6189:		rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFINFO, NULL, GFP_ATOMIC);
6190:		return;
6191:	errout:
6192:		rtnl_set_sk_err(net, RTNLGRP_IPV6_IFINFO, err);
6193:	}
 SourceFile:net/ipv6/addrconf.c]

21/2 2026/01/09 19:15 llm expert
0m Model:
unknown

Thoughts:
**Race Condition Analysis: IPv6 Router Advertisement MTU Field**

Okay, so KCSAN flagged a race condition in the IPv6 `ndisc_router_discovery` code, specifically concerning the `ra_mtu` field within the `inet6_dev` structure. Let's break this down. Basically, this function reads the MTU from an incoming Router Advertisement (RA) and updates the `ra_mtu` field, and then sends a notification to userspace. The potential problem is that two threads (T1 and T2) could try to update this `ra_mtu` concurrently.

The core of the issue is around lines 1557-1560 of `ndisc.c`. Both threads read the current `ra_mtu` and then, if it's different from the MTU in the RA they're processing, they update it. The KCSAN report suggests that this constitutes a "data race" because both threads can read and write to the same memory location without any explicit locking.

Now, I've got to look closely at what this `ra_mtu` field *actually* does. It appears to be primarily an informational field, reporting the MTU value from the last received RA to userspace. Critically, it *doesn't* directly control the interface MTU itself, which is set in a subsequent `else if` block using `cnf.mtu6` along with `READ_ONCE` and `WRITE_ONCE`. This is important, the actual MTU setting uses proper atomics and impacts kernel behavior.

So, if there's a race, the worst that's likely to happen is that userspace might receive inconsistent notifications about the MTU. In the event of a lost update, one thread overwrites another and some notifications are missed. It's also possible that userspace receives a stale value. So, if T1 writes V1 and then T2 writes V2, then two notifications are sent, and the final state is V2, this is consistent with the reality: two RAs, the system converged on one value. This isn't great, but it's not a crash or kernel corruption. The read/write happens on a `u32` which should be atomic, and `struct inet6_dev` is aligned, so store tearing is very unlikely. The more likely scenario is that a missed notification and a possible temporary inconsistency, which in the grand scheme is not an existential issue.

The thing that KCSAN points out is that the code doesn't use `READ_ONCE` or `WRITE_ONCE`. While this race is unlikely to corrupt the actual values, KCSAN expects these to be used on *every* shared variable, which is good programming practice. Developers used `READ_ONCE`/`WRITE_ONCE` for `cnf.mtu6`. So, the failure to use this for `ra_mtu` is an oversight, but not necessarily a critical bug. This lack of atomics also points out that the field is technically racy, as the compiler could reorder the reads/writes, but on x86, it won't.

I checked and `ra_mtu` *only* appears to be used for this RA-reported MTU. It does *not* seem to affect the actual interface MTU or any other critical kernel state.

The key is that the code *does* validate the MTU value *after* it updates `ra_mtu`. So, even if the RA announces a wildly incorrect MTU, the kernel won't actually apply that value to the interface. The code also ratelimits debug messages about it being invalid, so the kernel is well aware of it.

Wait, what if the value is garbage? As the report shows, the value is `0xe5400659` which is 3.8 billion, which doesn't make any sense. But looking at the code shows that the value is `memcpy`-ed from the packet from the device, and then assigned *before* any validation. So, the invalid value would be stored, *but* the check after prevents the invalid MTU from taking effect, so we get the "invalid mtu" warning.

This looks like a benign data race. The race is on a value that doesn't enforce any kernel invariant, but simply reflects the last received valid RA parameter to userspace. In short, the kernel reports that userspace received "bad data", and that's technically fine!

The fact that the stack trace includes `tun_get_user` confirms that the packet originates from a userspace TUN interface, which explains the garbage value. The race, then, is likely triggered by a fuzzer or malformed packets from userspace. It's not a race on a complex container;


22/2 2026/01/09 19:16 tool set-results
0m Model:
unknown

Args:
map[Benign:true]

Results:
map[Benign:true]

23/2 2026/01/09 19:16 llm expert
0m Model:
unknown

Thoughts:
**Benign Race Condition in IPv6 RA MTU Handling**

Okay, so I've marked this as Benign. Time to articulate exactly why. My analysis boils down to this: we've got a race condition involving `in6_dev->ra_mtu`, a `u32` field within the `inet6_dev` structure. This field essentially keeps track of the MTU value received in the *last* IPv6 Router Advertisement (RA) we processed.

The key is how this field is updated. The update itself happens within `ndisc_router_discovery`, the receiving path for RAs. The system stores the MTU value *immediately* upon receiving it (if an MTU option is present in the RA). However, the *effective* MTU that the interface actually uses (via `cnf.mtu6` and the underlying device MTU) is updated *later*, only after proper validation and checks. This is the crucial distinction.

Now, this `in6_dev->ra_mtu` field has one, and only one, primary purpose: to report the MTU from the last received RA to userspace. We expose this value via netlink notifications, specifically `RTM_NEWLINK` messages and `inet6_fill_ifinfo`.

The race itself arises because multiple RAs can arrive concurrently. This means `in6_dev->ra_mtu` could be updated by one RA while another is also trying to write to it. The "last received" value becomes non-deterministic between the competing updates, which is entirely expected in concurrent packet handling. But this is where it gets interesting: the read side, within `inet6_fill_ifla6_attrs`, uses `READ_ONCE` to safely handle the concurrency. It correctly reads what's there at that instant.

The write side, within `ndisc_router_discovery`, uses a plain assignment. While using `WRITE_ONCE` would be ideal for enhanced code correctness and documentation, on the architecture we're dealing with (and the vast majority of others), aligned 32-bit writes are atomic. So, no tearing can occur. The worst-case scenario is that we might report an outdated value if there is a flood of RAs, which is expected.

Crucially, this race does *not* lead to any memory corruption, list corruption, or inconsistency in the kernel's internal state. The actual MTU used by the device is determined separately, and that's the important part. The `in6_dev->ra_mtu` is just an informational field.

Finally, the invalid value we're seeing, `0xe5400659`, is almost certainly a product of the fuzzer. This value is, of course, invalid as an MTU. But the system is designed to treat `in6_dev->ra_mtu` as merely informational. That invalid value will not be used in device configuration. It's safe to store it, because it is *not* used in the control path.

So, in summary, we've got a harmless, informational race condition. It's a race, but it's benign. Time to write up the details.



LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)