Skip to main content

sandlock_core/netlink/
state.rs

1use std::collections::HashSet;
2use std::sync::Mutex;
3
4/// Per-sandbox registry of virtualized netlink cookie fds.
5///
6/// Keyed by `(pid, fd)` — the exact fd number allocated in the child
7/// when our `socket(AF_NETLINK, ..., NETLINK_ROUTE)` handler returned
8/// `InjectFdSendTracked`.  Using the fd number directly (instead of
9/// comparing `/proc/<pid>/fd/<fd>` inodes against a set of injected
10/// inodes) avoids TOCTOU: once we record `(pid, fd)`, no other thread
11/// can redirect that fd slot without our `close` handler observing it
12/// and removing the entry first.
13#[derive(Default)]
14pub struct NetlinkState {
15    cookies: Mutex<HashSet<(i32, i32)>>,
16}
17
18impl NetlinkState {
19    pub fn new() -> Self {
20        Self { cookies: Mutex::new(HashSet::new()) }
21    }
22
23    /// Register a new cookie fd injected into the child.
24    pub fn register(&self, pid: i32, fd: i32) {
25        self.cookies.lock().unwrap().insert((pid, fd));
26    }
27
28    /// Remove a cookie entry.  Called from the close handler when the
29    /// child closes a tracked fd.
30    pub fn unregister(&self, pid: i32, fd: i32) {
31        self.cookies.lock().unwrap().remove(&(pid, fd));
32    }
33
34    /// Is this (pid, fd) one of our injected netlink cookies?
35    pub fn is_cookie(&self, pid: i32, fd: i32) -> bool {
36        self.cookies.lock().unwrap().contains(&(pid, fd))
37    }
38}