diff --git a/src/capabilities.rs b/src/capabilities.rs index 66f515d91..7c1ed431d 100644 --- a/src/capabilities.rs +++ b/src/capabilities.rs @@ -178,9 +178,476 @@ mod tests { #[test] fn test_convert_oci_spec_to_caps_type() { - let chown = oci_spec::runtime::Capability::Chown; + struct Testcase { + input: SpecCapability, + want: CapsCapability, + } + + let tests = vec![ + Testcase { + input: SpecCapability::AuditControl, + want: CapsCapability::CAP_AUDIT_CONTROL, + }, + Testcase { + input: SpecCapability::AuditRead, + want: CapsCapability::CAP_AUDIT_READ, + }, + Testcase { + input: SpecCapability::AuditWrite, + want: CapsCapability::CAP_AUDIT_WRITE, + }, + Testcase { + input: SpecCapability::BlockSuspend, + want: CapsCapability::CAP_BLOCK_SUSPEND, + }, + Testcase { + input: SpecCapability::Bpf, + want: CapsCapability::CAP_BPF, + }, + Testcase { + input: SpecCapability::CheckpointRestore, + want: CapsCapability::CAP_CHECKPOINT_RESTORE, + }, + Testcase { + input: SpecCapability::Chown, + want: Capability::CAP_CHOWN, + }, + Testcase { + input: SpecCapability::DacOverride, + want: CapsCapability::CAP_DAC_OVERRIDE, + }, + Testcase { + input: SpecCapability::DacReadSearch, + want: CapsCapability::CAP_DAC_READ_SEARCH, + }, + Testcase { + input: SpecCapability::Fowner, + want: CapsCapability::CAP_FOWNER, + }, + Testcase { + input: SpecCapability::Fsetid, + want: CapsCapability::CAP_FSETID, + }, + Testcase { + input: SpecCapability::IpcLock, + want: CapsCapability::CAP_IPC_LOCK, + }, + Testcase { + input: SpecCapability::IpcOwner, + want: CapsCapability::CAP_IPC_OWNER, + }, + Testcase { + input: SpecCapability::Kill, + want: CapsCapability::CAP_KILL, + }, + Testcase { + input: SpecCapability::Lease, + want: CapsCapability::CAP_LEASE, + }, + Testcase { + input: SpecCapability::LinuxImmutable, + want: CapsCapability::CAP_LINUX_IMMUTABLE, + }, + Testcase { + input: SpecCapability::MacAdmin, + want: CapsCapability::CAP_MAC_ADMIN, + }, + Testcase { + input: SpecCapability::MacOverride, + want: CapsCapability::CAP_MAC_OVERRIDE, + }, + Testcase { + input: SpecCapability::Mknod, + want: CapsCapability::CAP_MKNOD, + }, + Testcase { + input: SpecCapability::NetAdmin, + want: CapsCapability::CAP_NET_ADMIN, + }, + Testcase { + input: SpecCapability::NetBindService, + want: CapsCapability::CAP_NET_BIND_SERVICE, + }, + Testcase { + input: SpecCapability::NetBroadcast, + want: CapsCapability::CAP_NET_BROADCAST, + }, + Testcase { + input: SpecCapability::NetRaw, + want: CapsCapability::CAP_NET_RAW, + }, + Testcase { + input: SpecCapability::Perfmon, + want: CapsCapability::CAP_PERFMON, + }, + Testcase { + input: SpecCapability::Setgid, + want: CapsCapability::CAP_SETGID, + }, + Testcase { + input: SpecCapability::Setfcap, + want: CapsCapability::CAP_SETFCAP, + }, + Testcase { + input: SpecCapability::Setpcap, + want: CapsCapability::CAP_SETPCAP, + }, + Testcase { + input: SpecCapability::Setuid, + want: CapsCapability::CAP_SETUID, + }, + Testcase { + input: SpecCapability::SysAdmin, + want: CapsCapability::CAP_SYS_ADMIN, + }, + Testcase { + input: SpecCapability::SysBoot, + want: CapsCapability::CAP_SYS_BOOT, + }, + Testcase { + input: SpecCapability::SysChroot, + want: CapsCapability::CAP_SYS_CHROOT, + }, + Testcase { + input: SpecCapability::SysModule, + want: CapsCapability::CAP_SYS_MODULE, + }, + Testcase { + input: SpecCapability::SysNice, + want: CapsCapability::CAP_SYS_NICE, + }, + Testcase { + input: SpecCapability::SysPacct, + want: CapsCapability::CAP_SYS_PACCT, + }, + Testcase { + input: SpecCapability::SysPtrace, + want: CapsCapability::CAP_SYS_PTRACE, + }, + Testcase { + input: SpecCapability::SysRawio, + want: CapsCapability::CAP_SYS_RAWIO, + }, + Testcase { + input: SpecCapability::SysResource, + want: CapsCapability::CAP_SYS_RESOURCE, + }, + Testcase { + input: SpecCapability::SysTime, + want: CapsCapability::CAP_SYS_TIME, + }, + Testcase { + input: SpecCapability::SysTtyConfig, + want: CapsCapability::CAP_SYS_TTY_CONFIG, + }, + Testcase { + input: SpecCapability::Syslog, + want: CapsCapability::CAP_SYSLOG, + }, + Testcase { + input: SpecCapability::WakeAlarm, + want: CapsCapability::CAP_WAKE_ALARM, + }, + ]; + + for test in tests { + let got = test.input.to_cap(); + assert_eq!(got, test.want); + } + } - let cap = chown.to_cap(); - assert_eq!(cap, Capability::CAP_CHOWN); + #[test] + fn test_convert_caps_type_to_oci_spec() { + struct Testcase { + input: CapsCapability, + want: SpecCapability, + } + + let tests = vec![ + Testcase { + input: CapsCapability::CAP_AUDIT_CONTROL, + want: SpecCapability::AuditControl, + }, + Testcase { + input: CapsCapability::CAP_AUDIT_READ, + want: SpecCapability::AuditRead, + }, + Testcase { + input: CapsCapability::CAP_AUDIT_WRITE, + want: SpecCapability::AuditWrite, + }, + Testcase { + input: CapsCapability::CAP_BLOCK_SUSPEND, + want: SpecCapability::BlockSuspend, + }, + Testcase { + input: CapsCapability::CAP_BPF, + want: SpecCapability::Bpf, + }, + Testcase { + input: CapsCapability::CAP_CHECKPOINT_RESTORE, + want: SpecCapability::CheckpointRestore, + }, + Testcase { + input: CapsCapability::CAP_CHOWN, + want: SpecCapability::Chown, + }, + Testcase { + input: CapsCapability::CAP_DAC_OVERRIDE, + want: SpecCapability::DacOverride, + }, + Testcase { + input: CapsCapability::CAP_DAC_READ_SEARCH, + want: SpecCapability::DacReadSearch, + }, + Testcase { + input: CapsCapability::CAP_FOWNER, + want: SpecCapability::Fowner, + }, + Testcase { + input: CapsCapability::CAP_FSETID, + want: SpecCapability::Fsetid, + }, + Testcase { + input: CapsCapability::CAP_IPC_LOCK, + want: SpecCapability::IpcLock, + }, + Testcase { + input: CapsCapability::CAP_IPC_OWNER, + want: SpecCapability::IpcOwner, + }, + Testcase { + input: CapsCapability::CAP_KILL, + want: SpecCapability::Kill, + }, + Testcase { + input: CapsCapability::CAP_LEASE, + want: SpecCapability::Lease, + }, + Testcase { + input: CapsCapability::CAP_LINUX_IMMUTABLE, + want: SpecCapability::LinuxImmutable, + }, + Testcase { + input: CapsCapability::CAP_MAC_ADMIN, + want: SpecCapability::MacAdmin, + }, + Testcase { + input: CapsCapability::CAP_MAC_OVERRIDE, + want: SpecCapability::MacOverride, + }, + Testcase { + input: CapsCapability::CAP_MKNOD, + want: SpecCapability::Mknod, + }, + Testcase { + input: CapsCapability::CAP_NET_ADMIN, + want: SpecCapability::NetAdmin, + }, + Testcase { + input: CapsCapability::CAP_NET_BIND_SERVICE, + want: SpecCapability::NetBindService, + }, + Testcase { + input: CapsCapability::CAP_NET_BROADCAST, + want: SpecCapability::NetBroadcast, + }, + Testcase { + input: CapsCapability::CAP_NET_RAW, + want: SpecCapability::NetRaw, + }, + Testcase { + input: CapsCapability::CAP_PERFMON, + want: SpecCapability::Perfmon, + }, + Testcase { + input: CapsCapability::CAP_SETGID, + want: SpecCapability::Setgid, + }, + Testcase { + input: CapsCapability::CAP_SETFCAP, + want: SpecCapability::Setfcap, + }, + Testcase { + input: CapsCapability::CAP_SETPCAP, + want: SpecCapability::Setpcap, + }, + Testcase { + input: CapsCapability::CAP_SETUID, + want: SpecCapability::Setuid, + }, + Testcase { + input: CapsCapability::CAP_SYS_ADMIN, + want: SpecCapability::SysAdmin, + }, + Testcase { + input: CapsCapability::CAP_SYS_BOOT, + want: SpecCapability::SysBoot, + }, + Testcase { + input: CapsCapability::CAP_SYS_CHROOT, + want: SpecCapability::SysChroot, + }, + Testcase { + input: CapsCapability::CAP_SYS_MODULE, + want: SpecCapability::SysModule, + }, + Testcase { + input: CapsCapability::CAP_SYS_NICE, + want: SpecCapability::SysNice, + }, + Testcase { + input: CapsCapability::CAP_SYS_PACCT, + want: SpecCapability::SysPacct, + }, + Testcase { + input: CapsCapability::CAP_SYS_PTRACE, + want: SpecCapability::SysPtrace, + }, + Testcase { + input: CapsCapability::CAP_SYS_RAWIO, + want: SpecCapability::SysRawio, + }, + Testcase { + input: CapsCapability::CAP_SYS_RESOURCE, + want: SpecCapability::SysResource, + }, + Testcase { + input: CapsCapability::CAP_SYS_TIME, + want: SpecCapability::SysTime, + }, + Testcase { + input: CapsCapability::CAP_SYS_TTY_CONFIG, + want: SpecCapability::SysTtyConfig, + }, + Testcase { + input: CapsCapability::CAP_SYSLOG, + want: SpecCapability::Syslog, + }, + Testcase { + input: CapsCapability::CAP_WAKE_ALARM, + want: SpecCapability::WakeAlarm, + }, + ]; + + for test in tests { + let got = SpecCapability::from_cap(test.input); + assert_eq!(got, test.want); + } + } + + #[test] + fn test_drop_privileges() { + struct Testcase { + name: String, + input: LinuxCapabilities, + // be awared of that calling sequence in the drop_privileges function + // will affect the output sequence from test_command.get_set_capability_args() + want: Vec<(CapSet, Vec)>, + } + + let cps = vec![ + SpecCapability::AuditWrite, + SpecCapability::Kill, + SpecCapability::NetBindService, + ]; + + let tests = vec![ + Testcase { + name: format!("all LinuxCapabilities fields with caps: {:?}", cps), + input: LinuxCapabilities { + bounding: cps.clone().into_iter().collect::().into(), + effective: cps.clone().into_iter().collect::().into(), + inheritable: cps.clone().into_iter().collect::().into(), + permitted: cps.clone().into_iter().collect::().into(), + ambient: cps.clone().into_iter().collect::().into(), + }, + want: vec![ + (CapSet::Bounding, cps.clone()), + (CapSet::Effective, cps.clone()), + (CapSet::Permitted, cps.clone()), + (CapSet::Inheritable, cps.clone()), + (CapSet::Ambient, cps.clone()), + ], + }, + Testcase { + name: format!("partial LinuxCapabilities fields with caps: {:?}", cps), + input: LinuxCapabilities { + bounding: cps.clone().into_iter().collect::().into(), + effective: cps.clone().into_iter().collect::().into(), + inheritable: None, + permitted: cps.clone().into_iter().collect::().into(), + ambient: None, + }, + want: vec![ + (CapSet::Bounding, cps.clone()), + (CapSet::Effective, cps.clone()), + (CapSet::Permitted, cps.clone()), + ], + }, + Testcase { + name: format!("empty LinuxCapabilities fields with caps: {:?}", cps), + input: LinuxCapabilities { + bounding: None, + effective: None, + inheritable: None, + permitted: None, + ambient: None, + }, + want: vec![], + }, + ]; + + for test in tests { + let test_command = TestHelperSyscall::default(); + assert!( + drop_privileges(&test.input, &test_command).is_ok(), + "{}, drop_privileges is not ok", + test.name + ); + + let got: Vec<(CapSet, Vec<_>)> = test_command + .get_set_capability_args() + .into_iter() + .map(|(capset, caps)| { + ( + capset, + caps.into_iter().map(SpecCapability::from_cap).collect(), + ) + }) + .collect(); + assert_eq!( + got.len(), + test.want.len(), + "{}, len of got:{}, want:{}", + test.name, + got.len(), + test.want.len(), + ); + + for (i, want) in test.want.iter().enumerate().take(test.want.len()) { + // because CapSet has no Eq, PartialEq attributes, + // so using String to do the comparsion. + let want_cap_set = format!("{:?}", want.0); + let got_cap_set = format!("{:?}", got[i].0); + let want_caps = &want.1; + let got_caps = &got[i].1; + + assert_eq!( + got_cap_set, want_cap_set, + "{}, capset of got:{}, want:{}", + test.name, got_cap_set, want_cap_set, + ); + // because get_set_capability_args returns a HasSet of capabilities, + // so the ordering is randomized. + assert!( + got_caps.iter().all(|cap| want_caps.contains(cap)), + "{}, caps of got:{:?}, want:{:?}", + test.name, + got_caps, + want_caps + ); + } + } } }