1use crate::vfs::socket::AuditNetlinkClient;
6use linux_uapi::{
7 AUDIT_CONFIG_CHANGE, AUDIT_FAIL_PANIC, AUDIT_FAIL_PRINTK, AUDIT_FAIL_SILENT,
8 AUDIT_FIRST_USER_MSG, AUDIT_FIRST_USER_MSG2, AUDIT_GET, AUDIT_LAST_USER_MSG,
9 AUDIT_LAST_USER_MSG2, AUDIT_SET, AUDIT_STATUS_BACKLOG_LIMIT, AUDIT_STATUS_ENABLED,
10 AUDIT_STATUS_FAILURE, AUDIT_STATUS_LOST, AUDIT_STATUS_PID, AUDIT_USER,
11};
12use starnix_lifecycle::AtomicCounter;
13use starnix_logging::log_warn;
14use starnix_sync::{AuditQueueLock, AuditSinkLock, LockDepGuard, LockDepMutex};
15use starnix_uapi::errors::Errno;
16use starnix_uapi::{audit_status, error, pid_t};
17use std::collections::VecDeque;
18use std::fmt::Display;
19use std::sync::Arc;
20use std::sync::atomic::{AtomicU8, AtomicU32, Ordering};
21use std::time::SystemTime;
22use std::u32;
23use zx::MonotonicDuration;
24
25use crate::task::{ArgNameAndValue, CurrentTask, Kernel};
26const DEFAULT_BACKLOG_LIMIT: u32 = 128;
27
28pub enum AuditRequest {
30 AuditGet,
31 AuditSet,
32 AuditUser,
33}
34
35impl TryFrom<u32> for AuditRequest {
36 type Error = Errno;
37
38 fn try_from(value: u32) -> Result<Self, Self::Error> {
39 match value {
40 AUDIT_GET => Ok(Self::AuditGet),
41 AUDIT_SET => Ok(Self::AuditSet),
42 AUDIT_USER
43 | AUDIT_FIRST_USER_MSG..=AUDIT_LAST_USER_MSG
44 | AUDIT_FIRST_USER_MSG2..=AUDIT_LAST_USER_MSG2 => Ok(Self::AuditUser),
45 _ => error!(ENOTSUP),
46 }
47 }
48}
49
50#[derive(PartialEq)]
52enum AuditMode {
53 Disabled,
54 Unspecified,
55 Enabled,
56}
57
58#[derive(Default)]
60struct AuditNetlinkClientRef {
61 client: Option<Arc<AuditNetlinkClient>>,
63 pid: pid_t,
65 messages: VecDeque<AuditMessage>,
67}
68
69struct AuditConfig {
71 audit_mode: AuditMode,
73 backlog_limit: AtomicU32,
75 fail_action: AtomicU8,
77 audit_sink: LockDepMutex<AuditNetlinkClientRef, AuditSinkLock>,
79}
80
81impl Default for AuditConfig {
82 fn default() -> Self {
83 Self {
84 audit_mode: AuditMode::Unspecified,
85 backlog_limit: AtomicU32::new(DEFAULT_BACKLOG_LIMIT),
86 fail_action: AtomicU8::new(AUDIT_FAIL_PRINTK as u8),
87 audit_sink: Default::default(),
88 }
89 }
90}
91
92impl AuditConfig {
93 pub fn new<'a>(cmdline_iter: impl Iterator<Item = ArgNameAndValue<'a>>) -> Self {
94 let mut config = Self::default();
95 config.apply_kernel_cmdline(cmdline_iter);
97 config
98 }
99
100 fn apply_kernel_cmdline<'a>(
102 &mut self,
103 cmdline_iter: impl Iterator<Item = ArgNameAndValue<'a>>,
104 ) {
105 for arg in cmdline_iter {
106 match arg {
107 ArgNameAndValue { name: "audit", value: Some(value) } => match value {
108 "0" | "off" => self.audit_mode = AuditMode::Disabled,
109 _ => self.audit_mode = AuditMode::Enabled,
111 },
112 ArgNameAndValue { name: "audit_backlog_limit", value: Some(value) } => self
113 .backlog_limit
114 .store(value.parse().unwrap_or(DEFAULT_BACKLOG_LIMIT), Ordering::Release),
115 _ => (),
116 }
117 }
118 }
119}
120
121pub struct AuditLogger {
123 configuration: AuditConfig,
125 lost_audit_messages: AtomicU32,
127 serial_counter: AtomicCounter<u64>,
129 audit_queue: LockDepMutex<VecDeque<AuditMessage>, AuditQueueLock>,
132}
133
134impl AuditLogger {
135 pub fn new(kernel: &Kernel) -> Self {
136 Self {
137 configuration: AuditConfig::new(kernel.cmdline_args_iter()),
138 lost_audit_messages: Default::default(),
139 serial_counter: Default::default(),
140 audit_queue: Default::default(),
141 }
142 }
143
144 pub fn is_disabled(&self) -> bool {
145 self.configuration.audit_mode == AuditMode::Disabled
146 }
147
148 pub fn audit_log<M: Display, T: FnOnce() -> M>(&self, audit_type: u16, audit_formatter: T) {
152 if self.configuration.audit_mode == AuditMode::Disabled {
153 return;
154 }
155 self.add_audit_to_backlog(audit_type, audit_formatter);
156 }
157
158 pub fn read_audit_log(&self, client: &Arc<AuditNetlinkClient>) -> Option<AuditMessage> {
160 let mut client_guard = self.configuration.audit_sink.lock();
161 let Some(current_client) = client_guard.client.as_ref() else {
162 return None;
163 };
164 if !Arc::ptr_eq(¤t_client, client) {
166 return None;
167 }
168 client_guard.messages.pop_front()
169 }
170
171 pub fn detach_client(&self, client: &Arc<AuditNetlinkClient>) {
174 let mut client_guard = self.configuration.audit_sink.lock();
175 if client_guard
176 .client
177 .as_ref()
178 .is_some_and(|current_client| Arc::ptr_eq(client, ¤t_client))
179 {
180 let pid = client_guard.pid;
181 client_guard.client = None;
182 client_guard.pid = 0;
183 client_guard.messages.clear();
184 drop(client_guard);
185 self.audit_log(AUDIT_CONFIG_CHANGE as u16, || format!("audit sink detached pid={pid}"));
186 }
187 }
188
189 pub fn set_status(
191 &self,
192 current_task: &CurrentTask,
193 status: audit_status,
194 client: &Arc<AuditNetlinkClient>,
195 ) -> Result<(), Errno> {
196 if status.mask & AUDIT_STATUS_ENABLED != 0 && status.enabled > 1 {
199 return error!(EINVAL);
200 }
201 if status.mask & AUDIT_STATUS_BACKLOG_LIMIT != 0 {
202 self.configuration.backlog_limit.store(status.backlog_limit, Ordering::Release);
203 }
204 if status.mask & AUDIT_STATUS_FAILURE != 0 {
205 self.configuration.fail_action.store(status.failure as u8, Ordering::Release);
206 }
207 if status.mask & AUDIT_STATUS_LOST != 0 {
208 self.lost_audit_messages.store(0, Ordering::Release);
209 }
210 if status.mask & AUDIT_STATUS_PID != 0 {
211 self.update_client(current_task.get_pid(), status.pid as pid_t, client)?;
212 }
213 Ok(())
214 }
215
216 pub fn get_status(&self) -> audit_status {
218 let pid = self.configuration.audit_sink.lock().pid as u32;
219 let backlog = self.audit_queue.lock().len() as u32;
220 audit_status {
221 mask: Default::default(),
222 enabled: Default::default(),
223 failure: self.configuration.fail_action.load(Ordering::Acquire) as u32,
224 pid,
225 rate_limit: u32::MAX,
226 backlog_limit: self.configuration.backlog_limit.load(Ordering::Acquire),
227 lost: self.lost_audit_messages.load(Ordering::Acquire),
228 backlog,
229 __bindgen_anon_1: Default::default(),
230 backlog_wait_time: Default::default(),
231 backlog_wait_time_actual: Default::default(),
232 }
233 }
234
235 pub fn get_backlog_count(&self, client: &Arc<AuditNetlinkClient>) -> usize {
237 let client_guard = self.configuration.audit_sink.lock();
238 if let Some(current_client) = &client_guard.client {
239 if Arc::ptr_eq(¤t_client, client) {
240 return client_guard.messages.len();
241 }
242 }
243 0
244 }
245
246 fn update_client(
248 &self,
249 pid: pid_t,
250 request_pid: pid_t,
251 client: &Arc<AuditNetlinkClient>,
252 ) -> Result<(), Errno> {
253 if request_pid == 0 {
254 let client_ref = {
255 let client_guard = self.configuration.audit_sink.lock();
256 if client_guard.pid == 0 {
258 return Ok(());
259 } else if pid != client_guard.pid {
260 return error!(EPERM);
261 }
262 client_guard.client.clone()
263 };
264 client_ref.inspect(|client_ref| self.detach_client(&client_ref));
265 return Ok(());
266 }
267 if pid != request_pid {
268 return error!(EINVAL);
269 }
270
271 let mut client_guard = self.configuration.audit_sink.lock();
272 if client_guard.client.is_some() {
273 return error!(EEXIST);
274 }
275 client_guard.client = Some(client.clone());
276 client_guard.pid = pid;
277 drop(client_guard);
278 self.audit_log(AUDIT_CONFIG_CHANGE as u16, || format!("new audit sink attached pid={pid}"));
279 Ok(())
280 }
281
282 fn add_audit_to_backlog<M: Display, T: FnOnce() -> M>(
284 &self,
285 audit_type: u16,
286 audit_formatter: T,
287 ) {
288 let audit_message = self.prepend_audit_metadata(audit_formatter);
290
291 let mut client_guard = self.configuration.audit_sink.lock();
292 if client_guard.client.is_none() {
295 log_warn!("audit: type={audit_type} msg={audit_message}");
296 }
297
298 if client_guard.client.is_some() || self.configuration.audit_mode == AuditMode::Enabled {
299 self.push_back_audit(audit_type, audit_message, &mut client_guard);
300 let client = client_guard.client.clone();
301 drop(client_guard);
302 if let Some(client) = client {
303 client.notify();
304 }
305 }
306 }
307
308 fn push_back_audit(
310 &self,
311 audit_type: u16,
312 audit_message: String,
313 client_guard: &mut LockDepGuard<'_, AuditNetlinkClientRef>,
314 ) {
315 if self.check_backlog(client_guard.messages.len() as u32) {
317 return;
318 }
319 client_guard.messages.push_back(AuditMessage { audit_type, message: audit_message.into() });
320 }
321
322 fn check_backlog(&self, backlog_size: u32) -> bool {
327 let limit = self.configuration.backlog_limit.load(Ordering::Acquire);
328 if limit != 0 && backlog_size >= limit {
329 let lost = self.lost_audit_messages.fetch_add(1, Ordering::Release) + 1;
330 log_warn!("audit_lost={lost} backlog_limit={limit}");
331 match self.configuration.fail_action.load(Ordering::Acquire) as u32 {
333 AUDIT_FAIL_PANIC => panic!("backlog limit exceeded"),
334 AUDIT_FAIL_PRINTK => log_warn!("backlog limit exceeded"),
335 AUDIT_FAIL_SILENT | _ => (),
336 }
337 return true;
338 }
339 false
340 }
341
342 fn prepend_audit_metadata<M: Display, T: FnOnce() -> M>(&self, audit: T) -> String {
344 let epoch_time = MonotonicDuration::from(
345 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap_or_default(),
346 )
347 .into_millis();
348
349 format!(
350 "audit({}.{}:{}): {}",
351 epoch_time / 1000,
352 epoch_time % 1000,
353 self.serial_counter.next(),
354 audit()
355 )
356 }
357}
358
359pub struct AuditMessage {
361 pub audit_type: u16,
363 pub message: Vec<u8>,
365}