1#![allow(non_upper_case_globals)]
7
8use crate::mm::memory::MemoryObject;
9use crate::security;
10use crate::task::{CurrentTask, Kernel, register_delayed_release};
11use ebpf::MapSchema;
12use ebpf_api::{Map, MapError, PinnedMap};
13use starnix_lifecycle::{ObjectReleaser, ReleaserAction};
14use starnix_sync::{EbpfMapStateLevel, LockDepGuard, LockDepMutex};
15use starnix_types::ownership::{Releasable, ReleaseGuard};
16use starnix_uapi::auth::{CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON, CAP_SYS_ADMIN};
17use starnix_uapi::errors::Errno;
18use starnix_uapi::{
19 bpf_map_type_BPF_MAP_TYPE_ARRAY_OF_MAPS, bpf_map_type_BPF_MAP_TYPE_BLOOM_FILTER,
20 bpf_map_type_BPF_MAP_TYPE_CGROUP_STORAGE, bpf_map_type_BPF_MAP_TYPE_CGRP_STORAGE,
21 bpf_map_type_BPF_MAP_TYPE_CPUMAP, bpf_map_type_BPF_MAP_TYPE_DEVMAP,
22 bpf_map_type_BPF_MAP_TYPE_DEVMAP_HASH, bpf_map_type_BPF_MAP_TYPE_HASH_OF_MAPS,
23 bpf_map_type_BPF_MAP_TYPE_INODE_STORAGE, bpf_map_type_BPF_MAP_TYPE_LPM_TRIE,
24 bpf_map_type_BPF_MAP_TYPE_LRU_HASH, bpf_map_type_BPF_MAP_TYPE_LRU_PERCPU_HASH,
25 bpf_map_type_BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, bpf_map_type_BPF_MAP_TYPE_QUEUE,
26 bpf_map_type_BPF_MAP_TYPE_SK_STORAGE, bpf_map_type_BPF_MAP_TYPE_SOCKHASH,
27 bpf_map_type_BPF_MAP_TYPE_SOCKMAP, bpf_map_type_BPF_MAP_TYPE_STACK,
28 bpf_map_type_BPF_MAP_TYPE_STACK_TRACE, bpf_map_type_BPF_MAP_TYPE_STRUCT_OPS,
29 bpf_map_type_BPF_MAP_TYPE_TASK_STORAGE, bpf_map_type_BPF_MAP_TYPE_XSKMAP, errno, error,
30};
31use std::ops::Deref;
32use std::sync::atomic::{AtomicU32, Ordering};
33use std::sync::{Arc, Weak};
34
35pub type BpfMapId = u32;
36
37static MAP_IDS: AtomicU32 = AtomicU32::new(1);
39fn new_map_id() -> BpfMapId {
40 MAP_IDS.fetch_add(1, Ordering::Relaxed)
41}
42
43pub(crate) fn map_error_to_errno(e: MapError) -> Errno {
44 match e {
45 MapError::InvalidParam => errno!(EINVAL),
46 MapError::InvalidKey => errno!(ENOENT),
47 MapError::EntryExists => errno!(EEXIST),
48 MapError::NoMemory => errno!(ENOMEM),
49 MapError::SizeLimit => errno!(E2BIG),
50 MapError::MapTypeNotSupported | MapError::NotSupported => errno!(ENOSYS),
51 MapError::InvalidVmo | MapError::Internal => errno!(EIO),
52 }
53}
54
55fn check_map_create_access(current_task: &CurrentTask, schema: &MapSchema) -> Result<(), Errno> {
56 if security::is_task_capable_noaudit(current_task, CAP_SYS_ADMIN) {
57 return Ok(());
58 }
59 let cap_bpf_always_required = matches!(
60 schema.map_type,
61 bpf_map_type_BPF_MAP_TYPE_LPM_TRIE
62 | bpf_map_type_BPF_MAP_TYPE_LRU_HASH
63 | bpf_map_type_BPF_MAP_TYPE_LRU_PERCPU_HASH
64 | bpf_map_type_BPF_MAP_TYPE_QUEUE
65 | bpf_map_type_BPF_MAP_TYPE_STACK
66 | bpf_map_type_BPF_MAP_TYPE_ARRAY_OF_MAPS
67 | bpf_map_type_BPF_MAP_TYPE_HASH_OF_MAPS
68 | bpf_map_type_BPF_MAP_TYPE_BLOOM_FILTER
69 | bpf_map_type_BPF_MAP_TYPE_SK_STORAGE
70 | bpf_map_type_BPF_MAP_TYPE_INODE_STORAGE
71 | bpf_map_type_BPF_MAP_TYPE_TASK_STORAGE
72 | bpf_map_type_BPF_MAP_TYPE_CGROUP_STORAGE
73 | bpf_map_type_BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE
74 | bpf_map_type_BPF_MAP_TYPE_CGRP_STORAGE
75 );
76
77 if cap_bpf_always_required || !current_task.kernel().allow_unprivileged_bpf() {
78 security::check_task_capable(current_task, CAP_BPF)?;
79 }
80
81 match schema.map_type {
82 bpf_map_type_BPF_MAP_TYPE_DEVMAP
83 | bpf_map_type_BPF_MAP_TYPE_DEVMAP_HASH
84 | bpf_map_type_BPF_MAP_TYPE_CPUMAP
85 | bpf_map_type_BPF_MAP_TYPE_SOCKMAP
86 | bpf_map_type_BPF_MAP_TYPE_SOCKHASH
87 | bpf_map_type_BPF_MAP_TYPE_XSKMAP => {
88 security::check_task_capable(current_task, CAP_NET_ADMIN)?;
89 }
90 bpf_map_type_BPF_MAP_TYPE_STACK_TRACE => {
91 security::check_task_capable(current_task, CAP_PERFMON)?;
92 }
93 bpf_map_type_BPF_MAP_TYPE_STRUCT_OPS => {
94 return error!(EPERM);
95 }
96 _ => {}
97 }
98 Ok(())
99}
100
101#[derive(Debug, Default)]
102struct BpfMapState {
103 memory_object: Option<Arc<MemoryObject>>,
104 is_frozen: bool,
105}
106
107#[derive(Debug)]
109pub struct BpfMap {
110 id: BpfMapId,
111 map: PinnedMap,
112
113 state: LockDepMutex<BpfMapState, EbpfMapStateLevel>,
115
116 pub security_state: security::BpfMapState,
118
119 kernel: Weak<Kernel>,
121}
122
123impl Deref for BpfMap {
124 type Target = PinnedMap;
125 fn deref(&self) -> &PinnedMap {
126 &self.map
127 }
128}
129
130impl BpfMap {
131 pub fn new(
132 current_task: &CurrentTask,
133 schema: MapSchema,
134 name: &str,
135 security_state: security::BpfMapState,
136 ) -> Result<BpfMapHandle, Errno> {
137 check_map_create_access(current_task, &schema)?;
138
139 let map = Map::new(schema, name).map_err(map_error_to_errno)?;
140 let map = BpfMapHandle::new(
141 Self {
142 id: new_map_id(),
143 map,
144 state: Default::default(),
145 security_state,
146 kernel: Arc::downgrade(current_task.kernel()),
147 }
148 .into(),
149 );
150 current_task.kernel().ebpf_state.register_map(&map);
151 Ok(map)
152 }
153
154 pub fn id(&self) -> BpfMapId {
155 self.id
156 }
157
158 pub(crate) fn frozen<'a>(&'a self) -> impl Deref<Target = bool> + 'a {
159 let guard = self.state.lock();
160 LockDepGuard::map(guard, |s| &mut s.is_frozen)
161 }
162
163 pub(crate) fn freeze(&self) -> Result<(), Errno> {
164 let mut state = self.state.lock();
165 if state.is_frozen {
166 return Ok(());
167 }
168 if let Some(memory) = state.memory_object.take() {
169 if let Err(memory) = Arc::try_unwrap(memory) {
171 state.memory_object = Some(memory);
173 return error!(EBUSY);
174 }
175 }
176 state.is_frozen = true;
177 return Ok(());
178 }
179
180 pub(crate) fn get_inner(&self) -> PinnedMap {
181 self.map.clone()
182 }
183
184 pub(crate) fn get_memory<F>(&self, factory: F) -> Result<Arc<MemoryObject>, Errno>
185 where
186 F: FnOnce() -> Result<Arc<MemoryObject>, Errno>,
187 {
188 let mut state = self.state.lock();
189 if state.is_frozen {
190 return error!(EPERM);
191 }
192 if let Some(memory) = state.memory_object.as_ref() {
193 return Ok(memory.clone());
194 }
195 let memory = factory()?;
196 state.memory_object = Some(memory.clone());
197 Ok(memory)
198 }
199}
200
201impl Releasable for BpfMap {
202 type Context<'a> = &'a CurrentTask;
203
204 fn release<'a>(self, _current_task: &'a CurrentTask) {
205 if let Some(kernel) = self.kernel.upgrade() {
206 kernel.ebpf_state.unregister_map(self.id);
207 }
208 }
209}
210
211pub enum BpfMapReleaserAction {}
212impl ReleaserAction<BpfMap> for BpfMapReleaserAction {
213 fn release(map: ReleaseGuard<BpfMap>) {
214 register_delayed_release(map);
215 }
216}
217pub type BpfMapReleaser = ObjectReleaser<BpfMap, BpfMapReleaserAction>;
218pub type BpfMapHandle = Arc<BpfMapReleaser>;
219pub type WeakBpfMapHandle = Weak<BpfMapReleaser>;