also set dumpable to 0, minor improvements

This commit is contained in:
Albert S. 2019-08-22 13:08:50 +02:00
parent f445ce7b1f
commit bb8de3b6c7
2 changed files with 32 additions and 49 deletions

2
Cargo.lock generated
View File

@ -1,3 +1,5 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.43" version = "0.2.43"

View File

@ -1,10 +1,10 @@
use std::env::Args; use std::env::Args;
use std::io::{Error, ErrorKind};
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::ffi::CString;
use std::ffi::CStr; use std::ffi::CStr;
use std::ffi::CString;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::io::{Error, ErrorKind};
extern crate libc; extern crate libc;
use libc::passwd; use libc::passwd;
@ -35,7 +35,6 @@ impl Entry {
} }
} }
struct Passwd { struct Passwd {
pw_name: String, pw_name: String,
pw_passwd: String, pw_passwd: String,
@ -46,15 +45,11 @@ struct Passwd {
pw_shell: String, pw_shell: String,
} }
fn initgroups(user: &str, group: libc::gid_t) -> std::io::Result<()> { fn initgroups(user: &str, group: libc::gid_t) -> std::io::Result<()> {
let userarg = CString::new(user); let userarg = CString::new(user);
return errnowrapper(unsafe { return errnowrapper(unsafe { libc::initgroups(userarg.unwrap().as_ptr(), group) });
libc::initgroups(userarg.unwrap().as_ptr(), group)
});
} }
fn errnowrapper(ret: libc::c_int) -> std::io::Result<()> { fn errnowrapper(ret: libc::c_int) -> std::io::Result<()> {
if ret != 0 { if ret != 0 {
return Err(Error::last_os_error()); return Err(Error::last_os_error());
@ -95,7 +90,6 @@ fn getpwnam(username: &str) -> std::io::Result<Passwd> {
pw_shell: getstr((*pwnamresult).pw_shell), pw_shell: getstr((*pwnamresult).pw_shell),
}) })
} }
} }
fn ensure_allowed(userid: libc::uid_t, entry: &Entry) -> std::io::Result<()> { fn ensure_allowed(userid: libc::uid_t, entry: &Entry) -> std::io::Result<()> {
@ -119,7 +113,6 @@ fn ensure_allowed(userid: libc::uid_t, entry: &Entry) -> std::io::Result<()> {
)); ));
} }
fn usage() { fn usage() {
println!("Usage: raou ENRTYNAME"); println!("Usage: raou ENRTYNAME");
} }
@ -141,13 +134,12 @@ fn assign(entry: &mut Entry, key: &str, value: &str) {
"env_vars" => add_multi(&mut entry.inherit_envs, val), "env_vars" => add_multi(&mut entry.inherit_envs, val),
"argv0" => entry.argv0 = val, "argv0" => entry.argv0 = val,
"target_user" => entry.dest_user = val, "target_user" => entry.dest_user = val,
"allow_args" => entry.arbitrary_args = (val == "1" || val == "true"), "allow_args" => entry.arbitrary_args = val == "1" || val == "true",
"args" => entry.args = val, "args" => entry.args = val,
"no_new_privs" => entry.no_new_privs = (val == "1" || val == "true"), "no_new_privs" => entry.no_new_privs = val == "1" || val == "true",
_ => { _ => {
eprintln!("Ignoring invalid key {}", key); eprintln!("Ignoring invalid key {}", key);
} }
} }
} }
fn assign_from_line(entry: &mut Entry, line: &str) { fn assign_from_line(entry: &mut Entry, line: &str) {
@ -159,7 +151,6 @@ fn assign_from_line(entry: &mut Entry, line: &str) {
return; return;
} }
assign(entry, key.unwrap(), value.unwrap()) assign(entry, key.unwrap(), value.unwrap())
} }
fn create_entry_from_file(filepath: &str) -> std::io::Result<Entry> { fn create_entry_from_file(filepath: &str) -> std::io::Result<Entry> {
let mut entry: Entry = Entry::new(); let mut entry: Entry = Entry::new();
@ -179,7 +170,8 @@ fn clearenv() -> std::io::Result<()> {
} }
//TODO: AsRef for envs? //TODO: AsRef for envs?
fn setup_environment(passwd: &Passwd, envs: &[String]) -> std::io::Result<()> { fn setup_environment(passwd: &Passwd, envs: &[String]) -> std::io::Result<()> {
let saved_envs: Vec<String> = envs.iter() let saved_envs: Vec<String> = envs
.iter()
.map(|s| std::env::var(s).expect("No such var")) .map(|s| std::env::var(s).expect("No such var"))
.collect(); .collect();
clearenv()?; clearenv()?;
@ -194,7 +186,6 @@ fn setup_environment(passwd: &Passwd, envs: &[String]) -> std::io::Result<()> {
std::env::set_var(&envs[i], item); std::env::set_var(&envs[i], item);
} }
Ok(()) Ok(())
} }
fn become_user(passwd: &Passwd) -> std::io::Result<()> { fn become_user(passwd: &Passwd) -> std::io::Result<()> {
@ -204,13 +195,12 @@ fn become_user(passwd: &Passwd) -> std::io::Result<()> {
std::env::set_current_dir(&passwd.pw_dir)?; std::env::set_current_dir(&passwd.pw_dir)?;
Ok(()) Ok(())
} }
fn init_sandbox(entry: &Entry) -> std::io::Result<()> {
if (entry.no_new_privs) {
errnowrapper(unsafe {
libc::prctl(libc::PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)
})?;
}
fn drop_privs(entry: &Entry) -> std::io::Result<()> {
if entry.no_new_privs {
errnowrapper(unsafe { libc::prctl(libc::PR_SET_DUMPABLE, 0) })?;
errnowrapper(unsafe { libc::prctl(libc::PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) })?;
}
Ok(()) Ok(())
} }
@ -220,8 +210,6 @@ fn to_cstring<T: AsRef<str>>(s: T) -> *const libc::c_char {
} }
fn create_execv_args(entry: &Entry, cmdargs: &Vec<String>) -> Vec<*const libc::c_char> { fn create_execv_args(entry: &Entry, cmdargs: &Vec<String>) -> Vec<*const libc::c_char> {
let mut args: Vec<*const libc::c_char>; let mut args: Vec<*const libc::c_char>;
if entry.arbitrary_args && cmdargs.len() > 2 { if entry.arbitrary_args && cmdargs.len() > 2 {
args = cmdargs.iter().skip(2).map(to_cstring).collect(); args = cmdargs.iter().skip(2).map(to_cstring).collect();
@ -256,11 +244,8 @@ fn exec(entryname: &str, cmdargs: &Vec<String>) -> std::io::Result<()> {
let destuserpasswd: Passwd = getpwnam(&entry.dest_user)?; let destuserpasswd: Passwd = getpwnam(&entry.dest_user)?;
let currentuser: u32 = geteuid(); let currentuser: u32 = geteuid();
let args = create_execv_args(&entry, &cmdargs); let args = create_execv_args(&entry, &cmdargs);
ensure_allowed(currentuser, &entry)?; ensure_allowed(currentuser, &entry)?;
become_user(&destuserpasswd).or_else(|e| { become_user(&destuserpasswd).or_else(|e| {
return Err(Error::new( return Err(Error::new(
@ -268,39 +253,35 @@ fn exec(entryname: &str, cmdargs: &Vec<String>) -> std::io::Result<()> {
"Failed to switch user: ".to_owned() + &e.to_string(), "Failed to switch user: ".to_owned() + &e.to_string(),
)); ));
})?; })?;
setup_environment(&destuserpasswd, &entry.inherit_envs) setup_environment(&destuserpasswd, &entry.inherit_envs).or_else(|e| {
.or_else(|e| {
return Err(Error::new(
ErrorKind::Other,
"Environment setup failure: ".to_owned() + &e.to_string(),
));
})?;
init_sandbox(&entry).or_else(|e| {
return Err(Error::new( return Err(Error::new(
ErrorKind::Other, ErrorKind::Other,
"Sandbox init failure: ".to_owned() + &e.to_string(), "Environment setup failure: ".to_owned() + &e.to_string(),
));
})?;
drop_privs(&entry).or_else(|e| {
return Err(Error::new(
ErrorKind::Other,
"Failed to drop priviliges: ".to_owned() + &e.to_string(),
)); ));
})?; })?;
unsafe { unsafe {
errnowrapper(libc::execv(to_cstring(entry.cmd), args.as_ptr())) errnowrapper(libc::execv(to_cstring(entry.cmd), args.as_ptr())).or_else(|e| {
.or_else(|e| { return Err(Error::new(
return Err(Error::new( ErrorKind::Other,
ErrorKind::Other, "execv failed: ".to_owned() + &e.to_string(),
"execv failed: ".to_owned() + &e.to_string(), ));
)); })?;
})?;
} }
std::process::exit(0); std::process::exit(0);
Ok(())
} }
fn main() -> Result<(), std::io::Error> { fn main() -> Result<(), std::io::Error> {
let argv: Args = std::env::args(); let argv: Args = std::env::args();
let cmdargs: Vec<String> = argv.collect(); let cmdargs: Vec<String> = argv.collect();
let entryname = cmdargs.get(1); let entryname = cmdargs.get(1);
if entryname.is_some() { if entryname.is_some() {
match exec(&entryname.unwrap(), &cmdargs) { match exec(&entryname.unwrap(), &cmdargs) {
Err(e) => { Err(e) => {
eprintln!("The following error ocurred:"); eprintln!("The following error ocurred:");