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(), &param) } {
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