Skip to content

Commit

Permalink
Drop privileges after loading certificates
Browse files Browse the repository at this point in the history
Related-to: TOR-3521

Signed-off-by: Leonardo Held <[email protected]>
  • Loading branch information
leonheldattoradex committed Aug 21, 2024
1 parent 4b322eb commit 590e31d
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ tokio = { version = "1.38.0", features = ["sync", "rt", "signal", "rt-multi-thre
webpki-roots = "0.26.3"
x509-parser = "0.16.0"
zbus = "4.3.1"
nix = "0.29.0"

[dev-dependencies]
tempfile = "3.4"
Expand Down
5 changes: 5 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ async fn run() -> Result<()> {
(device_id, Some(client_config))
};

if let Err(e) = utils::drop_privileges() {
eprintln!("Failed to drop privileges: {}", e);
std::process::exit(1);
}

info!("connecting to {device_id}@{mqtt_hostname}:{mqtt_port}");

let mut mqttoptions = rumqttc::MqttOptions::new(
Expand Down
34 changes: 34 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use nix::unistd::{self, Uid, Gid};
use std::ffi::CString;
use log::info;
use rustls_pemfile;
use eyre::{Context, Result, OptionExt};
use x509_parser::prelude::*;
Expand Down Expand Up @@ -83,3 +86,34 @@ pub fn parse_payload(payload: &[u8]) -> Result<(String, serde_json::Value)> {

Ok((command, args_json))
}

pub fn drop_privileges() -> Result<()> {
if !Uid::current().is_root() {
info!("No need to drop privileges, current user is not root");
return Ok(());
}

let user = "1000";
let group = "1000";

let ugroup = unistd::Group::from_gid(Gid::from_raw(1000))?
.ok_or(eyre::eyre!("Could not get group {group}"))?;
let uuser = unistd::User::from_uid(Uid::from_raw(1000))?
.ok_or(eyre::eyre!("Could not get user {user}"))?;

let user_name_cstring = CString::new(user)?;

unistd::initgroups(&user_name_cstring, ugroup.gid)?;

unistd::setgid(ugroup.gid)?;

unistd::setuid(uuser.uid)?;

if unistd::setuid(Uid::from_raw(0)).is_ok() {
eyre::bail!("Could not drop privileges, can still change back to uid 0");
}

info!("Dropped privileges to {user}:{group}");

Ok(())
}
31 changes: 30 additions & 1 deletion src/utils/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
#[cfg(test)]
mod tests {
use std::path::Path;
use crate::utils::{load_cert, load_private_key, read_device_id, parse_payload};
use nix::unistd::Uid;
use crate::utils::{load_cert, load_private_key, read_device_id, parse_payload, drop_privileges};


#[test]
Expand Down Expand Up @@ -60,4 +61,32 @@ mod tests {
let result = parse_payload(payload);
assert!(result.is_err(), "Expected error for missing `command`, got: {:?}", result);
}

#[test]
fn test_drop_privileges_non_root() {
// This test should only be run as a non-root user
if nix::unistd::getuid().is_root() {
panic!("This test should not be run as root");
}

let result = drop_privileges();
assert!(result.is_ok(), "Expected Ok(()), got {:?}", result);
}

#[test]
fn test_drop_privileges_root_user_simulation() {
// Simulate root user environment by temporarily setting nix::unistd::setuid to return root
let original_uid = nix::unistd::getuid();
let root_uid = Uid::from_raw(0);
let _ = nix::unistd::setuid(root_uid);

let result = drop_privileges();

let _ = nix::unistd::setuid(original_uid);

match original_uid.is_root() {
true => assert!(result.is_err(), "Expected an error, got {:?}", result),
false => assert!(result.is_ok(), "Expected Ok(()), got {:?}", result),
}
}
}

0 comments on commit 590e31d

Please sign in to comment.