Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/sandlock-core/src/checkpoint/capture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ use crate::error::{SandlockError, SandboxRuntimeError};

pub(crate) fn ptrace_seize(pid: i32) -> io::Result<()> {
let ret = unsafe {
libc::ptrace(libc::PTRACE_SEIZE as libc::c_uint, pid, 0, 0)
libc::ptrace(libc::PTRACE_SEIZE, pid, 0, 0)
};
if ret < 0 {
return Err(io::Error::last_os_error());
}
// PTRACE_INTERRUPT stops the tracee without SIGSTOP side effects
let ret = unsafe {
libc::ptrace(libc::PTRACE_INTERRUPT as libc::c_uint, pid, 0, 0)
libc::ptrace(libc::PTRACE_INTERRUPT, pid, 0, 0)
};
if ret < 0 {
return Err(io::Error::last_os_error());
Expand Down
4 changes: 2 additions & 2 deletions crates/sandlock-core/src/chroot/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1024,7 +1024,7 @@ pub(crate) async fn handle_chroot_exec(
let child_interp_fd = unsafe {
libc::ioctl(
notif_fd,
SECCOMP_IOCTL_NOTIF_ADDFD as libc::c_ulong,
SECCOMP_IOCTL_NOTIF_ADDFD as libc::Ioctl,
&addfd_interp as *const _,
)
};
Expand Down Expand Up @@ -1073,7 +1073,7 @@ pub(crate) async fn handle_chroot_exec(
let child_fd = unsafe {
libc::ioctl(
notif_fd,
SECCOMP_IOCTL_NOTIF_ADDFD as libc::c_ulong,
SECCOMP_IOCTL_NOTIF_ADDFD as libc::Ioctl,
&addfd as *const _,
)
};
Expand Down
4 changes: 2 additions & 2 deletions crates/sandlock-core/src/cow/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,7 @@ pub(crate) async fn handle_cow_exec(
let child_fd = unsafe {
libc::ioctl(
notif_fd,
crate::sys::structs::SECCOMP_IOCTL_NOTIF_ADDFD as libc::c_ulong,
crate::sys::structs::SECCOMP_IOCTL_NOTIF_ADDFD as libc::Ioctl,
&addfd as *const _,
)
};
Expand Down Expand Up @@ -1380,7 +1380,7 @@ pub(crate) async fn handle_cow_chdir(
let child_fd = unsafe {
libc::ioctl(
notif_fd,
crate::sys::structs::SECCOMP_IOCTL_NOTIF_ADDFD as libc::c_ulong,
crate::sys::structs::SECCOMP_IOCTL_NOTIF_ADDFD as libc::Ioctl,
&addfd as *const _,
)
};
Expand Down
4 changes: 2 additions & 2 deletions crates/sandlock-core/src/freeze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ fn seize_and_interrupt(tid: i32) -> io::Result<SeizeOutcome> {
}

let ret = unsafe {
libc::ptrace(libc::PTRACE_SEIZE as libc::c_uint, tid, 0, 0)
libc::ptrace(libc::PTRACE_SEIZE, tid, 0, 0)
};
if ret < 0 {
let err = io::Error::last_os_error();
Expand All @@ -132,7 +132,7 @@ fn seize_and_interrupt(tid: i32) -> io::Result<SeizeOutcome> {
// before returning so we don't leave the task traced-but-running.

let ret = unsafe {
libc::ptrace(libc::PTRACE_INTERRUPT as libc::c_uint, tid, 0, 0)
libc::ptrace(libc::PTRACE_INTERRUPT, tid, 0, 0)
};
if ret < 0 {
let err = io::Error::last_os_error();
Expand Down
20 changes: 11 additions & 9 deletions crates/sandlock-core/src/landlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,19 +150,21 @@ pub fn abi_version() -> Result<u32, ConfinementError> {

/// Open `path` and add a Landlock path-beneath rule to `ruleset_fd`.
fn add_path_rule(ruleset_fd: &OwnedFd, path: &Path, access: u64) -> Result<(), ConfinementError> {
use std::os::unix::fs::OpenOptionsExt;
use std::os::fd::FromRawFd;
// Reference the path with O_PATH rather than opening it for I/O: O_PATH does
// not block on FIFOs and needs no read permission on the target, so a rule
// on a FIFO or a write-only/no-read path neither hangs nor fails here. An
// O_PATH fd still supports fstat (the file-type check below) and serves as a
// valid parent_fd for landlock_add_rule.
let file = std::fs::OpenOptions::new()
.read(true)
.custom_flags(libc::O_PATH | libc::O_CLOEXEC)
.open(path)
.map_err(|e| {
ConfinementError::Landlock(format!("open path {:?} failed: {}", path, e))
})?;
// valid parent_fd for landlock_add_rule. Call open(2) directly: musl folds
// O_PATH into O_ACCMODE, which OpenOptions::custom_flags masks out.
let c_path = std::ffi::CString::new(path.as_os_str().as_encoded_bytes())
.map_err(|e| ConfinementError::Landlock(format!("open path {:?} failed: {}", path, e)))?;
let raw = unsafe { libc::open(c_path.as_ptr(), libc::O_PATH | libc::O_CLOEXEC) };
if raw < 0 {
let e = std::io::Error::last_os_error();
return Err(ConfinementError::Landlock(format!("open path {:?} failed: {}", path, e)));
}
let file = std::fs::File::from(unsafe { OwnedFd::from_raw_fd(raw) });

// Directory-only access rights (READ_DIR, MAKE_*, REMOVE_*, REFER) make
// landlock_add_rule fail with EINVAL on a non-directory path. Mask the
Expand Down
2 changes: 1 addition & 1 deletion crates/sandlock-core/src/network/send_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn send_materialized_at(fd: RawFd, m: &MaterializedMsg, offset: usize, flags: i3
}
if let Some(ref c) = m.control {
msg.msg_control = c.as_ptr() as *mut libc::c_void;
msg.msg_controllen = c.len();
msg.msg_controllen = c.len() as _;
}
}
msg.msg_iov = &iov as *const libc::iovec as *mut libc::iovec;
Expand Down
12 changes: 6 additions & 6 deletions crates/sandlock-core/src/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ fn process_creation_worker(
| libc::PTRACE_O_TRACEVFORK
| libc::PTRACE_O_TRACECLONE
| libc::PTRACE_O_TRACESYSGOOD) as libc::c_ulong;
let ret = unsafe { libc::ptrace(libc::PTRACE_SEIZE as libc::c_uint, caller_tid, 0, opts) };
let ret = unsafe { libc::ptrace(libc::PTRACE_SEIZE, caller_tid, 0, opts) };
if ret < 0 {
let errno = io::Error::last_os_error().raw_os_error().unwrap_or(libc::EPERM);
let _ = attached_tx.send(Err(errno));
Expand Down Expand Up @@ -441,13 +441,13 @@ fn run_creation_event_loop(caller_tid: i32, ctx: &Arc<SupervisorCtx>) -> io::Res
// Some other signal-delivery-stop in the window: forward the pending
// signal and keep waiting for the fork event.
let inject = if stopsig == libc::SIGTRAP { 0 } else { stopsig as libc::c_ulong };
ptrace_resume(caller_tid, libc::PTRACE_CONT, inject)?;
ptrace_cont(caller_tid, inject)?;
}
}

/// `ptrace(request, tid, 0, data)` returning an error on failure.
fn ptrace_resume(tid: i32, request: libc::c_uint, data: libc::c_ulong) -> io::Result<()> {
let ret = unsafe { libc::ptrace(request, tid, 0, data) };
/// Resume `tid` with `sig` injected (0 for none), failing on error.
fn ptrace_cont(tid: i32, sig: libc::c_ulong) -> io::Result<()> {
let ret = unsafe { libc::ptrace(libc::PTRACE_CONT, tid, 0, sig) };
if ret < 0 {
return Err(io::Error::last_os_error());
}
Expand All @@ -461,7 +461,7 @@ fn handle_fork_event(caller_tid: i32, ctx: &Arc<SupervisorCtx>) -> io::Result<bo
let mut child_pid: libc::c_ulong = 0;
let ret = unsafe {
libc::ptrace(
libc::PTRACE_GETEVENTMSG as libc::c_uint,
libc::PTRACE_GETEVENTMSG,
caller_tid,
0,
&mut child_pid,
Expand Down
35 changes: 19 additions & 16 deletions crates/sandlock-core/src/seccomp/notif.rs
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,7 @@ impl NotifPolicy {
fn recv_notif(fd: RawFd) -> io::Result<SeccompNotif> {
let mut notif: SeccompNotif = unsafe { std::mem::zeroed() };
let ret = unsafe {
libc::ioctl(fd, SECCOMP_IOCTL_NOTIF_RECV as libc::c_ulong, &mut notif as *mut _)
libc::ioctl(fd, SECCOMP_IOCTL_NOTIF_RECV as libc::Ioctl, &mut notif as *mut _)
};
if ret < 0 {
Err(io::Error::last_os_error())
Expand Down Expand Up @@ -945,7 +945,7 @@ fn inject_fd_and_send(fd: RawFd, id: u64, srcfd: RawFd, newfd_flags: u32) -> io:
newfd_flags,
};
let ret = unsafe {
libc::ioctl(fd, SECCOMP_IOCTL_NOTIF_ADDFD as libc::c_ulong, &addfd as *const _)
libc::ioctl(fd, SECCOMP_IOCTL_NOTIF_ADDFD as libc::Ioctl, &addfd as *const _)
};
if ret < 0 {
Err(io::Error::last_os_error())
Expand All @@ -965,7 +965,7 @@ fn inject_fd(fd: RawFd, id: u64, srcfd: RawFd, targetfd: i32) -> io::Result<()>
newfd_flags: 0,
};
let ret = unsafe {
libc::ioctl(fd, SECCOMP_IOCTL_NOTIF_ADDFD as libc::c_ulong, &addfd as *const _)
libc::ioctl(fd, SECCOMP_IOCTL_NOTIF_ADDFD as libc::Ioctl, &addfd as *const _)
};
if ret < 0 {
Err(io::Error::last_os_error())
Expand All @@ -977,7 +977,7 @@ fn inject_fd(fd: RawFd, id: u64, srcfd: RawFd, targetfd: i32) -> io::Result<()>
/// Raw ioctl to send a notification response.
fn send_resp_raw(fd: RawFd, resp: &SeccompNotifResp) -> io::Result<()> {
let ret = unsafe {
libc::ioctl(fd, SECCOMP_IOCTL_NOTIF_SEND as libc::c_ulong, resp as *const _)
libc::ioctl(fd, SECCOMP_IOCTL_NOTIF_SEND as libc::Ioctl, resp as *const _)
};
if ret < 0 {
Err(io::Error::last_os_error())
Expand All @@ -990,7 +990,7 @@ fn send_resp_raw(fd: RawFd, resp: &SeccompNotifResp) -> io::Result<()> {
/// ioctl(fd, SECCOMP_IOCTL_NOTIF_ID_VALID, &id)
pub(crate) fn id_valid(fd: RawFd, id: u64) -> io::Result<()> {
let ret = unsafe {
libc::ioctl(fd, SECCOMP_IOCTL_NOTIF_ID_VALID as libc::c_ulong, &id as *const _)
libc::ioctl(fd, SECCOMP_IOCTL_NOTIF_ID_VALID as libc::Ioctl, &id as *const _)
};
if ret < 0 {
Err(io::Error::last_os_error())
Expand All @@ -1003,7 +1003,7 @@ pub(crate) fn id_valid(fd: RawFd, id: u64) -> io::Result<()> {
fn try_set_sync_wakeup(fd: RawFd) {
let flags: u64 = SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP as u64;
unsafe {
libc::ioctl(fd, SECCOMP_IOCTL_NOTIF_SET_FLAGS as libc::c_ulong, &flags as *const _);
libc::ioctl(fd, SECCOMP_IOCTL_NOTIF_SET_FLAGS as libc::Ioctl, &flags as *const _);
}
}

Expand Down Expand Up @@ -1256,20 +1256,24 @@ fn read_exec_ptr_array(
}
}

/// Read exactly `len` bytes starting at `addr`, chunked at page boundaries.
fn read_exec_range(
/// Whether the `len` bytes at `addr` hold no NUL. Checked one page at a time
/// so the scan stops at a string's terminator before touching a later page,
/// which may be unmapped: musl's allocator leaves gaps between chunks.
fn nul_free_run(
read: &mut impl FnMut(u64, usize) -> Result<Vec<u8>, NotifError>,
addr: u64,
len: usize,
) -> Result<Vec<u8>, NotifError> {
let mut out = Vec::with_capacity(len);
) -> Result<bool, NotifError> {
let end = addr + len as u64;
let mut cur = addr;
while out.len() < len {
let chunk = ((4096 - cur % 4096) as usize).min(len - out.len());
out.extend_from_slice(&read(cur, chunk)?);
while cur < end {
let chunk = ((4096 - cur % 4096) as usize).min((end - cur) as usize);
if read(cur, chunk)?.contains(&0) {
return Ok(false);
}
cur += chunk as u64;
}
Ok(out)
Ok(true)
}

/// Read a NUL-terminated string (NUL excluded) of at most
Expand Down Expand Up @@ -1358,8 +1362,7 @@ fn plan_exec_rewrite(
below.dedup();
let mut nul_free_from = path_ptr;
for &p in below.iter().rev() {
let seg = read_exec_range(read, p, (nul_free_from - p) as usize)?;
if seg.contains(&0) {
if !nul_free_run(read, p, (nul_free_from - p) as usize)? {
break;
}
relocate(&mut buf, &mut relocated, read, p)?;
Expand Down
6 changes: 4 additions & 2 deletions crates/sandlock-core/src/sys/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -692,16 +692,18 @@ mod tests {

#[test]
fn statx_confines_symlinked_parent() {
// The libc crate only exposes this constant for glibc targets.
const STATX_BASIC_STATS: u32 = 0x7ff;
let tmp = TempDir::new().unwrap();
let root = tmp.path();
std::fs::write(root.join("f"), "data").unwrap();
symlink("/etc", root.join("dirlink")).unwrap();
let mut buf = vec![0u8; 256];

// In-tree file resolves; escaping parent does not.
skip_if_nosys!(statx_in_root(root, "f", 0, libc::STATX_BASIC_STATS, &mut buf)).unwrap();
skip_if_nosys!(statx_in_root(root, "f", 0, STATX_BASIC_STATS, &mut buf)).unwrap();
assert_eq!(
statx_in_root(root, "dirlink/group", 0, libc::STATX_BASIC_STATS, &mut buf),
statx_in_root(root, "dirlink/group", 0, STATX_BASIC_STATS, &mut buf),
Err(libc::ENOENT)
);
}
Expand Down
Loading