#[non_exhaustive]pub enum ConfigError {
Show 39 variants
RootfsMissing,
RootContradiction,
#[non_exhaustive] RootfsUnusable {
path: PathBuf,
source: Error,
},
RootfsIsHostRoot,
CommandMissing,
#[non_exhaustive] CommandNotAbsolute {
command: PathBuf,
},
#[non_exhaustive] ManagedMountsContradiction {
toggle: &'static str,
},
#[non_exhaustive] SearchPathUnusable {
path: OsString,
},
#[non_exhaustive] BindSourceUnusable {
path: PathBuf,
source: Error,
},
#[non_exhaustive] MountTargetInvalid {
path: PathBuf,
},
#[non_exhaustive] MountFlagsInvalid {
flags: u64,
},
#[non_exhaustive] WorkdirNotAbsolute {
path: PathBuf,
},
HostnameInvalid,
#[non_exhaustive] EnvNameInvalid {
name: OsString,
},
EmbeddedNul,
#[non_exhaustive] SeccompInvalid {
reason: String,
},
#[non_exhaustive] SeccompUnsupportedArch {
arch: String,
},
#[non_exhaustive] SeccompProgramTooLong {
len: usize,
max: usize,
},
#[non_exhaustive] LandlockPathInvalid {
path: PathBuf,
},
#[non_exhaustive] LandlockGrantEmpty {
grant: String,
},
RestrictionEmpty,
#[non_exhaustive] RestrictionLandlockUnenforceable {
abi: Option<i32>,
},
#[non_exhaustive] HostNetworkLandlockUnenforceable {
abi: Option<i32>,
},
#[non_exhaustive] ProfileOperationForbidden {
operation: &'static str,
},
#[non_exhaustive] StreamAttachmentConflict {
stream: &'static str,
attachment: &'static str,
},
#[non_exhaustive] IdentityMapInvalid {
reason: String,
},
#[non_exhaustive] IdentityMapUnavailable {
reason: String,
},
#[non_exhaustive] RunAsUnmapped {
id: u32,
space: &'static str,
},
RunAsGroupsWithSingleMap,
NestedUsernsNeedsProcfs,
#[non_exhaustive] SetidCapWithNonRootIdentity {
capability: &'static str,
},
#[non_exhaustive] OverlayPathInvalid {
path: PathBuf,
},
OverlayLowerMissing,
OverlayUpperMissing,
#[non_exhaustive] OverlayDirUnusable {
layer: OverlayLayer,
path: PathBuf,
source: Error,
},
#[non_exhaustive] OverlayDirUnowned {
layer: OverlayLayer,
path: PathBuf,
},
#[non_exhaustive] OverlayUpperIsRoot {
path: PathBuf,
},
#[non_exhaustive] OverlayUnavailable {
blocker: OverlayBlocker,
},
#[non_exhaustive] RlimitInvalid {
resource: Resource,
soft: Limit,
hard: Limit,
},
}Expand description
A sandbox configuration rejected by CageBuilder::build.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
RootfsMissing
No rootfs was provided.
RootContradiction
A plain rootfs and an overlay root were both configured, where exactly one root can be in force.
The builder’s setters keep the two exclusive — rootfs clears an
overlay and overlay clears a rootfs — so this arises from a profile
that carries both keys. Honoring either one silently would discard the
other’s configuration.
#[non_exhaustive]RootfsUnusable
The rootfs path could not be resolved and opened as a directory.
Fields
This variant is marked as non-exhaustive
RootfsIsHostRoot
The rootfs resolves to the host root directory.
CommandMissing
No command was provided, or the path given names nothing.
An empty path is the second: it is not a command that could not be
found, it is the absence of one written down. Every later check reads it
as something else — it carries no slash, so a path lookup takes it for a
bare name and joining it onto a PATH entry yields that entry — so it is
refused where the command is read rather than deferred to an execve of
a directory.
#[non_exhaustive]CommandNotAbsolute
The command path is not absolute.
The message names the remedy that fits: a bare command name — the most
common form of this mistake — is resolvable with
path_lookup, while a relative path
containing a slash is never searched and must be made absolute.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]ManagedMountsContradiction
The managed mount profile was opted out of, while one of its mounts was explicitly asked for. The two cannot both be honored.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]SearchPathUnusable
Path lookup was requested, but the PATH in force holds no absolute
directory to search, so the command could not resolve to any candidate.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]BindSourceUnusable
A bind-mount source could not be resolved on the host.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]MountTargetInvalid
A mount target is not a normal absolute path inside the rootfs.
A bind or raw-mount target must be absolute, must not be / itself,
and must not contain . or .. components.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]MountFlagsInvalid
A raw mount’s flags do not fit the kernel’s mount-flags word.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]WorkdirNotAbsolute
The working directory path is not absolute.
Fields
This variant is marked as non-exhaustive
HostnameInvalid
The hostname is empty or longer than 64 bytes.
#[non_exhaustive]EnvNameInvalid
An environment variable name is empty or contains =.
Fields
This variant is marked as non-exhaustive
EmbeddedNul
A configured path, name, or value contains an interior NUL byte.
#[non_exhaustive]SeccompInvalid
A seccomp policy could not be compiled into a BPF program.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]SeccompUnsupportedArch
Seccomp filtering is not available for the host architecture.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]SeccompProgramTooLong
A seccomp program is longer than the kernel’s instruction ceiling.
The kernel accepts a classic BPF filter of at most BPF_MAXINSNS
(4096) instructions. A precompiled SeccompPolicy::Program escape
hatch that exceeds it is rejected here rather than being silently
truncated when the filter is installed.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]LandlockPathInvalid
A Landlock grant path is not a normal absolute path.
A grant path must be absolute and must not contain . or ..
components. In a cage it is a sandbox path, resolved after the pivot;
in a restriction it is a host path.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]LandlockGrantEmpty
A Landlock grant names no access at all.
An empty access set is not “grant nothing here”: enrolling any grant denies everything ungranted, and the kernel skips a rule that permits nothing — so an empty grant is a total denial of the class it belongs to. That is never what an author means by naming a path or a port, so it is refused rather than silently applied.
Fields
This variant is marked as non-exhaustive
RestrictionEmpty
A restriction names no Landlock grant and no seccomp policy.
A restriction exists to confine the command; with nothing to enforce it would launch a plain process while appearing to sandbox it, so an empty restriction is rejected instead.
#[non_exhaustive]RestrictionLandlockUnenforceable
A restriction’s Landlock grants cannot be enforced on this host.
A restriction is confined only by what the running kernel enforces. When its Landlock grants all fall outside the supported Landlock ABI — a network grant on a kernel below ABI 4 — or the Landlock LSM is absent, no ruleset applies and the command would run unconfined, so the build is refused rather than silently dropping the requested confinement. A cage in the same case keeps its namespace isolation, so this is specific to the restriction fallback.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]HostNetworkLandlockUnenforceable
A host-network cage requests a Landlock network grant the kernel cannot enforce.
Under Network::Host there is no network
namespace, so a Landlock network grant is the only network boundary.
When the kernel’s Landlock ABI is below 4 (network rights first appear
there) or the LSM is absent, the grant governs nothing and the command
would reach the host network unrestricted, so the build is refused. A
Isolated or None
cage is unaffected: its network namespace remains the boundary.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]ProfileOperationForbidden
A profile loaded under the restricted policy uses an operation only a trusted profile may.
Deserializing a profile straight into a CageBuilder trusts it as
code-equivalent configuration. A profile from an untrusted source is
loaded under the restricted policy instead, which forbids the
operations that map host resources into the sandbox or share a host
namespace: bind mounts, raw mounts, an overlay root, host networking,
and sharing the host PID namespace.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]StreamAttachmentConflict
A launch attaches a conduit to a standard stream the sandbox was built to send somewhere else.
Stdio::Inherit states no destination, so a
launch is free to supply one and this never arises against it.
Stdio::Null and
Stdio::from_fd state one, and a launch that
would supply its own is refused rather than silently overriding what the
caller said. Two launches supply one: an Observer’s
capture pipes, on the output pair, and a terminal launch’s
pseudoterminal replica, on all three at once.
Reported by the launch rather than by
build: the contradiction is between the
frozen sandbox and one particular launch of it, and the same sandbox
launches without contradiction through an entry point that attaches
nothing.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]IdentityMapInvalid
An identity map’s ranges are structurally invalid.
The kernel’s rules are enforced here so an unwritable map is a typed configuration error: both lists non-empty, inside-id 0 mapped, no zero-count or wrapping extents, no overlaps, and at most 340 extents.
Fields
This variant is marked as non-exhaustive
No identity-map delegate can satisfy the requested range map.
The fallback is between delegates, never between tiers: a range
request that no delegate can establish is refused rather than
silently downgraded to the single-identity map. The reason carries
each delegate’s refusal, and the host probe’s diagnosis when
host::range_map_blocker
identifies one.
#[non_exhaustive]RunAsUnmapped
A run-as id is not contained in the identity map.
Every id the command runs as must be representable in the sandbox’s user namespace. Under the single-identity map the only id is 0; a range map contains what its extents say.
Fields
This variant is marked as non-exhaustive
RunAsGroupsWithSingleMap
A run-as identity names supplementary groups under the single-identity map.
Establishing that map requires denying setgroups, so no group list
can ever be set inside it. Supplementary groups need a range gid
map.
NestedUsernsNeedsProcfs
The profile mounts no procfs the nested user namespace’s identity map can be established through.
Every container enters a nested user namespace before it hardens, which is what locks the flags of the mounts it inherited — without it the command is root of the namespace those mounts belong to and may lift any restriction they carry. Establishing that namespace’s map reaches for a procfs by path from inside the sandbox, so a sandbox with no procfs has no way to establish one.
Reachable only from a profile that opts out of the managed mounts with
managed_mounts(false) (or
mount_proc(false)) and mounts no
procfs of its own, and then only where the map’s route reads one. The
single-identity map’s command writes its own map files, and a bind of
the host’s procfs serves it — every instance resolves self for its
reader. A range identity_map is
written by a delegate, and where the sandbox has a PID namespace that
delegate is inside it and needs a fresh procfs, since it names the
command by an in-namespace pid a bound procfs does not index. Where the
sandbox has no PID namespace the delegate is outside it and reads the
host’s own /proc, so no procfs is required at all.
#[non_exhaustive]SetidCapWithNonRootIdentity
A retained set-id capability alongside a non-root run-as identity.
The securebits that preserve kept capabilities across the identity
switch also mean a command holding CAP_SETUID, CAP_SETGID, or
CAP_SETPCAP could return to the mapped uid 0, making the non-root
identity no boundary at all. The combination is rejected by name
rather than shipped as a claim the configuration does not keep.
Fields
This variant is marked as non-exhaustive
#[non_exhaustive]OverlayPathInvalid
An overlay-root path holds a character the overlay mount options cannot carry.
The lower, upper, and work directories are passed to the kernel as a
comma-separated, colon-delimited option string, so a , or : in any of
their resolved paths would be misparsed. Such a path is refused rather
than silently truncated.
Fields
This variant is marked as non-exhaustive
OverlayLowerMissing
An overlay root names no lower layer.
The first lower is the base the overlay mounts over — the sandbox’s root
filesystem — so an overlay carrying only an upper has nothing to merge;
Overlay::lower is required.
OverlayUpperMissing
An overlay root names no upper layer.
An overlay with only lowers is a read-only merge; the sandbox needs
somewhere for its writes to land, so
Overlay::upper is required.
#[non_exhaustive]OverlayDirUnusable
An overlay layer directory could not be prepared.
Every layer is canonicalized, since the mount options name the layers absolutely; the upper and work directories are additionally created when absent, while a stacked lower must already exist. This reports a host failure at either step: a path that does not resolve, a permission refusal, or a path that resolves to something other than a usable directory.
Fields
This variant is marked as non-exhaustive
layer: OverlayLayerWhich layer directory failed.
#[non_exhaustive]OverlayDirUnowned
An overlay layer directory the library would have created was already there, and is not a directory the calling user owns.
The upper and work directories are created if absent, and the caller may name them under a directory it shares with other local users. An entry already at the path is adopted only when it is a directory belonging to the calling user: a symbolic link — which would send every write the sandbox makes to a destination of whoever planted it, and hand that destination back to the caller as the layer its run produced — or a directory owned by someone else is refused instead of used.
Fields
This variant is marked as non-exhaustive
layer: OverlayLayerWhich layer directory was refused.
#[non_exhaustive]OverlayUpperIsRoot
An overlay’s upper layer is the filesystem root.
The upper needs a parent directory: the work directory the library
derives is a sibling of the upper, and the host overlay preflight runs in
that parent so its scratch entries land beside the upper rather than
inside it. / has no parent — and an upper there would put the sandbox’s
writes over the whole host root.
Fields
This variant is marked as non-exhaustive
An overlay-rooted cage was requested on a host that cannot establish an unprivileged overlay mount.
The overlay preflight names what is missing: the running kernel may
predate unprivileged overlay-in-a-user-namespace (Linux 5.11), or the
upper layer’s filesystem may not support the user.* extended-attribute
namespace an unprivileged overlay records its metadata in — which tmpfs
gained only in Linux 6.6, so an on-disk upper (ext4, xfs, btrfs) is the
portable choice.
#[non_exhaustive]RlimitInvalid
A resource limit names a soft value above its hard value.
The kernel refuses such a pair with EINVAL; it is caught here so the
mistake is a typed configuration error rather than a launch failure.
Fields
This variant is marked as non-exhaustive
Trait Implementations§
Source§impl Debug for ConfigError
impl Debug for ConfigError
Source§impl Display for ConfigError
impl Display for ConfigError
Source§impl Error for ConfigError
impl Error for ConfigError
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
The OS failure underneath, for the three refusals that have one.
Every other variant is a request the builder refused on its own terms — a contradiction, a missing field, a path that is not the shape it has to be — where nothing failed and there is nothing to return.
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Source§impl From<ConfigError> for Error
impl From<ConfigError> for Error
Source§fn from(err: ConfigError) -> Self
fn from(err: ConfigError) -> Self
Auto Trait Implementations§
impl !RefUnwindSafe for ConfigError
impl !UnwindSafe for ConfigError
impl Freeze for ConfigError
impl Send for ConfigError
impl Sync for ConfigError
impl Unpin for ConfigError
impl UnsafeUnpin for ConfigError
Blanket Implementations§
Source§impl<T> AsErrorSource for Twhere
T: Error + 'static,
impl<T> AsErrorSource for Twhere
T: Error + 'static,
Source§fn as_error_source(&self) -> &(dyn Error + 'static)
fn as_error_source(&self) -> &(dyn Error + 'static)
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.