diff --git a/test/scripts/ssh-setup.sh b/test/scripts/ssh-setup.sh index 714756f45e46..906312208a8a 100644 --- a/test/scripts/ssh-setup.sh +++ b/test/scripts/ssh-setup.sh @@ -21,6 +21,9 @@ for file in test-runner connection-checker $APP_PACKAGE $PREVIOUS_APP $UI_RUNNER cp -f "$SCRIPT_DIR/$file" "$RUNNER_DIR" done +# Unprivileged users need execute rights for connection checker +chmod 551 "${RUNNER_DIR}/connection-checker" + chown -R root "$RUNNER_DIR/" # Create service @@ -69,11 +72,18 @@ function setup_macos { EOF + create_test_user_macos + echo "Starting test runner service" launchctl load -w $RUNNER_PLIST_PATH } +function create_test_user_macos { + echo "Adding test user account" + sysadminctl -addUser mole -fullName "Mole Molesson" -password mole +} + function setup_systemd { RUNNER_SERVICE_PATH="/etc/systemd/system/testrunner.service" @@ -94,10 +104,18 @@ EOF semanage fcontext -a -t bin_t "$RUNNER_DIR/.*" &> /dev/null || true + create_test_user_linux + systemctl enable testrunner.service systemctl start testrunner.service } +function create_test_user_linux { + echo "Adding test user account" + useradd -m mole + echo "mole" | passwd mole --stdin +} + if [[ "$(uname -s)" == "Darwin" ]]; then setup_macos exit 0 diff --git a/test/test-runner/Cargo.toml b/test/test-runner/Cargo.toml index b16a8c23b2b3..7206cb394a8d 100644 --- a/test/test-runner/Cargo.toml +++ b/test/test-runner/Cargo.toml @@ -58,7 +58,7 @@ features = ["codec"] default-features = false [target.'cfg(unix)'.dependencies] -nix = { workspace = true } +nix = { workspace = true, features = ["user"] } [target.'cfg(target_os = "linux")'.dependencies] rs-release = "0.1.7" diff --git a/test/test-runner/src/main.rs b/test/test-runner/src/main.rs index 59fc83672d77..ea16adf64031 100644 --- a/test/test-runner/src/main.rs +++ b/test/test-runner/src/main.rs @@ -386,11 +386,18 @@ impl Service for TestServer { } cmd.stderr(Stdio::piped()); + cmd.kill_on_drop(true); - let mut child = cmd.kill_on_drop(true).spawn().map_err(|error| { - log::error!("Failed to spawn {}: {error}", opts.path); - test_rpc::Error::Syscall - })?; + // TODO: do not hardcode + let mut child = util::as_unprivileged("mole", || cmd.spawn()) + .map_err(|error| { + log::error!("Failed to drop privileges: {error}"); + test_rpc::Error::Syscall + })? + .map_err(|error| { + log::error!("Failed to spawn {}: {error}", opts.path); + test_rpc::Error::Syscall + })?; let pid = child .id() diff --git a/test/test-runner/src/util.rs b/test/test-runner/src/util.rs index 03a334321412..030e945cc4a1 100644 --- a/test/test-runner/src/util.rs +++ b/test/test-runner/src/util.rs @@ -21,3 +21,52 @@ impl OnDrop { } } } + +#[cfg(target_os = "windows")] +pub fn as_unprivileged( + unpriv_user: &str, + func: impl FnOnce() -> T, +) -> Result { + // NOTE: no-op + let _ = unpriv_user; + Ok(func()) +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Failed to get the specified user")] + GetUser(#[source] nix::Error), + #[error("The specified user was not found")] + MissingUser, +} + +#[cfg(unix)] +pub fn as_unprivileged( + unpriv_user: &str, + func: impl FnOnce() -> T, +) -> Result { + let original_uid = nix::unistd::getuid(); + let original_gid = nix::unistd::getgid(); + + let user = nix::unistd::User::from_name(unpriv_user).map_err(Error::GetUser)?.ok_or(Error::MissingUser)?; + let uid = user.uid; + let gid = user.gid; + + if let Err(error) = nix::unistd::setegid(gid) { + log::error!("Failed to set gid: {error}"); + } + if let Err(error) = nix::unistd::seteuid(uid) { + log::error!("Failed to set uid: {error}"); + } + + let func_result = func(); + + if let Err(error) = nix::unistd::seteuid(original_uid) { + log::error!("Failed to restore uid: {error}"); + } + if let Err(error) = nix::unistd::setegid(original_gid) { + log::error!("Failed to restore gid: {error}"); + } + + Ok(func_result) +}