1 // Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved.
2 //
3 // StratoVirt is licensed under Mulan PSL v2.
4 // You can use this software according to the terms and conditions of the Mulan
5 // PSL v2.
6 // You may obtain a copy of Mulan PSL v2 at:
7 // http://license.coscl.org.cn/MulanPSL2
8 // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
9 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
10 // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11 // See the Mulan PSL v2 for more details.
12
13 use std::{
14 env,
15 ffi::CString,
16 fs::{self, read_to_string},
17 io::{stderr, stdin, stdout},
18 mem,
19 os::unix::{
20 io::{AsRawFd, RawFd},
21 net::UnixStream,
22 },
23 path::PathBuf,
24 str::FromStr,
25 };
26
27 use anyhow::{anyhow, bail, Context, Result};
28 use caps::{self, CapSet, Capability, CapsHashSet};
29 use libc::SIGCHLD;
30 use nix::{
31 errno::Errno,
32 sched::{clone, CloneFlags},
33 unistd::{self, chdir, setresgid, setresuid, Gid, Pid, Uid},
34 };
35 use rlimit::{setrlimit, Resource, Rlim};
36
37 use super::{apparmor, terminal::setup_console};
38 use crate::utils::{prctl, Clone3, OzonecErr};
39 use oci_spec::{linux::IoPriClass, process::Process as OciProcess};
40
41 pub struct Process {
42 pub stdin: Option<RawFd>,
43 pub stdout: Option<RawFd>,
44 pub stderr: Option<RawFd>,
45 pub init: bool,
46 pub tty: bool,
47 pub oci: OciProcess,
48 }
49
50 impl Process {
new(oci: &OciProcess, init: bool) -> Self51 pub fn new(oci: &OciProcess, init: bool) -> Self {
52 let mut p = Process {
53 stdin: None,
54 stdout: None,
55 stderr: None,
56 tty: oci.terminal,
57 init,
58 oci: oci.clone(),
59 };
60
61 if !p.tty {
62 p.stdin = Some(stdin().as_raw_fd());
63 p.stdout = Some(stdout().as_raw_fd());
64 p.stderr = Some(stderr().as_raw_fd());
65 }
66 p
67 }
68
set_tty(&self, console_fd: Option<UnixStream>, mount: bool) -> Result<()>69 pub fn set_tty(&self, console_fd: Option<UnixStream>, mount: bool) -> Result<()> {
70 if self.tty {
71 if console_fd.is_none() {
72 bail!("Terminal is specified, but no console socket set");
73 }
74 setup_console(&console_fd.unwrap().as_raw_fd(), mount)
75 .with_context(|| "Failed to setup console")?;
76 }
77 Ok(())
78 }
79
set_oom_score_adj(&self) -> Result<()>80 pub fn set_oom_score_adj(&self) -> Result<()> {
81 if let Some(score) = self.oci.oomScoreAdj {
82 fs::write("/proc/self/oom_score_adj", score.to_string().as_bytes())?;
83 }
84 Ok(())
85 }
86
set_rlimits(&self) -> Result<()>87 pub fn set_rlimits(&self) -> Result<()> {
88 if let Some(rlimits) = self.oci.rlimits.as_ref() {
89 for rlimit in rlimits {
90 setrlimit(
91 Resource::from_str(&rlimit.rlimit_type)
92 .with_context(|| "rlimit type is ill-formatted")?,
93 Rlim::from_raw(rlimit.soft),
94 Rlim::from_raw(rlimit.hard),
95 )?;
96 }
97 }
98 Ok(())
99 }
100
set_io_priority(&self) -> Result<()>101 pub fn set_io_priority(&self) -> Result<()> {
102 if let Some(io_prio) = &self.oci.ioPriority {
103 let class = match io_prio.class {
104 IoPriClass::IoprioClassRt => 1i64,
105 IoPriClass::IoprioClassBe => 2i64,
106 IoPriClass::IoprioClassIdle => 3i64,
107 };
108 // Who is a process id or thread id identifying a single process or
109 // thread. If who is 0, then operate on the calling process or thread.
110 let io_prio_who_process: libc::c_int = 1;
111 let io_prio_who_pid = 0;
112 // SAFETY: FFI call with valid arguments.
113 match unsafe {
114 libc::syscall(
115 libc::SYS_ioprio_set,
116 io_prio_who_process,
117 io_prio_who_pid,
118 (class << 13) | io_prio.priority,
119 )
120 } {
121 0 => Ok(()),
122 -1 => Err(nix::Error::last()),
123 _ => Err(nix::Error::UnknownErrno),
124 }?;
125 }
126 Ok(())
127 }
128
set_scheduler(&self) -> Result<()>129 pub fn set_scheduler(&self) -> Result<()> {
130 if let Some(scheduler) = &self.oci.scheduler {
131 // SAFETY: FFI call with valid arguments.
132 let mut param: libc::sched_param = unsafe { mem::zeroed() };
133 param.sched_priority = scheduler.priority.unwrap_or_default();
134 // SAFETY: FFI call with valid arguments.
135 match unsafe { libc::sched_setscheduler(0, scheduler.policy.into(), ¶m) } {
136 0 => Ok(()),
137 -1 => Err(nix::Error::last()),
138 _ => Err(nix::Error::UnknownErrno),
139 }?;
140 }
141 Ok(())
142 }
143
no_new_privileges(&self) -> bool144 pub fn no_new_privileges(&self) -> bool {
145 self.oci.noNewPrivileges.is_some()
146 }
147
set_no_new_privileges(&self) -> Result<()>148 pub fn set_no_new_privileges(&self) -> Result<()> {
149 if let Some(no_new_privileges) = self.oci.noNewPrivileges {
150 if no_new_privileges {
151 prctl::set_no_new_privileges(true)
152 .map_err(|e| anyhow!("Failed to set no new privileges: {}", e))?;
153 }
154 }
155 Ok(())
156 }
157
chdir_cwd(&self) -> Result<()>158 pub fn chdir_cwd(&self) -> Result<()> {
159 if !self.oci.cwd.is_empty() {
160 chdir(&PathBuf::from(&self.oci.cwd))
161 .with_context(|| format!("Failed to chdir to {}", &self.oci.cwd))?;
162 }
163 Ok(())
164 }
165
drop_capabilities(&self) -> Result<()>166 pub fn drop_capabilities(&self) -> Result<()> {
167 if let Some(caps) = self.oci.capabilities.as_ref() {
168 if let Some(bounding) = caps.bounding.as_ref() {
169 let all_caps = caps::read(None, CapSet::Bounding)
170 .with_context(|| OzonecErr::GetAllCaps("Bounding".to_string()))?;
171 let caps_hash_set = to_cap_set(bounding)?;
172 for cap in all_caps.difference(&caps_hash_set) {
173 caps::drop(None, CapSet::Bounding, *cap)
174 .with_context(|| format!("Failed to drop {} from bonding set", cap))?;
175 }
176 }
177 if let Some(effective) = caps.effective.as_ref() {
178 caps::set(None, CapSet::Effective, &to_cap_set(effective)?)
179 .with_context(|| OzonecErr::SetCaps("Effective".to_string()))?;
180 }
181 if let Some(permitted) = caps.permitted.as_ref() {
182 caps::set(None, CapSet::Permitted, &to_cap_set(permitted)?)
183 .with_context(|| OzonecErr::SetCaps("Permitted".to_string()))?;
184 }
185 if let Some(inheritable) = caps.inheritable.as_ref() {
186 caps::set(None, CapSet::Inheritable, &to_cap_set(inheritable)?)
187 .with_context(|| OzonecErr::SetCaps("Inheritable".to_string()))?;
188 }
189 if let Some(ambient) = caps.ambient.as_ref() {
190 caps::set(None, CapSet::Ambient, &to_cap_set(ambient)?)
191 .with_context(|| OzonecErr::SetCaps("Ambient".to_string()))?;
192 }
193 }
194 Ok(())
195 }
196
set_apparmor(&self) -> Result<()>197 pub fn set_apparmor(&self) -> Result<()> {
198 if let Some(profile) = &self.oci.apparmorProfile {
199 if !apparmor::is_enabled()? {
200 bail!("Apparmor is disabled.");
201 }
202 apparmor::apply_profile(profile)?;
203 }
204 Ok(())
205 }
206
reset_capabilities(&self) -> Result<()>207 pub fn reset_capabilities(&self) -> Result<()> {
208 let permitted = caps::read(None, CapSet::Permitted)
209 .with_context(|| OzonecErr::GetAllCaps("Permitted".to_string()))?;
210 caps::set(None, CapSet::Effective, &permitted)?;
211 Ok(())
212 }
213
set_additional_gids(&self) -> Result<()>214 pub fn set_additional_gids(&self) -> Result<()> {
215 if let Some(additional_gids) = &self.oci.user.additionalGids {
216 let setgroups = read_to_string("proc/self/setgroups")
217 .with_context(|| "Failed to read setgroups")?;
218 if setgroups.trim() == "deny" {
219 bail!("Cannot set additional gids as setgroup is desabled");
220 }
221
222 let gids: Vec<Gid> = additional_gids
223 .iter()
224 .map(|gid| Gid::from_raw(*gid))
225 .collect();
226 unistd::setgroups(&gids).with_context(|| "Failed to set additional gids")?;
227 }
228 Ok(())
229 }
230
set_process_id(&self) -> Result<()>231 pub fn set_process_id(&self) -> Result<()> {
232 let gid = Gid::from(self.oci.user.gid);
233 let uid = Uid::from(self.oci.user.uid);
234 self.set_id(gid, uid)?;
235 Ok(())
236 }
237
set_id(&self, gid: Gid, uid: Uid) -> Result<()>238 pub fn set_id(&self, gid: Gid, uid: Uid) -> Result<()> {
239 prctl::set_keep_capabilities(true)
240 .map_err(|e| anyhow!("Failed to enable keeping capabilities: {}", e))?;
241 setresgid(gid, gid, gid).with_context(|| "Failed to setresgid")?;
242 setresuid(uid, uid, uid).with_context(|| "Failed to setresuid")?;
243
244 let permitted = caps::read(None, CapSet::Permitted)
245 .with_context(|| OzonecErr::GetAllCaps("Permitted".to_string()))?;
246 caps::set(None, CapSet::Effective, &permitted)
247 .with_context(|| OzonecErr::SetCaps("Effective".to_string()))?;
248 prctl::set_keep_capabilities(false)
249 .map_err(|e| anyhow!("Failed to disable keeping capabilities: {}", e))?;
250 Ok(())
251 }
252
253 // Check and reserve valid environment variables.
254 // Invalid env vars may cause panic, refer to https://doc.rust-lang.org/std/env/fn.set_var.html#panics
255 // Key should not :
256 // * contain NULL character '\0'
257 // * contain ASCII character '='
258 // * be empty
259 // Value should not:
260 // * contain NULL character '\0'
is_env_valid(env: &str) -> Option<(&str, &str)>261 fn is_env_valid(env: &str) -> Option<(&str, &str)> {
262 // Split the env var by '=' to ensure there is no '=' in key, and there is only one '='
263 // in the whole env var.
264 if let Some((key, value)) = env.split_once('=') {
265 if !key.is_empty()
266 && !key.as_bytes().contains(&b'\0')
267 && !value.as_bytes().contains(&b'\0')
268 {
269 return Some((key.trim(), value.trim()));
270 }
271 }
272 None
273 }
274
set_envs(&self)275 pub fn set_envs(&self) {
276 if let Some(envs) = &self.oci.env {
277 for env in envs {
278 if let Some((key, value)) = Self::is_env_valid(env) {
279 env::set_var(key, value);
280 }
281 }
282 }
283 }
284
clean_envs(&self)285 pub fn clean_envs(&self) {
286 env::vars().for_each(|(key, _value)| env::remove_var(key));
287 }
288
exec_program(&self) -> !289 pub fn exec_program(&self) -> ! {
290 // It has been make sure that args is not None in validate_config().
291 let args = &self.oci.args.as_ref().unwrap();
292 // args don't have 0 byte in the middle such as "hello\0world".
293 let exec_bin = CString::new(args[0].as_bytes()).unwrap();
294 let args: Vec<CString> = args
295 .iter()
296 .map(|s| CString::new(s.as_bytes()).unwrap_or_default())
297 .collect();
298
299 let _ = unistd::execvp(&exec_bin, &args).map_err(|e| match e {
300 nix::Error::UnknownErrno => std::process::exit(-2),
301 _ => std::process::exit(e as i32),
302 });
303
304 unreachable!()
305 }
306
getcwd() -> Result<()>307 pub fn getcwd() -> Result<()> {
308 unistd::getcwd().map_err(|e| match e {
309 Errno::ENOENT => anyhow!("Current working directory is out of container rootfs"),
310 _ => anyhow!("Failed to getcwd"),
311 })?;
312 Ok(())
313 }
314 }
315
316 // Clone a new child process.
clone_process<F: FnMut() -> Result<i32>>(child_name: &str, mut cb: F) -> Result<Pid>317 pub fn clone_process<F: FnMut() -> Result<i32>>(child_name: &str, mut cb: F) -> Result<Pid> {
318 let mut clone3 = Clone3::default();
319 clone3.exit_signal(SIGCHLD as u64);
320
321 let mut ret = clone3.call();
322 if ret.is_err() {
323 // clone3() may not be supported in the kernel, fallback to clone();
324 let mut stack = [0; 1024 * 1024];
325 ret = clone(
326 Box::new(|| match cb() {
327 Ok(r) => r as isize,
328 Err(e) => {
329 eprintln!("{}", e);
330 -1
331 }
332 }),
333 &mut stack,
334 CloneFlags::empty(),
335 Some(SIGCHLD),
336 )
337 .map_err(|e| anyhow!("Clone error: errno {}", e));
338 }
339
340 match ret {
341 Ok(pid) => {
342 if pid.as_raw() != 0 {
343 return Ok(pid);
344 }
345
346 prctl::set_name(child_name)
347 .map_err(|e| anyhow!("Failed to set process name: errno {}", e))?;
348 let ret = match cb() {
349 Err(e) => {
350 eprintln!("Child process exit with errors: {:?}", e);
351 -1
352 }
353 Ok(exit_code) => exit_code,
354 };
355 std::process::exit(ret);
356 }
357 Err(e) => bail!(e),
358 }
359 }
360
to_cap_set(caps: &Vec<String>) -> Result<CapsHashSet>361 fn to_cap_set(caps: &Vec<String>) -> Result<CapsHashSet> {
362 let mut caps_hash_set = CapsHashSet::new();
363
364 for c in caps {
365 let cap = to_cap(c)?;
366 caps_hash_set.insert(cap);
367 }
368 Ok(caps_hash_set)
369 }
370
to_cap(value: &str) -> Result<Capability>371 fn to_cap(value: &str) -> Result<Capability> {
372 let binding = value.to_uppercase();
373 let stripped = binding.strip_prefix("CAP_").unwrap_or(&binding);
374
375 match stripped {
376 "AUDIT_CONTROL" => Ok(Capability::CAP_AUDIT_CONTROL),
377 "AUDIT_READ" => Ok(Capability::CAP_AUDIT_READ),
378 "AUDIT_WRITE" => Ok(Capability::CAP_AUDIT_WRITE),
379 "BLOCK_SUSPEND" => Ok(Capability::CAP_BLOCK_SUSPEND),
380 "BPF" => Ok(Capability::CAP_BPF),
381 "CHECKPOINT_RESTORE" => Ok(Capability::CAP_CHECKPOINT_RESTORE),
382 "CHOWN" => Ok(Capability::CAP_CHOWN),
383 "DAC_OVERRIDE" => Ok(Capability::CAP_DAC_OVERRIDE),
384 "DAC_READ_SEARCH" => Ok(Capability::CAP_DAC_READ_SEARCH),
385 "FOWNER" => Ok(Capability::CAP_FOWNER),
386 "FSETID" => Ok(Capability::CAP_FSETID),
387 "IPC_LOCK" => Ok(Capability::CAP_IPC_LOCK),
388 "IPC_OWNER" => Ok(Capability::CAP_IPC_OWNER),
389 "KILL" => Ok(Capability::CAP_KILL),
390 "LEASE" => Ok(Capability::CAP_LEASE),
391 "LINUX_IMMUTABLE" => Ok(Capability::CAP_LINUX_IMMUTABLE),
392 "MAC_ADMIN" => Ok(Capability::CAP_MAC_ADMIN),
393 "MAC_OVERRIDE" => Ok(Capability::CAP_MAC_OVERRIDE),
394 "MKNOD" => Ok(Capability::CAP_MKNOD),
395 "NET_ADMIN" => Ok(Capability::CAP_NET_ADMIN),
396 "NET_BIND_SERVICE" => Ok(Capability::CAP_NET_BIND_SERVICE),
397 "NET_BROADCAST" => Ok(Capability::CAP_NET_BROADCAST),
398 "NET_RAW" => Ok(Capability::CAP_NET_RAW),
399 "PERFMON" => Ok(Capability::CAP_PERFMON),
400 "SETGID" => Ok(Capability::CAP_SETGID),
401 "SETFCAP" => Ok(Capability::CAP_SETFCAP),
402 "SETPCAP" => Ok(Capability::CAP_SETPCAP),
403 "SETUID" => Ok(Capability::CAP_SETUID),
404 "SYS_ADMIN" => Ok(Capability::CAP_SYS_ADMIN),
405 "SYS_BOOT" => Ok(Capability::CAP_SYS_BOOT),
406 "SYS_CHROOT" => Ok(Capability::CAP_SYS_CHROOT),
407 "SYS_MODULE" => Ok(Capability::CAP_SYS_MODULE),
408 "SYS_NICE" => Ok(Capability::CAP_SYS_NICE),
409 "SYS_PACCT" => Ok(Capability::CAP_SYS_PACCT),
410 "SYS_PTRACE" => Ok(Capability::CAP_SYS_PTRACE),
411 "SYS_RAWIO" => Ok(Capability::CAP_SYS_RAWIO),
412 "SYS_RESOURCE" => Ok(Capability::CAP_SYS_RESOURCE),
413 "SYS_TIME" => Ok(Capability::CAP_SYS_TIME),
414 "SYS_TTY_CONFIG" => Ok(Capability::CAP_SYS_TTY_CONFIG),
415 "SYSLOG" => Ok(Capability::CAP_SYSLOG),
416 "WAKE_ALARM" => Ok(Capability::CAP_WAKE_ALARM),
417 _ => bail!("Invalid capability: {}", value),
418 }
419 }
420
421 #[cfg(test)]
422 pub mod tests {
423 use std::path::Path;
424
425 use nix::sys::resource::{getrlimit, Resource};
426 use rusty_fork::rusty_fork_test;
427 use unistd::getcwd;
428
429 use oci_spec::{
430 linux::{Capbilities, IoPriority, SchedPolicy, Scheduler},
431 posix::{Rlimits, User},
432 };
433
434 use super::*;
435
init_oci_process() -> OciProcess436 pub fn init_oci_process() -> OciProcess {
437 let user = User {
438 uid: 0,
439 gid: 0,
440 umask: None,
441 additionalGids: None,
442 };
443 OciProcess {
444 cwd: String::from("/"),
445 args: Some(vec![String::from("bash")]),
446 env: None,
447 terminal: false,
448 consoleSize: None,
449 rlimits: None,
450 apparmorProfile: None,
451 capabilities: None,
452 noNewPrivileges: None,
453 oomScoreAdj: None,
454 scheduler: None,
455 selinuxLabel: None,
456 ioPriority: None,
457 execCPUAffinity: None,
458 user,
459 }
460 }
461
462 #[test]
test_process_new()463 fn test_process_new() {
464 let mut oci_process = init_oci_process();
465
466 let process = Process::new(&oci_process, false);
467 assert_eq!(process.stdin.unwrap(), stdin().as_raw_fd());
468 assert_eq!(process.stdout.unwrap(), stdout().as_raw_fd());
469 assert_eq!(process.stderr.unwrap(), stderr().as_raw_fd());
470
471 oci_process.terminal = true;
472 let process = Process::new(&oci_process, false);
473 assert!(process.stdin.is_none());
474 assert!(process.stdout.is_none());
475 assert!(process.stderr.is_none());
476 }
477
478 #[test]
test_set_tty()479 fn test_set_tty() {
480 let mut oci_process = init_oci_process();
481
482 let process = Process::new(&oci_process, false);
483 assert!(process.set_tty(None, false).is_ok());
484
485 oci_process.terminal = true;
486 let process = Process::new(&oci_process, false);
487 assert!(process.set_tty(None, false).is_err());
488 }
489
490 #[test]
test_chdir_cwd()491 fn test_chdir_cwd() {
492 let oci_process = init_oci_process();
493 let process = Process::new(&oci_process, false);
494
495 assert!(process.chdir_cwd().is_ok());
496 assert_eq!(getcwd().unwrap().to_str().unwrap(), "/");
497 }
498
499 #[test]
test_set_envs()500 fn test_set_envs() {
501 let mut oci_process = init_oci_process();
502 oci_process.env = Some(vec![
503 String::from("OZONEC_ENV_1=1"),
504 String::from("=OZONEC_ENV_2"),
505 String::from("OZONEC_ENV"),
506 ]);
507 let process = Process::new(&oci_process, false);
508
509 process.set_envs();
510 for (key, value) in env::vars() {
511 if key == "OZONEC_ENV_1" {
512 assert_eq!(value, "1");
513 continue;
514 }
515 assert_ne!(value, "OZONEC_ENV_2");
516 assert_ne!(key, "OZONEC_ENV");
517 assert_ne!(value, "OZONEC_ENV");
518 }
519
520 env::remove_var("OZONEC_ENV_1");
521 }
522
523 #[test]
test_to_cap()524 fn test_to_cap() {
525 assert_eq!(
526 to_cap("CAP_AUDIT_CONTROL").unwrap(),
527 Capability::CAP_AUDIT_CONTROL
528 );
529 assert_eq!(
530 to_cap("CAP_AUDIT_READ").unwrap(),
531 Capability::CAP_AUDIT_READ
532 );
533 assert_eq!(
534 to_cap("CAP_AUDIT_WRITE").unwrap(),
535 Capability::CAP_AUDIT_WRITE
536 );
537 assert_eq!(
538 to_cap("CAP_BLOCK_SUSPEND").unwrap(),
539 Capability::CAP_BLOCK_SUSPEND
540 );
541 assert_eq!(to_cap("CAP_BPF").unwrap(), Capability::CAP_BPF);
542 assert_eq!(
543 to_cap("CAP_CHECKPOINT_RESTORE").unwrap(),
544 Capability::CAP_CHECKPOINT_RESTORE
545 );
546 assert_eq!(to_cap("CAP_CHOWN").unwrap(), Capability::CAP_CHOWN);
547 assert_eq!(
548 to_cap("CAP_DAC_OVERRIDE").unwrap(),
549 Capability::CAP_DAC_OVERRIDE
550 );
551 assert_eq!(
552 to_cap("CAP_DAC_READ_SEARCH").unwrap(),
553 Capability::CAP_DAC_READ_SEARCH
554 );
555 assert_eq!(to_cap("CAP_FOWNER").unwrap(), Capability::CAP_FOWNER);
556 assert_eq!(to_cap("CAP_FSETID").unwrap(), Capability::CAP_FSETID);
557 assert_eq!(to_cap("CAP_IPC_LOCK").unwrap(), Capability::CAP_IPC_LOCK);
558 assert_eq!(to_cap("CAP_IPC_OWNER").unwrap(), Capability::CAP_IPC_OWNER);
559 assert_eq!(to_cap("CAP_KILL").unwrap(), Capability::CAP_KILL);
560 assert_eq!(to_cap("CAP_LEASE").unwrap(), Capability::CAP_LEASE);
561 assert_eq!(
562 to_cap("CAP_LINUX_IMMUTABLE").unwrap(),
563 Capability::CAP_LINUX_IMMUTABLE
564 );
565 assert_eq!(to_cap("CAP_MAC_ADMIN").unwrap(), Capability::CAP_MAC_ADMIN);
566 assert_eq!(
567 to_cap("CAP_MAC_OVERRIDE").unwrap(),
568 Capability::CAP_MAC_OVERRIDE
569 );
570 assert_eq!(to_cap("CAP_MKNOD").unwrap(), Capability::CAP_MKNOD);
571 assert_eq!(to_cap("CAP_NET_ADMIN").unwrap(), Capability::CAP_NET_ADMIN);
572 assert_eq!(
573 to_cap("CAP_NET_BIND_SERVICE").unwrap(),
574 Capability::CAP_NET_BIND_SERVICE
575 );
576 assert_eq!(
577 to_cap("CAP_NET_BROADCAST").unwrap(),
578 Capability::CAP_NET_BROADCAST
579 );
580 assert_eq!(to_cap("CAP_NET_RAW").unwrap(), Capability::CAP_NET_RAW);
581 assert_eq!(to_cap("CAP_PERFMON").unwrap(), Capability::CAP_PERFMON);
582 assert_eq!(to_cap("CAP_SETGID").unwrap(), Capability::CAP_SETGID);
583 assert_eq!(to_cap("CAP_SETFCAP").unwrap(), Capability::CAP_SETFCAP);
584 assert_eq!(to_cap("CAP_SETPCAP").unwrap(), Capability::CAP_SETPCAP);
585 assert_eq!(to_cap("CAP_SETUID").unwrap(), Capability::CAP_SETUID);
586 assert_eq!(to_cap("CAP_SYS_ADMIN").unwrap(), Capability::CAP_SYS_ADMIN);
587 assert_eq!(to_cap("CAP_SYS_BOOT").unwrap(), Capability::CAP_SYS_BOOT);
588 assert_eq!(
589 to_cap("CAP_SYS_CHROOT").unwrap(),
590 Capability::CAP_SYS_CHROOT
591 );
592 assert_eq!(
593 to_cap("CAP_SYS_MODULE").unwrap(),
594 Capability::CAP_SYS_MODULE
595 );
596 assert_eq!(to_cap("CAP_SYS_NICE").unwrap(), Capability::CAP_SYS_NICE);
597 assert_eq!(to_cap("CAP_SYS_PACCT").unwrap(), Capability::CAP_SYS_PACCT);
598 assert_eq!(
599 to_cap("CAP_SYS_PTRACE").unwrap(),
600 Capability::CAP_SYS_PTRACE
601 );
602 assert_eq!(to_cap("CAP_SYS_RAWIO").unwrap(), Capability::CAP_SYS_RAWIO);
603 assert_eq!(
604 to_cap("CAP_SYS_RESOURCE").unwrap(),
605 Capability::CAP_SYS_RESOURCE
606 );
607 assert_eq!(to_cap("CAP_SYS_TIME").unwrap(), Capability::CAP_SYS_TIME);
608 assert_eq!(
609 to_cap("CAP_SYS_TTY_CONFIG").unwrap(),
610 Capability::CAP_SYS_TTY_CONFIG
611 );
612 assert_eq!(to_cap("CAP_SYSLOG").unwrap(), Capability::CAP_SYSLOG);
613 assert_eq!(
614 to_cap("CAP_WAKE_ALARM").unwrap(),
615 Capability::CAP_WAKE_ALARM
616 );
617 assert!(to_cap("CAP_TO_CAP").is_err());
618 }
619
620 rusty_fork_test! {
621 #[test]
622 #[ignore = "oom_score_adj may not be permitted to set"]
623 fn test_set_oom_score_adj() {
624 let mut oci_process = init_oci_process();
625 oci_process.oomScoreAdj = Some(100);
626 let process = Process::new(&oci_process, false);
627
628 assert!(process.set_oom_score_adj().is_ok());
629 assert_eq!(
630 read_to_string(Path::new("/proc/self/oom_score_adj")).unwrap(),
631 String::from("100\n")
632 );
633 }
634
635 #[test]
636 #[ignore = "setrlimit may not be permitted"]
637 fn test_set_rlimits() {
638 let mut oci_process = init_oci_process();
639 let rlimits = Rlimits {
640 rlimit_type: String::from("RLIMIT_CORE"),
641 soft: 10,
642 hard: 20,
643 };
644 oci_process.rlimits = Some(vec![rlimits]);
645 let process = Process::new(&oci_process, false);
646
647 assert!(process.set_rlimits().is_ok());
648 assert_eq!(getrlimit(Resource::RLIMIT_CORE).unwrap().0, 10);
649 assert_eq!(getrlimit(Resource::RLIMIT_CORE).unwrap().1, 20);
650 }
651
652 #[test]
653 fn test_set_io_priority() {
654 let mut oci_process = init_oci_process();
655 let io_pri = IoPriority {
656 class: IoPriClass::IoprioClassBe,
657 priority: 7,
658 };
659 oci_process.ioPriority = Some(io_pri.clone());
660 let process = Process::new(&oci_process, false);
661
662 assert!(process.set_io_priority().is_ok());
663
664 let io_prio_who_process: libc::c_int = 1;
665 let io_prio_who_pid = 0;
666 let ioprio = unsafe {
667 libc::syscall(libc::SYS_ioprio_get, io_prio_who_process, io_prio_who_pid)
668 };
669 assert_eq!(ioprio, (2 as i64) << 13 | io_pri.priority);
670 }
671
672 #[test]
673 fn test_set_scheduler() {
674 let mut oci_process = init_oci_process();
675 let scheduler = Scheduler {
676 policy: SchedPolicy::SchedOther,
677 nice: None,
678 priority: None,
679 flags: None,
680 runtime: None,
681 deadline: None,
682 period: None,
683 };
684 oci_process.scheduler = Some(scheduler);
685 let process = Process::new(&oci_process, false);
686
687 assert!(process.set_scheduler().is_ok());
688 }
689
690 #[test]
691 fn test_set_no_new_privileges() {
692 let mut oci_process = init_oci_process();
693 oci_process.noNewPrivileges = Some(true);
694 let process = Process::new(&oci_process, false);
695
696 assert!(process.set_no_new_privileges().is_ok());
697 }
698
699 #[test]
700 #[ignore = "capset may not be permitted"]
701 fn test_drop_capabilities() {
702 let mut oci_process = init_oci_process();
703 let caps = Capbilities {
704 effective: Some(vec![
705 String::from("CAP_DAC_OVERRIDE"),
706 String::from("CAP_DAC_READ_SEARCH"),
707 String::from("CAP_SETFCAP"),
708 ]),
709 bounding: Some(vec![
710 String::from("CAP_DAC_OVERRIDE"),
711 String::from("CAP_DAC_READ_SEARCH"),
712 ]),
713 inheritable: Some(vec![String::from("CAP_DAC_READ_SEARCH")]),
714 permitted: Some(vec![
715 String::from("CAP_DAC_OVERRIDE"),
716 String::from("CAP_DAC_READ_SEARCH"),
717 String::from("CAP_SETFCAP"),
718 ]),
719 ambient: Some(vec![String::from("CAP_DAC_READ_SEARCH")]),
720 };
721 oci_process.capabilities = Some(caps);
722 let process = Process::new(&oci_process, false);
723
724 assert!(process.drop_capabilities().is_ok());
725 let mut caps = caps::read(None, CapSet::Bounding).unwrap();
726 assert_eq!(caps.len(), 2);
727 assert!(caps.get(&Capability::CAP_DAC_OVERRIDE).is_some());
728 assert!(caps.get(&Capability::CAP_DAC_READ_SEARCH).is_some());
729 caps = caps::read(None, CapSet::Effective).unwrap();
730 assert_eq!(caps.len(), 3);
731 assert!(caps.get(&Capability::CAP_DAC_OVERRIDE).is_some());
732 assert!(caps.get(&Capability::CAP_DAC_READ_SEARCH).is_some());
733 assert!(caps.get(&Capability::CAP_SETFCAP).is_some());
734 caps = caps::read(None, CapSet::Inheritable).unwrap();
735 assert_eq!(caps.len(), 1);
736 assert!(caps.get(&Capability::CAP_DAC_READ_SEARCH).is_some());
737 caps = caps::read(None, CapSet::Permitted).unwrap();
738 assert_eq!(caps.len(), 3);
739 assert!(caps.get(&Capability::CAP_DAC_OVERRIDE).is_some());
740 assert!(caps.get(&Capability::CAP_DAC_READ_SEARCH).is_some());
741 assert!(caps.get(&Capability::CAP_SETFCAP).is_some());
742 caps = caps::read(None, CapSet::Ambient).unwrap();
743 assert_eq!(caps.len(), 1);
744 assert!(caps.get(&Capability::CAP_DAC_READ_SEARCH).is_some());
745 }
746
747 #[test]
748 fn test_reset_capabilities() {
749 let oci_process = init_oci_process();
750 let process = Process::new(&oci_process, false);
751
752 assert!(process.reset_capabilities().is_ok());
753 let permit_caps = caps::read(None, CapSet::Permitted).unwrap();
754 let eff_caps = caps::read(None, CapSet::Effective).unwrap();
755 assert_eq!(permit_caps, eff_caps);
756 }
757
758 #[test]
759 fn test_clean_envs() {
760 let oci_process = init_oci_process();
761 let process = Process::new(&oci_process, false);
762 process.clean_envs();
763 assert_eq!(env::vars().count(), 0);
764 }
765 }
766 }
767