diff --git a/src/header/fcntl/mod.rs b/src/header/fcntl/mod.rs index 4abdb6baf0..2036d71a1b 100644 --- a/src/header/fcntl/mod.rs +++ b/src/header/fcntl/mod.rs @@ -51,6 +51,46 @@ pub const F_OFD_SETLKW: c_int = 38; /// Duplicate file descriptor with the close-on-exec flag `FD_CLOEXEC` set. pub const F_DUPFD_CLOEXEC: c_int = 1030; +// File sealing (Linux ABI values). Seals are a property of the underlying +// memory object, enforced against every holder of the descriptor across dup() +// and across processes. Redox has no such object yet: there is no +// memfd_create, and no scheme services a seal mask, so `fcntl` reports these +// as unsupported (EINVAL) rather than accepting them. +// +// That refusal is the correct, Linux-compatible behaviour -- Linux likewise +// returns EINVAL for F_ADD_SEALS on any fd whose backing object cannot seal. +// Callers are expected to cope; kwin's utils/ramfile.cpp, for instance, notes +// "This can fail for QTemporaryFile based on the underlying file system" and +// degrades to an unsealed mapping. +// +// DO NOT make these succeed without enforcement. A caller that seals a buffer +// it then shares with a less-trusted process is relying on the seal to hold; +// reporting success without enforcing it converts an honest failure into a +// silent one. +// +// Implementing them for real means giving Redox a sealable object. On a +// microkernel that belongs in a userspace scheme, not the kernel: a `memfd:` +// scheme owning the memory and checking a per-object monotonic seal mask in +// its write/ftruncate/fmap handlers, with F_ADD_SEALS/F_GET_SEALS routed to it +// from Sys::fcntl. See local/docs/ for the workstream note. +/// Add seals to the underlying memory object. Unsupported on Redox: EINVAL. +pub const F_ADD_SEALS: c_int = 1033; +/// Query the seals set on the underlying memory object. Unsupported: EINVAL. +pub const F_GET_SEALS: c_int = 1034; + +/// Prevent any further seals from being set. +pub const F_SEAL_SEAL: c_int = 0x0001; +/// Prevent the object from being shrunk. +pub const F_SEAL_SHRINK: c_int = 0x0002; +/// Prevent the object from being grown. +pub const F_SEAL_GROW: c_int = 0x0004; +/// Prevent writes to the object. +pub const F_SEAL_WRITE: c_int = 0x0008; +/// Prevent future writes while leaving existing mappings writable. +pub const F_SEAL_FUTURE_WRITE: c_int = 0x0010; +/// Prevent the object from being mapped executable. +pub const F_SEAL_EXEC: c_int = 0x0020; + // Used for `l_type` to describe the type of lock { /// Shared or read lock. pub const F_RDLCK: c_int = 0; @@ -116,7 +156,7 @@ pub unsafe extern "C" fn fcntl(fildes: c_int, cmd: c_int, mut __valist: ...) -> // c_ulonglong let arg = match cmd { F_DUPFD | F_SETFD | F_SETFL | F_GETLK | F_SETLK | F_SETLKW | F_OFD_GETLK | F_OFD_SETLK - | F_OFD_SETLKW | F_DUPFD_CLOEXEC => unsafe { __valist.next_arg::() }, + | F_OFD_SETLKW | F_DUPFD_CLOEXEC | F_ADD_SEALS => unsafe { __valist.next_arg::() }, _ => 0, }; diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index fa4d461efc..152edf7377 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -569,6 +569,18 @@ unsafe { &mut *(args as *mut flock) }; return Ok(0); } + fcntl::F_ADD_SEALS | fcntl::F_GET_SEALS => { + // File sealing needs an object that enforces the seal mask against + // every holder of the fd, in every process. Redox has none yet, so + // refuse explicitly instead of letting an unrecognised command + // reach the kernel, where its meaning is undefined. + // + // EINVAL is what Linux returns for a non-sealable object, so callers + // that already handle unsealable backing stores work unchanged. + // Do not turn this into Ok(0) -- see the note in header/fcntl/mod.rs. + return Err(Errno(EINVAL)); + } + _ => {} }