1use sandbox_core::{Result, SandboxError};
7
8#[derive(Debug, Clone, Default)]
10pub struct RlimitConfig {
11 pub max_memory: Option<u64>,
13 pub max_cpu_seconds: Option<u64>,
15 pub max_processes: Option<u64>,
17 pub max_file_size: Option<u64>,
19 pub max_open_files: Option<u64>,
21}
22
23impl RlimitConfig {
24 pub fn apply(&self) -> Result<()> {
27 if let Some(mem) = self.max_memory {
28 set_rlimit(libc::RLIMIT_AS, mem)?;
29 }
30 if let Some(cpu) = self.max_cpu_seconds {
31 set_rlimit(libc::RLIMIT_CPU, cpu)?;
32 }
33 if let Some(nproc) = self.max_processes {
34 set_rlimit(libc::RLIMIT_NPROC, nproc)?;
35 }
36 if let Some(fsize) = self.max_file_size {
37 set_rlimit(libc::RLIMIT_FSIZE, fsize)?;
38 }
39 if let Some(nofile) = self.max_open_files {
40 set_rlimit(libc::RLIMIT_NOFILE, nofile)?;
41 }
42 Ok(())
43 }
44}
45
46fn set_rlimit(resource: libc::__rlimit_resource_t, limit: u64) -> Result<()> {
47 let rlim = libc::rlimit {
48 rlim_cur: limit,
49 rlim_max: limit,
50 };
51
52 let ret = unsafe { libc::setrlimit(resource, &rlim) };
53 if ret != 0 {
54 let resource_name = match resource {
55 libc::RLIMIT_AS => "RLIMIT_AS",
56 libc::RLIMIT_CPU => "RLIMIT_CPU",
57 libc::RLIMIT_NPROC => "RLIMIT_NPROC",
58 libc::RLIMIT_FSIZE => "RLIMIT_FSIZE",
59 libc::RLIMIT_NOFILE => "RLIMIT_NOFILE",
60 _ => "UNKNOWN",
61 };
62 return Err(SandboxError::Syscall(format!(
63 "setrlimit({}) failed: {}",
64 resource_name,
65 std::io::Error::last_os_error()
66 )));
67 }
68 Ok(())
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn test_rlimit_config_default() {
77 let config = RlimitConfig::default();
78 assert!(config.max_memory.is_none());
79 assert!(config.max_cpu_seconds.is_none());
80 }
81
82 #[test]
83 fn test_empty_config_apply_succeeds() {
84 let config = RlimitConfig::default();
85 assert!(config.apply().is_ok());
86 }
87}