#![allow(clippy::missing_safety_doc)]
#![allow(clippy::not_unsafe_ptr_arg_deref)]
mod inode;
mod ownership;
mod platform;
use ownership::{
current_fake_gid, current_fake_uid, maybe_remove_inode_path, modify_stat_buf,
prepare_rename_overwrite, record_chmod_fd, record_chmod_path, record_chown_fd,
record_chown_path, set_current_ids, set_fsuid, setfsgid as set_fake_fsgid,
};
#[cfg(any(target_os = "linux", target_os = "macos"))]
use ownership::{
fake_mknod_path, fake_mknodat, maybe_remove_inode_at, record_chmod_at, record_chown_at,
};
use std::ffi::CStr;
use std::os::raw::c_char;
#[ctor::ctor]
unsafe fn init() {
let uid = std::env::var("PSEUDOROOT_UID")
.ok()
.and_then(|u| u.parse::<u32>().ok())
.unwrap_or(0);
let gid = std::env::var("PSEUDOROOT_GID")
.ok()
.and_then(|g| g.parse::<u32>().ok())
.unwrap_or(0);
ownership::store_bootstrap_ids(uid, gid);
}
pub use platform::*;
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn getuid() -> u32 {
current_fake_uid()
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn geteuid() -> u32 {
current_fake_uid()
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn getgid() -> u32 {
current_fake_gid()
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn getegid() -> u32 {
current_fake_gid()
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn getresuid(ruid: *mut u32, euid: *mut u32, suid: *mut u32) -> i32 {
let current_uid = getuid();
if !ruid.is_null() {
unsafe {
*ruid = current_uid;
}
}
if !euid.is_null() {
unsafe {
*euid = current_uid;
}
}
if !suid.is_null() {
unsafe {
*suid = current_uid;
}
}
0
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn getresgid(rgid: *mut u32, egid: *mut u32, sgid: *mut u32) -> i32 {
let current_gid = getgid();
if !rgid.is_null() {
unsafe {
*rgid = current_gid;
}
}
if !egid.is_null() {
unsafe {
*egid = current_gid;
}
}
if !sgid.is_null() {
unsafe {
*sgid = current_gid;
}
}
0
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn setuid(uid: u32) -> i32 {
set_current_ids(uid, getgid())
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn setgid(gid: u32) -> i32 {
set_current_ids(getuid(), gid)
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn setreuid(_ruid: u32, euid: u32) -> i32 {
set_current_ids(euid, getgid())
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn setregid(_rgid: u32, egid: u32) -> i32 {
set_current_ids(getuid(), egid)
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn setresuid(_ruid: u32, euid: u32, _suid: u32) -> i32 {
set_current_ids(euid, getgid())
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn setresgid(_rgid: u32, egid: u32, _sgid: u32) -> i32 {
set_current_ids(getuid(), egid)
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn setfsuid(uid: u32) -> i32 {
set_fsuid(uid) as i32
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn setfsgid(gid: u32) -> i32 {
set_fake_fsgid(gid) as i32
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn chown(path: *const c_char, uid: u32, gid: u32) -> i32 {
record_chown_path(path, false, uid, gid)
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn stat(path: *const c_char, buf: *mut libc::stat) -> i32 {
let result = unsafe { platform::real_stat(path, buf) };
if result == 0 && !buf.is_null() {
unsafe { modify_stat_buf(buf) };
}
result
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn fstat(fd: i32, buf: *mut libc::stat) -> i32 {
let result = unsafe { platform::real_fstat(fd, buf) };
if result == 0 && !buf.is_null() {
unsafe { modify_stat_buf(buf) };
}
result
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn lstat(path: *const c_char, buf: *mut libc::stat) -> i32 {
let result = unsafe { platform::real_lstat(path, buf) };
if result == 0 && !buf.is_null() {
unsafe { modify_stat_buf(buf) };
}
result
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn fstatat(
dirfd: i32,
pathname: *const c_char,
buf: *mut libc::stat,
flags: i32,
) -> i32 {
let result = unsafe { platform::real_fstatat(dirfd, pathname, buf, flags) };
if result == 0 && !buf.is_null() {
unsafe { modify_stat_buf(buf) };
}
result
}
#[cfg(target_os = "linux")]
#[unsafe(no_mangle)]
pub extern "C" fn statx(
dirfd: i32,
pathname: *const c_char,
flags: i32,
mask: u32,
buf: *mut std::ffi::c_void,
) -> i32 {
let result = unsafe { platform::real_statx(dirfd, pathname, flags, mask, buf) };
if result == 0 && !buf.is_null() {
unsafe { ownership::modify_statx_buf(buf) };
}
result
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn chmod(path: *const c_char, mode: libc::mode_t) -> i32 {
record_chmod_path(path, mode)
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn fchmod(fd: i32, mode: libc::mode_t) -> i32 {
record_chmod_fd(fd, mode)
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn fchmodat(dirfd: i32, path: *const c_char, mode: libc::mode_t, flags: i32) -> i32 {
record_chmod_at(dirfd, path, mode, flags)
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn lchown(path: *const c_char, uid: u32, gid: u32) -> i32 {
record_chown_path(path, true, uid, gid)
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn fchown(fd: i32, uid: u32, gid: u32) -> i32 {
record_chown_fd(fd, uid, gid)
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn fchownat(dirfd: i32, path: *const c_char, uid: u32, gid: u32, flags: i32) -> i32 {
record_chown_at(dirfd, path, flags, uid, gid)
}
#[inline]
#[must_use]
pub unsafe fn cstr_to_string(cstr: *const c_char) -> Option<String> {
if cstr.is_null() {
None
} else {
Some(
unsafe { CStr::from_ptr(cstr) }
.to_string_lossy()
.into_owned(),
)
}
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn unlink(path: *const c_char) -> i32 {
maybe_remove_inode_path(path);
unsafe { platform::real_unlink(path) }
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn unlinkat(dirfd: i32, path: *const c_char, flags: i32) -> i32 {
maybe_remove_inode_at(dirfd, path, flags);
unsafe { platform::real_unlinkat(dirfd, path, flags) }
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn rmdir(path: *const c_char) -> i32 {
maybe_remove_inode_path(path);
unsafe { platform::real_rmdir(path) }
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn rename(oldpath: *const c_char, newpath: *const c_char) -> i32 {
prepare_rename_overwrite(libc::AT_FDCWD, oldpath, libc::AT_FDCWD, newpath);
unsafe { platform::real_rename(oldpath, newpath) }
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn renameat(
olddirfd: i32,
oldpath: *const c_char,
newdirfd: i32,
newpath: *const c_char,
) -> i32 {
prepare_rename_overwrite(olddirfd, oldpath, newdirfd, newpath);
unsafe { platform::real_renameat(olddirfd, oldpath, newdirfd, newpath) }
}
#[cfg(target_os = "linux")]
#[unsafe(no_mangle)]
pub extern "C" fn renameat2(
olddirfd: i32,
oldpath: *const c_char,
newdirfd: i32,
newpath: *const c_char,
flags: u32,
) -> i32 {
prepare_rename_overwrite(olddirfd, oldpath, newdirfd, newpath);
unsafe { platform::real_renameat2(olddirfd, oldpath, newdirfd, newpath, flags) }
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn mknod(pathname: *const c_char, mode: libc::mode_t, dev: libc::dev_t) -> i32 {
fake_mknod_path(pathname, mode, dev)
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn mknodat(
dirfd: i32,
pathname: *const c_char,
mode: libc::mode_t,
dev: libc::dev_t,
) -> i32 {
fake_mknodat(dirfd, pathname, mode, dev)
}
#[cfg_attr(target_os = "linux", unsafe(no_mangle))]
pub extern "C" fn setgroups(_size: libc::size_t, _list: *const libc::gid_t) -> i32 {
0
}
#[cfg(target_os = "linux")]
#[unsafe(no_mangle)]
pub extern "C" fn capset(_hdrp: *const std::ffi::c_void, _data: *const std::ffi::c_void) -> i32 {
0
}