-
- Downloads
Prevent lost updates in IfaceNameForIndexAndMAC (#716)
* fix(ifaces): avoid potential lost update in IfaceNameForIndexAndMAC IfaceNameForIndexAndMAC reads the interface cache under RLock, and if no match is found, performs a syscall fallback (net.InterfaceByIndex) followed by an unconditional write under Lock. This creates a potential lost update scenario under contention: 1. Goroutine A reads r.ifaces[idx][mac], sees missing 2. Goroutine B does the same 3. Both perform fallback syscall 4. A acquires Lock and inserts result 5. B acquires Lock and overwrites A’s entry This change avoids that risk by applying double-checked locking: the map is re-checked under Lock before any write occurs. No test has been added. The code is already synchronised and correct at the memory level; the issue is about preserving consistency in concurrent insertions, and reproducing it reliably would require coordinated thread interleaving. Signed-off-by:Andrew McDermott <amcdermo@redhat.com> * Add failing test-race * fix(ifaces): eliminate race condition in IfaceNameForIndexAndMAC Eliminate a critical read-after-unlock race condition where the function releases the RLock but continues accessing macsMap without protection, while other goroutines could concurrently modify the same map. This creates a classic data race between: - Reader threads accessing macsMap (len, iteration, lookup) - Writer threads modifying the map via Subscribe() or fallback updates Hold the RLock throughout the entire cache access phase, only releasing it before each return or before the syscall fallback. Signed-off-by:
Andrew McDermott <amcdermo@redhat.com> * Add test for race condition * Extract cache lookup function * fix(ifaces): eliminate race condition in IfaceNameForIndexAndMAC Fix a critical read-after-unlock race condition where the function released the RLock but continued accessing macsMap without protection, while other goroutines could concurrently modify the same map. The race occurred between: - Reader threads accessing macsMap (len, iteration, lookup) - Writer threads modifying the map via Subscribe() or fallback updates Hold the RLock throughout the entire cache access phase, releasing it only before each return or before the syscall fallback. Use individual unlock calls rather than defer to prevent deadlock, since RWMutex does not support lock upgrades from read to write. Add comment documenting this design choice to prevent future "optimisations" that would introduce deadlock. Signed-off-by:
Andrew McDermott <amcdermo@redhat.com> * fix leaking fd in test --------- Signed-off-by:
Andrew McDermott <amcdermo@redhat.com> Co-authored-by:
Joel Takvorian <jtakvori@redhat.com>
Please register or sign in to comment