Repository navigation
Upgrading from 0.4
Security and correctness release. The API is additive, but some behavior changed (see Changed):
guard::OpenOptionsnow rejectscreate/create_newwithout write or append,truncatewithout write, andtruncatewithappend(JailError::InvalidPath), matchingstd::fs::OpenOptions.Jail::joinreports permission and I/O errors asJailError::Ioinstead of treating the component as nonexistent.FdJail::check_pathperforms a real containment check, returns your path rather than a symlink-resolved one, and fails if the jail root was replaced.
Security fixes, upgrade recommended:
- On ARM, AArch64, PowerPC and m68k Linux, 0.4.0 used the wrong
O_NOFOLLOWvalue insecure-openand theguardfallback, so a final-component symlink could be followed. - On Linux aarch64, the
guardopenat2 path used x86_64 values forO_DIRECTORY/O_NOFOLLOWwhen pinning the jail root.
For untrusted trees, open with .require_regular_file(true).reject_hard_links(true); both are opt-in.
What's new
Added
- Linux x86_64/aarch64
guardoperations for fd-relative directory creation,
file/directory removal, and rename (FdJail::create_dir,remove_file,
remove_dir,rename). Parent directories are pinned with
openat2(RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS)before the matching*at
syscall executes.*_withvariants take the newResolveOptionsto apply
no_symlinks/no_xdevto parent resolution. A trailing/,/.or/..
is rejected rather than normalized away. OpenOptions::require_regular_file()andOpenOptions::reject_hard_links()
handle policies for guarded opens, checked withfstaton the opened handle.
Failures return the newJailError::FileTypeRejectedand
JailError::HardLinkRejectedvariants. With either policy set, the open uses
O_NONBLOCKso a FIFO in the jail cannot block the caller (cleared again
before the handle is returned),truncateis deferred until the policies
pass (so an already hard-linked file is not emptied; the check is
point-in-time, not race-free), and directories are exempt from the
hard-link check.GuardedFile::opened_metadata()andGuardedFile::file_kind()expose the
point-in-time metadata captured at open, with the newguard::FileKindenum.FdJail::try_clone()for services that need to handle file-descriptor
exhaustion without the panic inherent in theClonetrait.
Changed
OpenOptionsrejects invalid access combinations on every platform, matching
std::fs::OpenOptions:create/create_newwithout write or append,
truncatewithout write, andtruncatewithappendnow return
JailError::InvalidPathinstead of being passed to the kernel.Jail::join(and everything built on it) propagates metadata and permission
errors asJailError::Ioinstead of treating the component as nonexistent.
Symlink loops are still reported asBrokenSymlink.FdJail::check_path()now performs a point-in-time containment check instead
of only validating the string: it rejects traversal and symlink escapes,
rejects a jail root replaced sinceFdJail::new(device and inode), and
returns the caller's path rather than a symlink-resolved one. On Linux,
existing paths are resolved with the sameopenat2rules asopen, so
absolute and magic symlinks thatopenrejects are rejected here too.FdJail::newfails withUnsupportedKernelwhen a seccomp/LSM policy
answersopenat2withEPERM, instead of succeeding and failing every
later call.- Guarded opens on Linux pass
O_NOCTTY.
Fixed
- Correct architecture-specific
O_NOFOLLOWvalues on Linux/Android in both
secure-openand the guard fallback; incorrect constants could silently
follow a final symlink on ARM-family targets. - Correct
O_DIRECTORY/O_NOFOLLOWfor the openat2 path on Linux aarch64,
where the x86_64 values meanO_DIRECT/O_LARGEFILE. The pinned root dirfd
previously lackedO_DIRECTORY | O_NOFOLLOWon aarch64. - Linux guarded opens with read and write/append use
O_RDWRinstead of
O_WRONLY. openat2retries transientEAGAINfrom..resolution races.- The guard API accepts non-UTF-8 Unix paths.
Documentation
- README and crate examples for uploads and web frameworks use the guard API
(FdJailwithrequire_regular_file/reject_hard_links) instead of
validate-then-std::fs::write; path-only examples now state that the write
is a separate, unpinned step. - Correct magic-link errors to
SymlinkRejected, compile the signing adapter
example, publish all-feature docs on docs.rs, and document v1 attestation
replay limitations.
CI
- Runtime tests under QEMU for i686, powerpc, powerpc64le, riscv64gc and
s390x; compile/lint checks for Android, FreeBSD, NetBSD, loongarch64,
sparc64 and illumos; the full suite on a FreeBSD 14 VM; a native arm64
runner for the guard suite. - Scheduled fuzzing of arbitrary path bytes and a privileged bind-mount test
forRESOLVE_NO_XDEV.
Full changelog: v0.4.0...v0.5.0