1
0
mirror of https://github.com/containers/youki synced 2024-11-22 17:02:00 +01:00

Add e2e test for process user (#2978)

* add-test-process-user

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* fix format

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* fix error

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* fix err and format

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* fix err to use UserBuilder

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* fix format err

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* remove unnecessary return

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* rename module name

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* fix unsafe code to use nix

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* fix err to use nix

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* fix format err

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* update fn validate_additional_gids to check group ids length

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* set additional_gids to random number

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* set umask value to variables

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* fix format err

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* change random number range

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* change err msg to use bail

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>

* nit: update error message in case of test failure

Signed-off-by: Yashodhan Joshi <yjdoc2@gmail.com>

* fix: make sure random gid values are unique

Signed-off-by: Yashodhan Joshi <yjdoc2@gmail.com>

---------

Signed-off-by: sat0ken <15720506+sat0ken@users.noreply.github.com>
Signed-off-by: Yashodhan Joshi <yjdoc2@gmail.com>
Co-authored-by: Yashodhan Joshi <yjdoc2@gmail.com>
This commit is contained in:
sat0ken 2024-11-14 23:10:11 +09:00 committed by GitHub
parent 87befd9386
commit d5d5fadf99
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 124 additions and 1 deletions

@ -22,6 +22,7 @@ use crate::tests::mounts_recursive::get_mounts_recursive_test;
use crate::tests::no_pivot::get_no_pivot_test; use crate::tests::no_pivot::get_no_pivot_test;
use crate::tests::pidfile::get_pidfile_test; use crate::tests::pidfile::get_pidfile_test;
use crate::tests::process_rlimits::get_process_rlimits_test; use crate::tests::process_rlimits::get_process_rlimits_test;
use crate::tests::process_user::get_process_user_test;
use crate::tests::readonly_paths::get_ro_paths_test; use crate::tests::readonly_paths::get_ro_paths_test;
use crate::tests::scheduler::get_scheduler_test; use crate::tests::scheduler::get_scheduler_test;
use crate::tests::seccomp::get_seccomp_test; use crate::tests::seccomp::get_seccomp_test;
@ -115,6 +116,7 @@ fn main() -> Result<()> {
let scheduler = get_scheduler_test(); let scheduler = get_scheduler_test();
let io_priority_test = get_io_priority_test(); let io_priority_test = get_io_priority_test();
let devices = get_devices_test(); let devices = get_devices_test();
let process_user = get_process_user_test();
let process_rlimtis = get_process_rlimits_test(); let process_rlimtis = get_process_rlimits_test();
let no_pivot = get_no_pivot_test(); let no_pivot = get_no_pivot_test();
@ -140,6 +142,7 @@ fn main() -> Result<()> {
tm.add_test_group(Box::new(sysctl)); tm.add_test_group(Box::new(sysctl));
tm.add_test_group(Box::new(scheduler)); tm.add_test_group(Box::new(scheduler));
tm.add_test_group(Box::new(devices)); tm.add_test_group(Box::new(devices));
tm.add_test_group(Box::new(process_user));
tm.add_test_group(Box::new(process_rlimtis)); tm.add_test_group(Box::new(process_rlimtis));
tm.add_test_group(Box::new(no_pivot)); tm.add_test_group(Box::new(no_pivot));

@ -12,6 +12,7 @@ pub mod mounts_recursive;
pub mod no_pivot; pub mod no_pivot;
pub mod pidfile; pub mod pidfile;
pub mod process_rlimits; pub mod process_rlimits;
pub mod process_user;
pub mod readonly_paths; pub mod readonly_paths;
pub mod scheduler; pub mod scheduler;
pub mod seccomp; pub mod seccomp;

@ -0,0 +1,2 @@
mod process_user_test;
pub use process_user_test::get_process_user_test;

@ -0,0 +1,56 @@
use anyhow::{Context, Ok, Result};
use oci_spec::runtime::{ProcessBuilder, Spec, SpecBuilder, UserBuilder};
use rand::Rng;
use test_framework::{test_result, Test, TestGroup, TestResult};
use crate::utils::test_inside_container;
// Generates a Vec<u32> with a random number of elements (between 5 and 15),
// where each element is a random u32 value between 0 and 65535.
fn generate_unique_random_vec() -> Vec<u32> {
let mut rng = rand::thread_rng();
let vec_size = rng.gen_range(5..=10);
let mut ret = Vec::new();
while ret.len() < vec_size {
let rand = rng.gen_range(100..=200);
if !ret.contains(&rand) {
ret.push(rand);
}
}
ret
}
fn create_spec() -> Result<Spec> {
let umask = 0o002;
let user = UserBuilder::default()
.uid(10u32)
.gid(10u32)
.additional_gids(generate_unique_random_vec())
.umask(umask as u32)
.build()?;
let spec = SpecBuilder::default()
.process(
ProcessBuilder::default()
.args(vec!["runtimetest".to_string(), "process_user".to_string()])
.user(user)
.build()
.expect("error in creating process config"),
)
.build()
.context("failed to build spec")?;
Ok(spec)
}
fn process_user_test() -> TestResult {
let spec = test_result!(create_spec());
test_inside_container(spec, &|_| Ok(()))
}
pub fn get_process_user_test() -> TestGroup {
let mut process_user_test_group = TestGroup::new("process_user");
let test = Test::new("process_user_test", Box::new(process_user_test));
process_user_test_group.add(vec![Box::new(test)]);
process_user_test_group
}

@ -44,6 +44,7 @@ fn main() {
"io_priority_class_be" => tests::test_io_priority_class(&spec, IoprioClassBe), "io_priority_class_be" => tests::test_io_priority_class(&spec, IoprioClassBe),
"io_priority_class_idle" => tests::test_io_priority_class(&spec, IoprioClassIdle), "io_priority_class_idle" => tests::test_io_priority_class(&spec, IoprioClassIdle),
"devices" => tests::validate_devices(&spec), "devices" => tests::validate_devices(&spec),
"process_user" => tests::validate_process_user(&spec),
"process_rlimits" => tests::validate_process_rlimits(&spec), "process_rlimits" => tests::validate_process_rlimits(&spec),
"no_pivot" => tests::validate_rootfs(), "no_pivot" => tests::validate_rootfs(),
_ => eprintln!("error due to unexpected execute test name: {execute_test}"), _ => eprintln!("error due to unexpected execute test name: {execute_test}"),

@ -7,8 +7,9 @@ use anyhow::{bail, Result};
use nix::errno::Errno; use nix::errno::Errno;
use nix::libc; use nix::libc;
use nix::sys::resource::{getrlimit, Resource}; use nix::sys::resource::{getrlimit, Resource};
use nix::sys::stat::{umask, Mode};
use nix::sys::utsname; use nix::sys::utsname;
use nix::unistd::getcwd; use nix::unistd::{getcwd, getgid, getgroups, getuid, Gid, Uid};
use oci_spec::runtime::IOPriorityClass::{self, IoprioClassBe, IoprioClassIdle, IoprioClassRt}; use oci_spec::runtime::IOPriorityClass::{self, IoprioClassBe, IoprioClassIdle, IoprioClassRt};
use oci_spec::runtime::{ use oci_spec::runtime::{
LinuxDevice, LinuxDeviceType, LinuxSchedulerPolicy, PosixRlimit, PosixRlimitType, Spec, LinuxDevice, LinuxDeviceType, LinuxSchedulerPolicy, PosixRlimit, PosixRlimitType, Spec,
@ -549,6 +550,65 @@ pub fn test_io_priority_class(spec: &Spec, io_priority_class: IOPriorityClass) {
} }
} }
pub fn validate_process_user(spec: &Spec) {
let process = spec.process().as_ref().unwrap();
let expected_uid = Uid::from(process.user().uid());
let expected_gid = Gid::from(process.user().gid());
let expected_umask = Mode::from_bits(process.user().umask().unwrap()).unwrap();
let uid = getuid();
let gid = getgid();
// The umask function not only gets the current mask, but also has the ability to set a new mask,
// so we need to set it back after getting the latest value.
let current_umask = umask(nix::sys::stat::Mode::empty());
umask(current_umask);
if expected_uid != uid {
eprintln!("error due to uid want {}, got {}", expected_uid, uid)
}
if expected_gid != gid {
eprintln!("error due to gid want {}, got {}", expected_gid, gid)
}
if let Err(e) = validate_additional_gids(process.user().additional_gids().as_ref().unwrap()) {
eprintln!("error additional gids {e}");
}
if expected_umask != current_umask {
eprintln!(
"error due to umask want {:?}, got {:?}",
expected_umask, current_umask
)
}
}
// validate_additional_gids function is used to validate additional groups of user
fn validate_additional_gids(expected_gids: &Vec<u32>) -> Result<()> {
let current_gids = getgroups().unwrap();
if expected_gids.len() != current_gids.len() {
bail!(
"error : additional group mismatch, want {:?}, got {:?}",
expected_gids,
current_gids
);
}
for gid in expected_gids {
if !current_gids.contains(&Gid::from_raw(*gid)) {
bail!(
"error : additional gid {} is not in current groups, expected {:?}, got {:?}",
gid,
expected_gids,
current_gids
);
}
}
Ok(())
}
pub fn validate_process_rlimits(spec: &Spec) { pub fn validate_process_rlimits(spec: &Spec) {
let process = spec.process().as_ref().unwrap(); let process = spec.process().as_ref().unwrap();
let spec_rlimits: &Vec<PosixRlimit> = process.rlimits().as_ref().unwrap(); let spec_rlimits: &Vec<PosixRlimit> = process.rlimits().as_ref().unwrap();