Skip to content

bug: get_specific_virtual_fd read/write TOCTOU #1370

Description

@Shounak-Ghosh

Component: src/fdtables (dashmaparrayglobal.rs:197, dashmapvecglobal.rs:199)
Severity: Correctness (a race between concurrent dup2() calls)
Found by: CONC-003 (#1304), fdtables::tests::conc_003_dup2_overwrite_refcount_conservation

Symptom

Two dup2()s racing onto the same target fd (or a dup2() racing a close() /
allocation that lands on the same slot) can both observe the same "old" entry and
both decrement it, which double-releases a single host fd. Alternatively, one call's
write can overwrite a concurrent get_unused_virtual_fd()'s insert, losing an entry
entirely.

Root cause

// src/fdtables/src/dashmaparrayglobal.rs (in get_specific_virtual_fd)
let myoptionentry = FDTABLE.get(&cageid).unwrap()[requested_virtualfd as usize];
// ... guard released here ...
FDTABLE.get_mut(&cageid).unwrap()[requested_virtualfd as usize] = Some(myentry);

The old value is read under one guard and the new value written under a second,
separately acquired one.

Proposed fix

Single .replace() under one guard, dropped before the close handler runs (a handler
may re-enter this module):

-    let myoptionentry = FDTABLE.get(&cageid).unwrap()[requested_virtualfd as usize];
-    // always add the new entry.  I'm doing this first, before I close
-    // the old one because I need to ensure I've cleaned up state correctly
-    // before calling the close handlers...
-    FDTABLE.get_mut(&cageid).unwrap()[requested_virtualfd as usize] = Some(myentry);
+    let myoptionentry = {
+        let mut row = FDTABLE.get_mut(&cageid).unwrap();
+        row[requested_virtualfd as usize].replace(myentry)
+    };

vanillaglobal.rs and muthashmaxglobal.rs use HashMap::insert, which already
returns the old value atomically, and need no change.

Un-skip on merge

In src/fdtables/src/lib.rs, remove the #[ignore] from
conc_003_dup2_overwrite_refcount_conservation.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions