use serde::Deserialize;
use serde::Serialize;
use crate::fd::OpenFileId;
use crate::pid::DetTid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct MmId {
creator: DetTid,
generation: u64,
}
impl MmId {
pub const fn initial(creator: DetTid) -> Self {
Self {
creator,
generation: 0,
}
}
pub const fn for_clone(parent: Self, child: DetTid, shares_vm: bool) -> Self {
if shares_vm {
parent
} else {
Self::initial(child)
}
}
pub fn for_exec(self, creator: DetTid) -> Self {
Self {
creator,
generation: self.generation + 1,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum SharedMemoryObjectId {
Anonymous {
origin: MmId,
sequence: u64,
},
File {
device: u64,
inode: u64,
},
OpenFile { id: OpenFileId },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum FutexID {
Private { mm: MmId, address: usize },
Shared {
object: SharedMemoryObjectId,
offset: u64,
},
}
impl FutexID {
pub const fn private(mm: MmId, address: usize) -> Self {
Self::Private { mm, address }
}
pub const fn shared(object: SharedMemoryObjectId, offset: u64) -> Self {
Self::Shared { object, offset }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn clone_vm_controls_private_futex_aliasing() {
let parent = MmId::initial(DetTid::from_raw(10));
let child = DetTid::from_raw(11);
assert_eq!(
FutexID::private(parent, 0x1000),
FutexID::private(MmId::for_clone(parent, child, true), 0x1000),
"CLONE_VM tasks should use the same private futex key"
);
assert_ne!(
FutexID::private(parent, 0x1000),
FutexID::private(MmId::for_clone(parent, child, false), 0x1000),
"a copied address space should not alias the parent's private futex"
);
assert_ne!(
FutexID::private(parent, 0x1000),
FutexID::private(parent.for_exec(DetTid::from_raw(10)), 0x1000),
"exec should replace the private futex namespace"
);
}
#[test]
fn exec_generation_never_repeats_when_caller_identity_changes() {
let leader = DetTid::from_raw(10);
let worker = DetTid::from_raw(11);
let initial = MmId::initial(leader);
let worker_exec = initial.for_exec(worker);
let leader_exec = worker_exec.for_exec(leader);
assert_ne!(worker_exec, initial);
assert_ne!(leader_exec, initial);
assert_ne!(leader_exec, worker_exec);
}
#[test]
fn shared_futexes_alias_by_object_and_offset() {
let object = SharedMemoryObjectId::File {
device: 10,
inode: 20,
};
assert_eq!(
FutexID::shared(object, 64),
FutexID::shared(object, 64),
"virtual-address aliases of one backing offset must share a key"
);
assert_ne!(
FutexID::shared(object, 64),
FutexID::shared(object, 68),
"different words in one backing object need distinct keys"
);
assert_ne!(
FutexID::shared(object, 64),
FutexID::private(MmId::initial(DetTid::from_raw(10)), 64),
"private and shared namespaces must remain distinct"
);
}
}