Make escalated communication pathless using sendfd.

This commit is contained in:
4lDO2
2023-10-14 12:48:12 +02:00
parent 76242fc7bc
commit 966c59ca0c
6 changed files with 127 additions and 114 deletions
Generated
+70 -81
View File
@@ -35,8 +35,8 @@ dependencies = [
"heck",
"indexmap",
"log",
"proc-macro2 1.0.66",
"quote 1.0.32",
"proc-macro2 1.0.69",
"quote 1.0.33",
"serde",
"serde_json",
"syn 1.0.109",
@@ -55,9 +55,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.80"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51f1226cd9da55587234753d1245dd5b132343ea240f26b6a9003d68706141ba"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
@@ -113,25 +113,14 @@ version = "0.1.0"
[[package]]
name = "errno"
version = "0.3.2"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "fastrand"
version = "1.9.0"
@@ -175,9 +164,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.3.2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
[[package]]
name = "indexmap"
@@ -204,7 +193,7 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi 0.3.2",
"hermit-abi 0.3.3",
"libc",
"windows-sys 0.48.0",
]
@@ -251,15 +240,15 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.19"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
version = "2.5.0"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "memoffset"
@@ -272,9 +261,9 @@ dependencies = [
[[package]]
name = "num-traits"
version = "0.2.16"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
]
@@ -306,9 +295,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.66"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [
"unicode-ident",
]
@@ -324,11 +313,11 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.32"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2 1.0.66",
"proc-macro2 1.0.69",
]
[[package]]
@@ -389,7 +378,8 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "redox_syscall"
version = "0.3.5"
source = "git+https://gitlab.redox-os.org/redox-os/syscall#a525620c818a801bb7038e111b71033eff56a3ee"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags",
]
@@ -397,8 +387,7 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
source = "git+https://gitlab.redox-os.org/4lDO2/syscall?branch=sendfd#0200e818a4ba752c1869be9718eb7f090c19d65c"
dependencies = [
"bitflags",
]
@@ -522,29 +511,29 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.180"
version = "1.0.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed"
checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.180"
version = "1.0.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036"
checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
dependencies = [
"proc-macro2 1.0.66",
"quote 1.0.32",
"syn 2.0.28",
"proc-macro2 1.0.69",
"quote 1.0.33",
"syn 2.0.38",
]
[[package]]
name = "serde_json"
version = "1.0.104"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c"
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
dependencies = [
"itoa",
"ryu",
@@ -589,19 +578,19 @@ version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2 1.0.66",
"quote 1.0.32",
"proc-macro2 1.0.69",
"quote 1.0.33",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.28"
version = "2.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
dependencies = [
"proc-macro2 1.0.66",
"quote 1.0.32",
"proc-macro2 1.0.69",
"quote 1.0.33",
"unicode-ident",
]
@@ -620,9 +609,9 @@ dependencies = [
[[package]]
name = "termcolor"
version = "1.2.0"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
dependencies = [
"winapi-util",
]
@@ -650,15 +639,15 @@ checksum = "e92e959f029e4f8ee25d70d15ab58d2b46f98a17bc238b9265ff0c26f6f3d67f"
[[package]]
name = "unicode-ident"
version = "1.0.11"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-width"
version = "0.1.10"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "unicode-xid"
@@ -684,9 +673,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]
@@ -712,7 +701,7 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.1",
"windows-targets 0.48.5",
]
[[package]]
@@ -732,17 +721,17 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.48.1"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.0",
"windows_aarch64_msvc 0.48.0",
"windows_i686_gnu 0.48.0",
"windows_i686_msvc 0.48.0",
"windows_x86_64_gnu 0.48.0",
"windows_x86_64_gnullvm 0.48.0",
"windows_x86_64_msvc 0.48.0",
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
@@ -753,9 +742,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
@@ -765,9 +754,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
@@ -777,9 +766,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
@@ -789,9 +778,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
@@ -801,9 +790,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
@@ -813,9 +802,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
@@ -825,6 +814,6 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+1 -1
View File
@@ -61,4 +61,4 @@ panic = "abort"
[patch.crates-io]
libc = { git = "https://gitlab.redox-os.org/redox-os/liblibc.git", branch = "redox_0.2.138" }
redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall" }
redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall", branch = "sendfd" }
+3
View File
@@ -144,6 +144,9 @@ impl Pal for Sys {
unsafe fn execve(path: &CStr, argv: *const *mut c_char, envp: *const *mut c_char) -> c_int {
e(syscall!(EXECVE, path.as_ptr(), argv, envp)) as c_int
}
unsafe fn fexecve(fildes: c_int, argv: *const *mut c_char, envp: *const *mut c_char) -> c_int {
todo!("not yet used by relibc")
}
fn exit(status: c_int) -> ! {
unsafe {
+1
View File
@@ -48,6 +48,7 @@ pub trait Pal {
fn dup2(fildes: c_int, fildes2: c_int) -> c_int;
unsafe fn execve(path: &CStr, argv: *const *mut c_char, envp: *const *mut c_char) -> c_int;
unsafe fn fexecve(fildes: c_int, argv: *const *mut c_char, envp: *const *mut c_char) -> c_int;
fn exit(status: c_int) -> !;
+43 -30
View File
@@ -13,7 +13,8 @@ use redox_exec::{ExtraInfo, FdGuard, FexecResult};
use syscall::{data::Stat, error::*, flag::*};
fn fexec_impl(
file: File,
exec_file: FdGuard,
open_via_dup: FdGuard,
path: &[u8],
args: &[&[u8]],
envs: &[&[u8]],
@@ -21,15 +22,10 @@ fn fexec_impl(
extrainfo: &ExtraInfo,
interp_override: Option<redox_exec::InterpOverride>,
) -> Result<usize> {
let fd = *file;
core::mem::forget(file);
let image_file = FdGuard::new(fd as usize);
let open_via_dup = FdGuard::new(syscall::open("thisproc:current/open_via_dup", 0)?);
let memory = FdGuard::new(syscall::open("memory:", 0)?);
let addrspace_selection_fd = match redox_exec::fexec_impl(
image_file,
exec_file,
open_via_dup,
&memory,
path,
@@ -55,7 +51,7 @@ fn fexec_impl(
let path_cstr = CStr::from_bytes_with_nul(&path).map_err(|_| Error::new(ENOEXEC))?;
return execve(
path_cstr,
Executable::AtPath(path_cstr),
ArgEnv::Parsed {
total_args_envs_size,
args,
@@ -83,20 +79,31 @@ pub enum ArgEnv<'a> {
total_args_envs_size: usize,
},
}
pub enum Executable<'a> {
AtPath(&'a CStr),
InFd { file: File, arg0: &'a [u8] },
}
pub fn execve(
path: &CStr,
exec: Executable<'_>,
arg_env: ArgEnv,
interp_override: Option<redox_exec::InterpOverride>,
) -> Result<usize> {
// NOTE: We must omit O_CLOEXEC and close manually, otherwise it will be closed before we
// have even read it!
let mut image_file = File::open(path, O_RDONLY as c_int).map_err(|_| Error::new(ENOENT))?;
let (mut image_file, arg0) = match exec {
Executable::AtPath(path) => (File::open(path, O_RDONLY as c_int).map_err(|_| Error::new(ENOENT))?, path.to_bytes()),
Executable::InFd { file, arg0 } => (file, arg0),
};
// With execve now being implemented in userspace, we need to check ourselves that this
// file is actually executable. While checking for read permission is unnecessary as the
// scheme will not allow us to read otherwise, the execute bit is completely unenforced. We
// have the permission to mmap executable memory and fill it with the program even if it is
// unset, so the best we can do is check that nothing is executed by accident.
// scheme will not allow us to read otherwise, the execute bit is completely unenforced.
//
// But we do (currently) have the permission to mmap executable memory and fill it with any
// program, even marked non-executable, so really the best we can do is check that nothing is
// executed by accident.
//
// TODO: At some point we might have capabilities limiting the ability to allocate
// executable memory, and in that case we might use the `escalate:` scheme as we already do
@@ -260,25 +267,23 @@ pub fn execve(
}
}
if !is_interpreted && wants_setugid {
// Make sure the last file descriptor not covered by O_CLOEXEC is not leaked.
drop(image_file);
let this_context_fd = FdGuard::new(syscall::open("thisproc:current/open_via_dup", 0)?);
// TODO: Convert image_file to FdGuard earlier?
let exec_fd_guard = FdGuard::new(image_file.fd as usize);
core::mem::forget(image_file);
if !is_interpreted && wants_setugid {
// We are now going to invoke `escalate:` rather than loading the program ourselves.
let escalate_fd = FdGuard::new(syscall::open("escalate:", O_WRONLY)?);
// First, we write the path.
//
// TODO: For improved security, use a hypothetical SYS_DUP_FORWARD syscall to give the
// scheme our file descriptor. It can check through the kernel-overwritten stat.st_dev
// field that it pertains to a "trusted" scheme (i.e. of at least the privilege the
// new uid/gid has), although for now only root can open schemes. Passing a file
// descriptor and not a path will allow escalated to run in a limited namespace.
//
// TODO: Plus, at this point fexecve is not implemented (but specified in
// POSIX.1-2008), and to avoid bad syscalls such as fpath, passing a file descriptor
// would be better.
let _ = syscall::write(*escalate_fd, path.to_bytes());
// First, send the context handle of this process to escalated.
send_fd_guard(*escalate_fd, this_context_fd)?;
// Then, send the file descriptor containing the file descriptor to be executed.
send_fd_guard(*escalate_fd, exec_fd_guard)?;
// Then, write the path (argv[0]).
let _ = syscall::write(*escalate_fd, arg0);
// Second, we write the flattened args and envs with NUL characters separating
// individual items. This can be copied directly into the new executable's memory.
@@ -298,8 +303,9 @@ pub fn execve(
} else {
let extrainfo = ExtraInfo { cwd: Some(&cwd) };
fexec_impl(
image_file,
path.to_bytes(),
exec_fd_guard,
this_context_fd,
arg0,
&args,
&envs,
total_args_envs_size,
@@ -319,3 +325,10 @@ where
}
vec.into_boxed_slice()
}
fn send_fd_guard(dst_socket: usize, fd: FdGuard) -> Result<()> {
syscall::sendfd(dst_socket, *fd, 0, 0)?;
// The kernel closes file descriptors that are sent, so don't call SYS_CLOSE redundantly.
core::mem::forget(fd);
Ok(())
}
+9 -2
View File
@@ -63,7 +63,7 @@ macro_rules! path_from_c_str {
}};
}
use self::path::canonicalize;
use self::{path::canonicalize, exec::Executable};
pub fn e(sys: Result<usize>) -> usize {
match sys {
@@ -231,7 +231,14 @@ impl Pal for Sys {
unsafe fn execve(path: &CStr, argv: *const *mut c_char, envp: *const *mut c_char) -> c_int {
e(self::exec::execve(
path,
Executable::AtPath(path),
self::exec::ArgEnv::C { argv, envp },
None,
)) as c_int
}
unsafe fn fexecve(fildes: c_int, argv: *const *mut c_char, envp: *const *mut c_char) -> c_int {
e(self::exec::execve(
Executable::InFd { file: File::new(fildes), arg0: CStr::from_ptr(argv.read()).to_bytes() },
self::exec::ArgEnv::C { argv, envp },
None,
)) as c_int