1use serde::Deserialize;
10use serde::Serialize;
11
12use crate::fd::OpenFileId;
13use crate::pid::DetTid;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
17pub struct MmId {
18 creator: DetTid,
19 generation: u64,
20}
21
22impl MmId {
23 pub const fn initial(creator: DetTid) -> Self {
25 Self {
26 creator,
27 generation: 0,
28 }
29 }
30
31 pub const fn for_clone(parent: Self, child: DetTid, shares_vm: bool) -> Self {
33 if shares_vm {
34 parent
35 } else {
36 Self::initial(child)
37 }
38 }
39
40 pub fn for_exec(self, creator: DetTid) -> Self {
42 Self {
43 creator,
44 generation: self.generation + 1,
47 }
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
53pub enum SharedMemoryObjectId {
54 Anonymous {
56 origin: MmId,
58 sequence: u64,
60 },
61 File {
63 device: u64,
65 inode: u64,
67 },
68 OpenFile { id: OpenFileId },
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
74pub enum FutexID {
75 Private { mm: MmId, address: usize },
77 Shared {
79 object: SharedMemoryObjectId,
80 offset: u64,
81 },
82}
83
84impl FutexID {
85 pub const fn private(mm: MmId, address: usize) -> Self {
87 Self::Private { mm, address }
88 }
89
90 pub const fn shared(object: SharedMemoryObjectId, offset: u64) -> Self {
92 Self::Shared { object, offset }
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn clone_vm_controls_private_futex_aliasing() {
102 let parent = MmId::initial(DetTid::from_raw(10));
103 let child = DetTid::from_raw(11);
104
105 assert_eq!(
106 FutexID::private(parent, 0x1000),
107 FutexID::private(MmId::for_clone(parent, child, true), 0x1000),
108 "CLONE_VM tasks should use the same private futex key"
109 );
110 assert_ne!(
111 FutexID::private(parent, 0x1000),
112 FutexID::private(MmId::for_clone(parent, child, false), 0x1000),
113 "a copied address space should not alias the parent's private futex"
114 );
115 assert_ne!(
116 FutexID::private(parent, 0x1000),
117 FutexID::private(parent.for_exec(DetTid::from_raw(10)), 0x1000),
118 "exec should replace the private futex namespace"
119 );
120 }
121
122 #[test]
123 fn exec_generation_never_repeats_when_caller_identity_changes() {
124 let leader = DetTid::from_raw(10);
125 let worker = DetTid::from_raw(11);
126 let initial = MmId::initial(leader);
127 let worker_exec = initial.for_exec(worker);
128 let leader_exec = worker_exec.for_exec(leader);
129
130 assert_ne!(worker_exec, initial);
131 assert_ne!(leader_exec, initial);
132 assert_ne!(leader_exec, worker_exec);
133 }
134
135 #[test]
136 fn shared_futexes_alias_by_object_and_offset() {
137 let object = SharedMemoryObjectId::File {
138 device: 10,
139 inode: 20,
140 };
141 assert_eq!(
142 FutexID::shared(object, 64),
143 FutexID::shared(object, 64),
144 "virtual-address aliases of one backing offset must share a key"
145 );
146 assert_ne!(
147 FutexID::shared(object, 64),
148 FutexID::shared(object, 68),
149 "different words in one backing object need distinct keys"
150 );
151 assert_ne!(
152 FutexID::shared(object, 64),
153 FutexID::private(MmId::initial(DetTid::from_raw(10)), 64),
154 "private and shared namespaces must remain distinct"
155 );
156 }
157}