Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
261cce5
linux: the calls that only look at a file, in a table of their own
eKisNonos Sep 28, 2026
c7bfb97
linux-guests: bbsuite, busybox running forty applets against the host
eKisNonos Sep 28, 2026
0eba141
procstat: show a foreign supervisor the rows of the guests it hosts
eKisNonos Sep 28, 2026
67bf3f1
linux: one copy of a file's bytes and offset for the whole family
eKisNonos Sep 28, 2026
6f9a133
linux: serve fcntl F_DUPFD and F_DUPFD_CLOEXEC
eKisNonos Sep 28, 2026
2682ceb
linux: stat, access and readlink say what Linux says about a file
eKisNonos Sep 28, 2026
350c2ea
linux: /dev, /proc and /sys, made from what NONOS declares
eKisNonos Sep 28, 2026
50e20d3
linux: serve the file calls a program meets beyond read and write
eKisNonos Sep 28, 2026
e1730d6
linux: refuse inotify by name
eKisNonos Sep 28, 2026
5943c36
linux: serve flock and fcntl's record locks, with Linux's rules
eKisNonos Sep 28, 2026
4220b09
linux: sysinfo, getrusage, times, and the id, group and priority calls
eKisNonos Sep 28, 2026
ba00a70
linux-guests: let an image carry only the guests it boots
eKisNonos Sep 28, 2026
1d73f49
linux-guests: bbsuite prints its own output when it fails
eKisNonos Sep 28, 2026
75a6c39
linux-guests: cfiles, the file and system calls against the host
eKisNonos Sep 28, 2026
f856369
linux-guests: cproc, /dev, /proc and /sys against the host
eKisNonos Sep 28, 2026
85ffec3
linux-guests: goos, Go's os, io/fs and path/filepath against the host
eKisNonos Sep 28, 2026
acb4446
linux: walk a path a name at a time, so ".." follows the link before it
eKisNonos Sep 28, 2026
9fa8594
linux: serve openat2's RESOLVE_IN_ROOT
eKisNonos Sep 28, 2026
0e7e4ae
linux: act on preadv2 and pwritev2's RWF_ flags as Linux does
eKisNonos Sep 28, 2026
24d3332
linux-guests: cfiles checks RWF_ flags and RESOLVE_IN_ROOT
eKisNonos Sep 28, 2026
71a9872
linux: put statfs's fields where Linux's struct statfs has them
eKisNonos Sep 28, 2026
8750b2f
linux-guests: cfiles checks statfs against the host
eKisNonos Sep 28, 2026
040f0ca
linux: say ENOSPC when the store is full, not EIO
eKisNonos Sep 28, 2026
08ce349
linux: statfs reports the room the family has, not invented figures
eKisNonos Sep 28, 2026
12ae574
linux-guests: cfiles checks that statfs counts what is written
eKisNonos Sep 28, 2026
993d9dc
linux: measure the family's load average instead of printing zeros
eKisNonos Sep 28, 2026
71d1614
linux: count the family's file copies as its cache and shared memory
eKisNonos Sep 28, 2026
745b049
linux: fill /proc/<pid>/stat's fields that are known, not zeros
eKisNonos Sep 28, 2026
c4813ad
linux: take a whole write to a file in one call, as Linux does
eKisNonos Sep 28, 2026
04b8e78
linux-guests: cproc checks stat's fields, the load and shared memory
eKisNonos Sep 28, 2026
7938c20
linux-guests: cfiles checks that a file takes a 3 MiB write whole
eKisNonos Sep 28, 2026
824a3c4
linux: count what a waited child waited for into its parent's children
eKisNonos Sep 29, 2026
38d5dec
linux-guests: cproc checks a grandchild's counts, not a fault count
eKisNonos Sep 29, 2026
abaaf55
linux: say what each call this branch serves discloses
eKisNonos Sep 30, 2026
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
8 changes: 7 additions & 1 deletion src/syscall/microkernel/procstat_redact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ pub(super) fn sees_all() -> bool {

/// `e` as the caller may see it.
pub(super) fn visible(mut e: ProcStatEntry, caller: u32, all: bool) -> ProcStatEntry {
if all || e.pid == caller {
/*
* A foreign supervisor answers for the guests it hosts, and reports their
* times and memory to them as Linux's getrusage and /proc do; it sees
* those rows and no one else's.
*/
let hosts = caller != 0 && crate::process::foreign::supervisor_of(e.pid) == Some(caller);
if all || e.pid == caller || hosts {
return e;
}
e.run_ticks = 0;
Expand Down
41 changes: 41 additions & 0 deletions userland/capsule_linux/abi/disclosure.txt
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,44 @@ memfd_create | a descriptor number | its own table
statx | as stat | as stat
rseq | 0 | a constant
faccessat2 | as access | as open
pwrite64 | nothing back but a count | as write
preadv | bytes of its own files, as read | as read
pwritev | nothing back but a count | as write
preadv2 | as preadv | as read
pwritev2 | as pwritev | as write
sendfile | a count of bytes moved between its own descriptors | its own data
copy_file_range | a count of bytes copied between its own files | its own data
truncate | success or refusal on a path | as open
fallocate | success or refusal on its own file | its own state
fadvise64 | nothing | none
close_range | nothing | none
creat | as open | as open
openat2 | as open, and whether a walk left the directory it named | the walk is of the guest's own tree
sync | nothing | none
syncfs | nothing | none
fdatasync | whether its own writes reached the store | its own data
flock | whether another process of the family holds a lock on a file | only the family's own locks are seen
setxattr | success or refusal of an attribute on its own file | its own state
lsetxattr | as setxattr | its own state
fsetxattr | as setxattr | its own state
getxattr | an attribute the family set on a file | only what the family itself set
lgetxattr | as getxattr | only what the family itself set
fgetxattr | as getxattr | only what the family itself set
listxattr | the names of the attributes the family set | only what the family itself set
llistxattr | as listxattr | only what the family itself set
flistxattr | as listxattr | only what the family itself set
removexattr | success or refusal | its own state
lremovexattr | as removexattr | its own state
fremovexattr | as removexattr | its own state
sysinfo | the family's uptime, its memory limit and what it holds, its own load, one CPU | declared figures and the family's own measurements; nothing of the machine
getrusage | its own threads' CPU ticks, switches, faults and resident size, and those of children it waited for | the kernel's counts of the family's own threads only
times | its own and its waited children's CPU ticks, and ticks since the family started | its own threads only
getgroups | no supplementary groups | a fixed identity, the same on every install
setgroups | refusal | the identity cannot change
getresuid | 0, 0, 0 | a fixed identity, the same on every install
getresgid | 0, 0, 0 | a fixed identity, the same on every install
setresuid | success only for the identity already held | the identity cannot change
setresgid | success only for the identity already held | the identity cannot change
getpriority | the nice value set for a process of the family | its own state; no process outside the family is named
setpriority | success or refusal of a nice value for a process of the family | its own state; no process outside the family is named
personality | PER_LINUX, the only persona served | the same on every install
1 change: 1 addition & 0 deletions userland/capsule_linux/src/linux/abi/errno.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

//! Linux errno values, and the convention for returning them.

pub use super::errno_io::*;
pub const EPERM: i64 = 1;
pub const ENOENT: i64 = 2;
pub const EINTR: i64 = 4;
Expand Down
27 changes: 27 additions & 0 deletions userland/capsule_linux/src/linux/abi/errno_io.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// NONOS Operating System
// Copyright (C) 2026 NONOS Contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

/*
* The errnos the file, lock and xattr calls answer with, beyond the ones
* errno.rs has always held.
*/

pub const ENXIO: i64 = 6;
pub const EXDEV: i64 = 18;
pub const EFBIG: i64 = 27;
pub const ENOLCK: i64 = 37;
pub const ENODATA: i64 = 61;
pub const EOPNOTSUPP: i64 = 95;
2 changes: 2 additions & 0 deletions userland/capsule_linux/src/linux/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
#![allow(dead_code)]

pub mod errno;
pub mod errno_io;
pub mod name;
pub mod nr;
pub mod nr_path;
pub mod nr_file;
pub mod nr_high;
pub mod nr_sig;
pub mod nr_sched;
62 changes: 62 additions & 0 deletions userland/capsule_linux/src/linux/abi/nr_file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// NONOS Operating System
// Copyright (C) 2026 NONOS Contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

/*
* Syscall numbers for the file, lock, xattr, id and usage calls, transcribed
* from the x86_64 table.
*/

/* Files, their data and their locks; from syscall_64.tbl. */
pub const SENDFILE: u64 = 40;
pub const FLOCK: u64 = 73;
pub const FDATASYNC: u64 = 75;
pub const TRUNCATE: u64 = 76;
pub const CREAT: u64 = 85;
pub const SYNC: u64 = 162;
pub const SETXATTR: u64 = 188;
pub const LSETXATTR: u64 = 189;
pub const FSETXATTR: u64 = 190;
pub const GETXATTR: u64 = 191;
pub const LGETXATTR: u64 = 192;
pub const FGETXATTR: u64 = 193;
pub const LISTXATTR: u64 = 194;
pub const LLISTXATTR: u64 = 195;
pub const FLISTXATTR: u64 = 196;
pub const REMOVEXATTR: u64 = 197;
pub const LREMOVEXATTR: u64 = 198;
pub const FREMOVEXATTR: u64 = 199;
pub const FADVISE64: u64 = 221;
pub const FALLOCATE: u64 = 285;
pub const PREADV: u64 = 295;
pub const PWRITEV: u64 = 296;
pub const SYNCFS: u64 = 306;
pub const COPY_FILE_RANGE: u64 = 326;
pub const PREADV2: u64 = 327;
pub const PWRITEV2: u64 = 328;
pub const CLOSE_RANGE: u64 = 436;
pub const OPENAT2: u64 = 437;

/* What the system is and what the process used; from syscall_64.tbl. */
pub const GETRUSAGE: u64 = 98;
pub const SYSINFO: u64 = 99;
pub const TIMES: u64 = 100;
pub const GETGROUPS: u64 = 115;
pub const SETGROUPS: u64 = 116;
pub const SETRESUID: u64 = 117;
pub const SETRESGID: u64 = 119;
pub const PERSONALITY: u64 = 135;
pub const GETPRIORITY: u64 = 140;
pub const SETPRIORITY: u64 = 141;
1 change: 1 addition & 0 deletions userland/capsule_linux/src/linux/abi/nr_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
//! Syscall numbers for the path, time and process calls, transcribed from the
//! x86_64 table.

pub use super::nr_file::*;
pub const CHDIR: u64 = 80;
pub const FCHDIR: u64 = 81;
pub const RENAME: u64 = 82;
Expand Down
11 changes: 6 additions & 5 deletions userland/capsule_linux/src/linux/call/ctl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
//! `fcntl`.

use crate::linux::abi::errno;
use crate::linux::file;
use crate::linux::file::flags::{O_NONBLOCK, O_RDWR, O_WRONLY};
use crate::linux::guest::{Fd, Guest, Kind};

Expand All @@ -25,6 +26,7 @@ const F_GETFD: u64 = 1;
const F_SETFD: u64 = 2;
const F_GETFL: u64 = 3;
const F_SETFL: u64 = 4;
const F_DUPFD_CLOEXEC: u64 = 1030;

/// The only descriptor flag there is.
const FD_CLOEXEC: u64 = 1;
Expand Down Expand Up @@ -53,11 +55,10 @@ pub fn fcntl(guest: &mut Guest, fd: u64, cmd: u64, arg: u64) -> u64 {
errno::ok(0)
}
F_GETFL => errno::ok(status(entry)),
/*
* Duplication needs a second handle on the server, which the store
* does not offer yet.
*/
F_DUPFD => errno::fail(errno::ENOSYS),
/* The lowest free number at or above `arg`: where a shell keeps one aside. */
F_DUPFD | F_DUPFD_CLOEXEC => file::dup_from(guest, fd, arg, cmd == F_DUPFD_CLOEXEC),
/* The record locks; a wait among them is parked before this is reached. */
c if file::is_lock_cmd(c) => file::fcntl_lock(guest, fd, cmd, arg),
_ => errno::fail(errno::EINVAL),
}
}
Expand Down
19 changes: 11 additions & 8 deletions userland/capsule_linux/src/linux/call/cwd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,29 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! Moving the working directory.
/* Moving the working directory. */

use crate::linux::abi::errno;
use crate::linux::file::{look, read_path, visible};
use crate::linux::file::{follow, join, look, read_path};
use crate::linux::guest::{Guest, Kind};

pub fn chdir(guest: &mut Guest, path: u64) -> u64 {
let Some(name) = read_path(guest, path) else {
return errno::fail(errno::EFAULT);
};
let at = guest.links.follow(visible(&guest.cwd, &name), true);
// Checked before it is taken.
let at = follow(guest, join(&guest.cwd, &name), true);
/* Checked before it is taken. */
match look(&at) {
Some(_) => {
Some((_, true)) => {
guest.cwd = at;
errno::ok(0)
}
Some(_) => errno::fail(errno::ENOTDIR),
None => errno::fail(errno::ENOENT),
}
}

/// `fchdir`: the same, named by a directory the guest already opened.
/* `fchdir`: the same, named by a directory the guest already opened. */
pub fn fchdir(guest: &mut Guest, fd: u64) -> u64 {
let Some(entry) = guest.fds.get(fd as usize).filter(|f| f.kind == Kind::Dir) else {
return errno::fail(errno::EBADF);
Expand All @@ -44,8 +45,10 @@ pub fn fchdir(guest: &mut Guest, fd: u64) -> u64 {
errno::ok(0)
}

/// `getcwd` writes the path and returns its length including the terminator,
/// which is what a libc uses to tell success from a buffer that was too small.
/*
* `getcwd` writes the path and returns its length including the terminator,
* which is what a libc uses to tell success from a buffer that was too small.
*/
pub fn getcwd(guest: &Guest, buf: u64, len: u64) -> u64 {
let mut out = guest.cwd.clone();
out.push(0);
Expand Down
22 changes: 16 additions & 6 deletions userland/capsule_linux/src/linux/call/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,29 @@
//! Who the guest is, and which process group it belongs to.

use crate::linux::abi::errno;
use crate::linux::file;
use crate::linux::guest::Guest;

/// The identity every guest runs as.
/* The identity every guest runs as. */
const GUEST_UID: u64 = 0;

/*
* The process that forked this one, as /proc/<pid>/stat names it; the
* personality, the namespace's pid 1, for the program it started. A kernel
* pid: the serve loop gives it the number the namespace knows it by.
*/
pub fn getppid(guest: &Guest) -> u64 {
// The personality is the parent of every guest it hosts.
errno::ok(u64::from(guest.parent))
let parent = file::view_with(|v| {
let me = v.procs.iter().find(|p| p.kernel == guest.pid)?;
v.procs.iter().find(|p| p.ns == me.ppid).map(|p| p.kernel)
});
errno::ok(u64::from(parent.unwrap_or(guest.parent)))
}


/// Setting the identity to the one already held is the only change
/// that can be honoured, so it is the only one accepted.
/*
* Setting the identity to the one already held is the only change
* that can be honoured, so it is the only one accepted.
*/
pub fn setuid(want: u64) -> u64 {
match want {
GUEST_UID => errno::ok(0),
Expand Down
17 changes: 9 additions & 8 deletions userland/capsule_linux/src/linux/call/limits_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,30 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! Which limit each resource number reports.
/* Which limit each resource number reports. */

use crate::linux::file::MAX_FDS;

/// `struct rlimit` is a soft limit then a hard one, both 64-bit.
/* `struct rlimit` is a soft limit then a hard one, both 64-bit. */
pub(super) const RLIMIT: usize = 16;

const RLIMIT_STACK: u64 = 3;
const RLIMIT_NOFILE: u64 = 7;
const RLIMIT_AS: u64 = 9;

/// What a guest's stack is given, from the loader that maps it.
/* What a guest's stack is given, from the loader that maps it. */
const STACK_BYTES: u64 = 1 << 20;

/// The top of the guest's own half, which is the most address space one
/// can hold however it asks.
/*
* The top of the guest's own half, which is the most address space one
* can hold however it asks.
*/
const ADDRESS_SPACE: u64 = 0x0000_7FFF_F000;

/// Unlimited, as Linux spells it.
/* Unlimited, as Linux spells it. */
const INFINITY: u64 = u64::MAX;

pub(super) fn limit_for(resource: u64) -> Option<(u64, u64)> {
pub fn limit_for(resource: u64) -> Option<(u64, u64)> {
match resource {
RLIMIT_STACK => Some((STACK_BYTES, STACK_BYTES)),
RLIMIT_NOFILE => Some((MAX_FDS as u64, MAX_FDS as u64)),
Expand All @@ -47,4 +49,3 @@ pub(super) fn limit_for(resource: u64) -> Option<(u64, u64)> {
_ => Some((INFINITY, INFINITY)),
}
}

3 changes: 3 additions & 0 deletions userland/capsule_linux/src/linux/call/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ mod pipe_end;
mod pipe_io;
mod pipe_poll;
mod pipe_read;
mod process;
mod sched;
mod session;
pub mod sigframe;
Expand Down Expand Up @@ -76,6 +77,7 @@ mod uname;
mod vector;
mod vector_read;

pub use process::*;
pub use ctl::fcntl;
pub use ioctl::ioctl;
pub use cwd::{chdir, fchdir, getcwd};
Expand All @@ -85,6 +87,7 @@ pub use io::{close, read, write};
pub use life::{exit, exit_thread, killed, set_tid_address};
pub use life_one::exit_one;
pub use limits::{getrlimit, prlimit64};
pub use limits_table::limit_for;
pub use glibc::prctl;
pub use glibc_sched::{clone3, getcpu, membarrier, sched_getaffinity};
pub use mem::{brk, mmap, mprotect, mremap, munmap, MapReq};
Expand Down
Loading
Loading