--disable-sandbox for disabling libalpm sandbox

- Ability to instruct libalpm to disable its own sandboxing mechanism by
  engaging `--disable-sandbox` at the command line.
- Updated manuals to reflect new command-line options.
- Disable sandbox user when disabling libalpm's sandbox
This commit is contained in:
Xavier Moffett 2024-09-14 21:05:40 -04:00
parent 2819f5d216
commit e4b8a85ccd
Signed by: Sapphirus
GPG key ID: A6C061B2CEA1A7AC
8 changed files with 73 additions and 34 deletions

View file

@ -19,6 +19,7 @@
use std::{
fmt::{Display, Formatter, Result as FmtResult},
io::ErrorKind as IOErrorKind,
os::{fd::AsRawFd, unix::process::ExitStatusExt},
process::{Child, Command, ExitStatus, Stdio},
};
@ -70,7 +71,7 @@ lazy_static! {
#[derive(Debug, Clone)]
pub enum ExecutionError {
InvalidPathVar(String, std::io::ErrorKind),
InvalidPathVar(String, IOErrorKind),
ExecutableUnavailable(String),
RuntimeArguments,
UnabsolutePath(String),
@ -116,9 +117,9 @@ pub enum ExecutionType {
#[rustfmt::skip]
pub fn fakeroot_container(exec_type: ExecutionType, trap: Option<fn(i32)>, ins: &ContainerHandle, arguments: Vec<&str>) -> Result<()> {
let term_control = TermControl::new(0);
let info_pipe = os_pipe::pipe().unwrap();
let sec_pipe = os_pipe::pipe().unwrap();
let sec_fd = provide_bpf_program(vec![Standard, Namespaces], &sec_pipe.0, sec_pipe.1).unwrap();
let info_pipe = os_pipe::pipe().expect("bwrap pipe");
let sec_pipe = os_pipe::pipe().expect("eBPF pipe");
let sec_fd = provide_bpf_program(vec![Standard, Namespaces], &sec_pipe.0, sec_pipe.1).expect("eBPF program");
let info_fd = info_pipe.1.as_raw_fd();
let fd_mappings = vec![
FdMapping {
@ -198,10 +199,10 @@ pub fn fakeroot_container(exec_type: ExecutionType, trap: Option<fn(i32)>, ins:
#[rustfmt::skip]
pub fn transaction_agent(ins: &ContainerHandle, params: TransactionParameters, metadata: &TransactionMetadata) -> Result<Child> {
let params_pipe = os_pipe::pipe().unwrap();
let params_pipe = os_pipe::pipe().expect("params pipe");
let params_fd = agent_params(&params_pipe.0, &params_pipe.1, &params, metadata)?;
let sec_pipe = os_pipe::pipe().unwrap();
let sec_fd = provide_bpf_program(vec![Standard, Namespaces], &sec_pipe.0, sec_pipe.1).unwrap();
let sec_pipe = os_pipe::pipe().expect("eBPF pipe");
let sec_fd = provide_bpf_program(vec![Standard, Namespaces], &sec_pipe.0, sec_pipe.1).expect("eBPF program");
let fd_mappings = vec![
FdMapping {
parent_fd: sec_fd,

View file

@ -196,23 +196,27 @@ fn alpm_log_callback(level: LogLevel, msg: &str, counter: &mut usize) {
}
pub fn instantiate_alpm_agent(config: &Global, remotes: &AlpmConfigData, transflags: &TransactionFlags) -> Alpm {
let mut handle = Alpm::new("/mnt/fs", "/mnt/fs/var/lib/pacman/").unwrap();
let mut handle = Alpm::new("/mnt/fs", "/mnt/fs/var/lib/pacman/").expect("Unable to acquire ALPM handle");
let hook_dirs = vec!["/mnt/fs/usr/share/libalpm/hooks/", "/mnt/fs/etc/pacman.d/hooks/"];
let debug = transflags.intersects(TransactionFlags::DEBUG);
let disable_sandbox = config.alpm().disable_sandbox() || transflags.intersects(TransactionFlags::NO_ALPM_SANDBOX);
if debug {
handle.set_log_cb(*UNIX_TIMESTAMP as usize, alpm_log_callback);
}
handle.set_disable_sandbox(config.alpm().disable_sandbox());
handle.set_logfile("/mnt/share/pacwrap.log").unwrap();
handle.set_hookdirs(hook_dirs.iter()).unwrap();
handle.set_cachedirs(vec!["/mnt/share/cache"].iter()).unwrap();
handle.set_gpgdir("/mnt/share/gnupg").unwrap();
handle.set_logfile("/mnt/share/pacwrap.log").unwrap();
handle.set_check_space(false);
handle.set_disable_dl_timeout(config.alpm().download_timeout());
if disable_sandbox {
handle.set_disable_sandbox(true);
handle.set_sandbox_user(None::<&str>).expect("set sandbox user");
}
handle.set_logfile("/mnt/share/pacwrap.log").expect("set logfile");
handle.set_hookdirs(hook_dirs.iter()).expect("set hookdirs");
handle.set_gpgdir("/mnt/share/gnupg").expect("set gpgdir");
handle.set_cachedirs(vec!["/mnt/share/cache"].iter()).expect("set cachedirs");
handle.set_parallel_downloads(config.alpm().parallel_downloads());
handle.set_disable_dl_timeout(config.alpm().download_timeout());
handle.set_check_space(false);
handle = register_remote(handle, remotes);
handle
}
@ -222,20 +226,25 @@ pub fn instantiate_alpm(inshandle: &ContainerHandle, transflags: &TransactionFla
}
fn alpm_handle(insvars: &ContainerVariables, remotes: &AlpmConfigData, transflags: &TransactionFlags, db_path: String) -> Alpm {
let mut handle = Alpm::new(insvars.root(), &db_path).unwrap();
let mut handle = Alpm::new(insvars.root(), &db_path).expect("Unable to acquire ALPM handle");
let debug = transflags.intersects(TransactionFlags::DEBUG);
let disable_sandbox = CONFIG.alpm().disable_sandbox() || transflags.intersects(TransactionFlags::NO_ALPM_SANDBOX);
if debug {
handle.set_log_cb(*UNIX_TIMESTAMP as usize, alpm_log_callback);
}
handle.set_disable_sandbox(CONFIG.alpm().disable_sandbox());
handle.set_cachedirs(vec![format!("{}/pkg", *CACHE_DIR)].iter()).unwrap();
handle.set_gpgdir(format!("{}/pacman/gnupg", *DATA_DIR)).unwrap();
handle.set_logfile(format!("{}/pacwrap.log", *DATA_DIR)).unwrap();
if disable_sandbox {
handle.set_disable_sandbox(true);
handle.set_sandbox_user(None::<&str>).expect("set sandbox user");
}
handle.set_logfile(format!("{}/pacwrap.log", *DATA_DIR)).expect("set logfile");
handle.set_gpgdir(format!("{}/pacman/gnupg", *DATA_DIR)).expect("set gpgdir");
handle.set_cachedirs(vec![format!("{}/pkg", *CACHE_DIR)].iter()).expect("set cachedirs");
handle.set_parallel_downloads(CONFIG.alpm().parallel_downloads());
handle.set_check_space(CONFIG.alpm().check_space());
handle.set_disable_dl_timeout(CONFIG.alpm().download_timeout());
handle.set_check_space(CONFIG.alpm().check_space());
handle = register_remote(handle, remotes);
handle
}

View file

@ -99,15 +99,16 @@ pub trait Transaction {
bitflags! {
pub struct TransactionFlags: u16 {
const NONE = 0;
const TARGET_ONLY = 0b000000001;
const PREVIEW = 0b000000010;
const NO_CONFIRM = 0b000000100;
const FORCE_DATABASE = 0b000001000;
const DATABASE_ONLY = 0b000010000;
const CREATE = 0b000100000;
const FILESYSTEM_SYNC = 0b001000000;
const LAZY_LOAD_DB = 0b010000000;
const DEBUG = 0b100000000;
const TARGET_ONLY = 0b0000000001;
const PREVIEW = 0b0000000010;
const NO_CONFIRM = 0b0000000100;
const FORCE_DATABASE = 0b0000001000;
const DATABASE_ONLY = 0b0000010000;
const CREATE = 0b0000100000;
const FILESYSTEM_SYNC = 0b0001000000;
const LAZY_LOAD_DB = 0b0010000000;
const DEBUG = 0b0100000000;
const NO_ALPM_SANDBOX = 0b1000000000;
}
}

View file

@ -184,6 +184,7 @@ fn engage_aggregator<'a>(args: &mut Arguments, lock: &'a Lock) -> Result<()> {
Op::Long("from-config") => continue,
Op::Long("debug") => flags = flags | TransactionFlags::DEBUG,
Op::Long("noconfirm") => flags = flags | TransactionFlags::NO_CONFIRM,
Op::Long("disable-sandbox") => flags = flags | TransactionFlags::NO_ALPM_SANDBOX,
Op::Long("reinitialize-all") =>
for instance in cache.registered() {
if let Some(handle) = cache.get_instance_option(instance) {

View file

@ -148,6 +148,10 @@ This document was generated by the {name} binary with version {} of the program.
{tab}{tab}Instructs {bold}libalpm{reset_bold}(3) to parallelise the download queue with a maximum queue amount. Specify an
{tab}{tab}{bold}integer{reset_bold} to declare a maximum value.
{sub_bold}disable_sandbox{reset_bold}: false
{tab}{tab}Instructs {bold}libalpm{reset_bold}(3) to disable the landlock and seccomp sandbox for downloads. Specify a
{tab}{tab}{bold}bool{reset_bold} to declare a maximum value.
{head}SEE ALSO{reset}
{tab}{tab}{bold}pacman.conf{reset_bold}(5), {bold}libalpm{reset_bold}(3)

View file

@ -228,6 +228,13 @@ pub fn sync(buf: &mut String, layout: &HelpLayout) -> Result {
{sub_bold}--noconfirm{reset_bold}
{tab}{tab}Override confirmation prompts and confirm all operations.
{sub_bold}--disable-sandbox{reset_bold}
{tab}{tab}Instruct libalpm to disable its own sandbox, utilizing landlock and seccomp, in order to mitigate potential
{tab}{tab}issues with kernel compatibillity.
{sub_bold}--debug{reset_bold}
{tab}{tab}Use this option when reporting bugs.
{sub_sect}EXAMPLES{reset_bold}
{sub}`$ pacwrap init --base --target base`
{tab}{tab}Synchronize remotes and create a base-type container named `base` with no additional packages.
@ -294,6 +301,13 @@ pub fn remove(buf: &mut String, layout: &HelpLayout) -> Result {
{sub_bold}--noconfirm{reset_bold}
{tab}{tab}Override confirmation prompts and confirm all operations.
{sub_bold}--disable-sandbox{reset_bold}
{tab}{tab}Instruct libalpm to disable its own sandbox, utilizing landlock and seccomp, in order to mitigate potential
{tab}{tab}issues with kernel compatibillity.
{sub_bold}--debug{reset_bold}
{tab}{tab}Use this option when reporting bugs.
{sub_sect}EXAMPLES{reset_bold}
{sub}`$ pacwrap -Rt firefox firefox`
{tab}{tab}Remove the target package firefox from target container firefox.
@ -351,6 +365,13 @@ pub fn compose(buf: &mut String, layout: &HelpLayout) -> Result {
{sub_bold}--noconfirm{reset_bold}
{tab}{tab}Override confirmation prompts and confirm all operations.
{sub_bold}--disable-sandbox{reset_bold}
{tab}{tab}Instruct libalpm to disable its own sandbox, utilizing landlock and seccomp, in order to mitigate potential
{tab}{tab}issues with kernel compatibillity.
{sub_bold}--debug{reset_bold}
{tab}{tab}Use this option when reporting bugs.
{sub_sect}EXAMPLES{reset_bold}
{sub}`$ pacwrap compose -rt element element.yml`
{tab}{tab}Reinitialize an existing container named element with its configuration derived

View file

@ -98,6 +98,7 @@ fn engage_aggregator<'a>(
Op::Long("dbonly") => flags = flags | TransactionFlags::DATABASE_ONLY,
Op::Long("noconfirm") => flags = flags | TransactionFlags::NO_CONFIRM,
Op::Long("force-foreign") => flags = flags | TransactionFlags::FORCE_DATABASE,
Op::Long("disable-sandbox") => flags = flags | TransactionFlags::NO_ALPM_SANDBOX,
Op::Short('p') | Op::Long("preview") => flags = flags | TransactionFlags::PREVIEW,
Op::Short('f') | Op::Long("filesystem") => flags = flags | TransactionFlags::FILESYSTEM_SYNC,
Op::Short('t') | Op::Long("target") => match args.next() {

View file

@ -167,10 +167,11 @@ fn engage_aggregator<'a>(
while let Some(arg) = args.next() {
match arg {
Op::Short('y') | Op::Short('u') | Op::Long("refresh") | Op::Long("upgrade") => continue,
Op::Long("dbonly") => flags = flags | TransactionFlags::DATABASE_ONLY,
Op::Long("force-foreign") => flags = flags | TransactionFlags::FORCE_DATABASE,
Op::Long("noconfirm") => flags = flags | TransactionFlags::NO_CONFIRM,
Op::Long("debug") => flags = flags | TransactionFlags::DEBUG,
Op::Long("dbonly") => flags = flags | TransactionFlags::DATABASE_ONLY,
Op::Long("noconfirm") => flags = flags | TransactionFlags::NO_CONFIRM,
Op::Long("force-foreign") => flags = flags | TransactionFlags::FORCE_DATABASE,
Op::Long("disable-sandbox") => flags = flags | TransactionFlags::NO_ALPM_SANDBOX,
Op::Short('l') | Op::Long("lazy-load") => flags = flags | TransactionFlags::LAZY_LOAD_DB,
Op::Short('o') | Op::Long("target-only") => flags = flags | TransactionFlags::TARGET_ONLY,
Op::Short('f') | Op::Long("filesystem") => flags = flags | TransactionFlags::FILESYSTEM_SYNC,