Commit Graph

1404 Commits

Author SHA1 Message Date
skaiea13-ai
b4cff719c2 Limit nstun TCP receive buffers with a shared payload budget
Cap retained guest-to-host TCP payload across flows so a stalled sink cannot grow the supervisor toward the per-flow limit times the maximum flow count.
2026-08-22 04:30:29 +09:00
robertswiecki
5ebcc30bef Merge pull request #291 from yexinw-ctrl/statx-unotify-trace
unotify: trace statx
2026-07-27 09:09:09 +02:00
yexinw
c20246ad0a unotify: trace statx
Add statx to the seccomp user-notify traced-syscall table
(unotify/syscall_defs.h::kTracedSyscalls). That table is the single source
of truth -- the kafel policy string and the argument decoder are both
derived from it -- so this one entry is the whole change.

Modern glibc/coreutils (ls, stat) issue statx before falling back to
newfstatat/openat when probing a path. Because statx was not traced, a
stat of a path that is not present in the jail's mount namespace was never
observed at all: under a restrictive mount set, `ls /opt` and `stat /opt`
produced no access record, while openat-based reads (cat, head) were
recorded normally. Tracing statx closes that gap.

statx(dirfd, path, flags, mask, statxbuf) has arg0 = dirfd and arg1 =
path, the same shape as newfstatat, so it reuses the existing DIRFD/PATH
arg roles. Guarded by #ifdef __NR_statx (defined on x86_64 and arm64).
kafel already knows the statx syscall, so no policy-side change is needed.

Tested by running a command under --seccomp_unotify with a mount set that
excludes /opt. Before: `stat /opt` and `ls /opt` did not appear in the
report. After: /opt appears with exists_in_jail:false, exists_in_main:true
via a statx syscall, while a genuinely missing path still reports
exists_in_main:false and an allowlisted path still reports
exists_in_jail:true.
2026-07-27 00:10:11 +00:00
robertswiecki
d6454b4640 Merge pull request #271 from Alvov1/use-core-scheduling
contain: add core scheduling support (PR_SCHED_CORE)
2026-06-18 08:48:14 +02:00
Alexander Lvov
81784bfbac contain: add core scheduling support (PR_SCHED_CORE)
Adds --use_core_scheduling proto flag that calls prctl(PR_SCHED_CORE_CREATE) in the child process, giving each jail its own SMT scheduling group. Prevents sharing a physical core with other tenants and mitigates L1TF/MDS side-channel attacks in multi-tenant environments. Requires Linux >= 5.14; guarded with #ifdef PR_SCHED_CORE for compatibility with older kernel headers.
2026-06-11 10:33:53 +03:00
robertswiecki
1595ebcdf1 Merge pull request #270 from philwo/fix-unused-result
unotify: check return value of TextFormat::PrintToString
2026-05-28 22:27:26 +02:00
robertswiecki
5674c622c4 Merge pull request #269 from philwo/fix/exec-file-clobbered-by-positional-argv
cmdline: stop overwriting --exec_file with positional argv[0]
2026-05-28 22:26:15 +02:00
Philipp Wollermann
7e4a6fb5a6 unotify: check return value of TextFormat::PrintToString
The protobuf API marks PrintToString as nodiscard, so ignoring its
return value broke the build under -Werror=unused-result. Check the
result and bail out with a warning if formatting fails.
2026-05-27 07:24:41 +09:00
Philipp Wollermann
c4f20c7dae cmdline: stop overwriting --exec_file with positional argv[0]
setupArgv() unconditionally called set_path(argv[optind]) when positional
arguments were present after --, clobbering any path previously set via
the -x / --exec_file flag. The intended behavior, documented in the help
text ("File to exec (default: argv[0])"), is for --exec_file to win and
fall back to argv[0] only when not given.

Remove the unconditional set_path; the existing fallback a few lines
below already sets the path from argv[0] when --exec_file was not
provided.
2026-05-24 10:26:35 +09:00
rsc
66ad78dc36 unotify: ignore ENOENT and EINPROGRESS when logging SECCOMP_IOCTL_NOTIF_SEND failures
ENOENT means the thread has moved on (killed or interrupted).
EINPROGRESS indicates either misuse by sending again after
a successful send (which we're not doing) but we also see it
when a process is exiting, perhaps related to thread shutdown.

Authored-by: rsc@google.com
Tested-by: rsc@google.com
2026-05-08 09:41:43 +02:00
rsc
0c95a1f7a9 unotify: fix unotify implementation
Most of the system calls involved in the unotify poll loop were subtly wrong.
The biggest problem was the reuse of the previous message's req.id with
isTargetAlive to decide whether to exit the loop. The loop can be watching
many threads and many processes, any one of which might exit at any time
(especially if the last observed system call was exit!), so it does not make
sense to focus on a specific thread except within the context of a pending
syscall being evaluated.

SECCOMP_IOCTL_NOTIF_ID_VALID is for one purpose and one purpose only:
checking after an access by pid that the pid was not reused, invalidating
whatever was just read. The only time that purpose applies is between
parseSyscall and addStat, which is now the only time that the loop calls
isTargetAlive.

The loop was misusing isTargetAlive to decide when to exit the loop.
Now it correctly waits until a POLLHUP event.

The loop was misusing isTargetAlive to decide whether to call
SECCOMP_IOCTL_NOTIF_SEND. That's going to do the same check itself,
because otherwise there would be a race between the check and the send.
That redundant check is deleted.

The loop was also misusing isTargetAlive after a failed
SECCOMP_IOCTL_NOTIF_SEND to decide whether to exit the loop.
As before, one target being dead does not imply that all the traced targets
are dead, so that check is deleted. On failure, if the error is EINTR,
the send is tried again. If the error is ENOENT, that means the thread is
no longer blocked in the system call (either due to an interrupt or signal),
so we stop the send attempt but continue the processing loop.
Otherwise we print the error error, stop the send, but continue the processing loop.

The hangs seem to have been caused by a few different failure modes:

 1. The loop could have been exiting prematurely, hanging the syscalls
     waiting for judgement.

 2. In one strace log I read carefully, the loop kept running after POLLHUP,
    hanging in SECCOMP_IOCTL_NOTIF_RECV. I believe this may have been
    fixed between 6.6 and 6.12.

 3. The loop was not reacting well at all to send failing because the syscall
    had been interrupted. This manifested as needing to run Go programs
    with GODEBUG=asyncpreemptoff=1 to let them run at all.
    With these changes, Go programs using signals work just fine.

Authored-by: rsc@google.com
Tested-by: rsc@google.com
2026-05-07 06:51:10 +02:00
robertswiecki
9853352c7c Merge pull request #265 from sharadboni/fix/double-free-nl-cache-initParent
net: fix double-free of nl_cache in initParent error paths
2026-05-05 10:22:25 +02:00
robertswiecki
5b52bf10f0 Merge pull request #264 from kiyoungkim-gg/patch-1
Fix ESRCH in sched_setaffinity due to glibc TID caching with clone3
2026-05-05 10:21:58 +02:00
Sharad Boni
831ddd215b net: remove redundant nl_cache_free calls to fix double-free in initParent
initParent registers a defer{nl_cache_free(link_cache)} RAII guard that
runs on all exit paths, but the error returns inside the iface_own loop
and the cloneIface block also called nl_cache_free explicitly, causing
a double-free when moveToNs or cloneIface fails.

Remove the redundant explicit frees; the defer guard is sufficient.
2026-04-27 15:26:17 -07:00
kiyoungkim-gg
a1dd160283 Fix ESRCH in sched_setaffinity due to glibc TID caching with clone3
When nsjail creates a new process in a new PID namespace (CLONE_NEWPID) using the direct kernel syscall clone/clone3 (introduced in d1f332b), glibc's internal PID/TID cache is not updated for the child process.

As a result, calling the glibc wrapper `sched_setaffinity(0, ...)` inside the child process causes glibc to inadvertently pass the cached parent's TID to the kernel instead of 0 (current thread). Since the parent's TID does not exist within the new PID namespace, the kernel returns ESRCH (No such process).

This commit fixes the issue by bypassing the glibc wrapper and invoking the `sched_setaffinity` syscall directly via `util::syscall`. This ensures that `0` is passed accurately to the kernel, referring to the current thread.
2026-04-27 15:02:38 +09:00
Robert Swiecki
6356dee0c6 Makefile/all: make libnl3 optional 2026-04-14 14:26:28 +02:00
Robert Swiecki
bcf9eca738 make depend 2026-04-11 22:09:01 +02:00
Robert Swiecki
57277f38fd configs/znc-with-net.cfg - removing unneeded spaces 2026-04-11 22:07:43 +02:00
Robert Swiecki
a79c21ff9f nsjail.h: restore prematurely removed struct fields 2026-04-11 15:44:46 +02:00
Robert Swiecki
91010b3cdf logs: added tid, plus a help function 2026-04-09 22:48:18 +02:00
Robert Swiecki
b7ff9f3018 util/missing_defs: new support functions + a file defining missing syscall numbers/defs 2026-04-09 22:44:32 +02:00
Robert Swiecki
9043b9da73 unotify: surround syscall table by guards, as they're not implemented on all platforms 2026-04-03 11:38:38 +02:00
Robert Swiecki
16099aebd0 nstun: handle setsockopt failures 2026-04-03 11:28:21 +02:00
Robert Swiecki
ee2d05e874 Integrate a seccomp user notification to trace and log sandboxed filesystem and network operations
* Introduces a dedicated, async worker thread that monitors SECCOMP_RET_USER_NOTIF events
 * Produces telemetry using protobufs to track resolved namespace paths, and network endpoints
2026-04-03 11:20:02 +02:00
Robert Swiecki
4f69b0bffb Makefile: tests inbound connections properly 2026-04-03 02:22:18 +02:00
Robert Swiecki
3c92a17d2b nstun: set IPV6_V6ONLY on IPv6 so it doesn't collide with IPv4 2026-04-03 02:01:11 +02:00
Robert Swiecki
86530d8068 nstun/tcp: set flow_success=true on accept paths so the defer guard doesn't immediately destroy every inbound connection 2026-04-03 01:47:02 +02:00
Robert Swiecki
408d49ed48 mnt: consolidate EROFS fallbacks into errno-preserving helpers 2026-04-02 15:00:33 +02:00
robertswiecki
f1a9dc67b1 Merge pull request #260 from nemmyam/fix-erofs-mkdir-readonly-mounts
mnt: handle EROFS from mkdir/open on read-only mounts
2026-04-02 14:56:14 +02:00
Robert Swiecki
508d9bf3b5 Refactor nstun TCP/UDP state machines and harden IPv6 handling
* Replace switch/goto dispatch with table-driven per-state handlers; deduplicate flow init
 * Eliminate magic numbers - use named constants for buffer limits, timeouts, and struct sizes
 * Block IPv4-compatible IPv6 addresses (SSRF) and cache redirect destinations per-flow

Replace switch/goto dispatch with table-driven per-state handlers; deduplicate flow init
Eliminate magic numbers: use named constants for buffer limits, timeouts, and struct sizes
Block IPv4-compatible IPv6 addresses (SSRF) and cache redirect destinations per-flow
2026-04-02 14:03:31 +02:00
Robert Swiecki
68832ab865 nstun: remove dead code, and change some functions to static 2026-04-02 01:31:57 +02:00
Robert Swiecki
1984f83a45 nstun/tcp: remove dead mss/window code 2026-04-02 01:18:26 +02:00
Robert Swiecki
15f730cdba nstun: handle EPOLLHUP/EPOLLERR for TCP 2026-04-02 00:59:14 +02:00
Robert Swiecki
15e16bc93b nstun: make Flow a base clase, with derivative classes for each supported proto 2026-04-02 00:52:22 +02:00
Robert Swiecki
1695944e40 tests - config for TCP/UDP redirection 2026-04-01 21:55:53 +02:00
Robert Swiecki
b6bf68c4c1 nstun: Harden networking stack and modernize to C++20
- Migrate TCP/UDP flow management to std::unique_ptr and packet parsing to std::span
- Add mandatory checksum validation for UDP (IPv4 optional, IPv6 per RFC 8200), closing parity with TCP/ICMP
- Handle IPv6 Authentication Header (AH) in extension header parser to prevent firewall rule bypass
- Add defense-in-depth MTU cap in tcp_process_data to prevent int32_t overflow in sequence arithmetic
- Fix uint16_t port loop overflow in HOST_TO_GUEST listener setup (infinite loop when dport_end=65535)
- Block SSRF via forged loopback/v4mapped destinations in both IPv4 and IPv6 TCP/UDP paths
- Extract policy evaluation and proxy encapsulation into standalone policy.cc and encap.cc modules
- Replace all raw inet_ntop+char[] patterns with ip4_to_string/ip6_to_string helpers
2026-04-01 19:38:13 +02:00
Robert Swiecki
2b1f4b0241 Makefile: reenable socks tests 2026-03-31 23:56:42 +02:00
Robert Swiecki
0381754dfc nstun: add support for ENCAP_CONNECT - http connect encapsulation 2026-03-31 23:54:57 +02:00
Robert Swiecki
ea5d664561 nsjail: increase RLIMIT_NOFILE to min 8192 2026-03-31 08:32:40 +02:00
Robert Swiecki
e49f75c528 Makefile: improved test (wget) for socks5 2026-03-31 07:51:59 +02:00
Robert Swiecki
5151646146 nstun: IPv6 implementation 2026-03-31 07:49:52 +02:00
Robert Swiecki
0f8b4a389e nstun: IPv6 implementation 2026-03-31 06:55:27 +02:00
Robert Swiecki
17836b71a3 nstun: use writev 2026-03-30 17:05:21 +02:00
Robert Swiecki
6b850698a5 nstun: use designated initializers with structs 2026-03-30 13:03:13 +02:00
Robert Swiecki
6c7788d62a nstun: add missing TCP state - TcpState::CLOSING 2026-03-30 11:17:16 +02:00
Robert Swiecki
2ee9590ba6 nstun: use redirect_port correctly for REDIRECT's 2026-03-30 09:39:04 +02:00
Robert Swiecki
53584b422e nstun: centralize src ip address checks to ip.cc 2026-03-30 09:25:37 +02:00
Robert Swiecki
033adf6128 nstun: faster downloads by draining upstream TCP sockets 2026-03-30 09:00:05 +02:00
Robert Swiecki
a2bd0b0ad1 nstun: Implement HOST_TO_GUEST forwarding 2026-03-30 07:12:52 +02:00
Robert Swiecki
1d5282c23c net: remove encap for traffic rules (ip-route), it can be done via a backend 2026-03-29 14:37:19 +02:00