Peios Learn
Products
PePeios pkpekit PvProvium UDUniversal Directory TrTrail Ckclackatoo PrProject WiWispist
Using Peios Security Basics Technical Documentation Source
Using Peios Security Basics Technical Documentation Source
Peios

Mount policies

Single-page view · as markdown

Mount policies

Peios / Using Peios / Mount policies

Choose a mount policy before attaching a filesystem. It determines what Peios does when a file has no security descriptor (SD): deny access, derive a temporary SD, or derive one and save it. A valid stored SD still supplies the file's access rules, and a corrupt SD is denied under every managed policy.

Start by inspecting the devices and current mounts:

lsblk
mount

Match the intended filesystem to its stable device name, then choose a class below. For a new system filesystem, format it with an SD before using deny-missing. For an existing volume, check whether its descriptors were preserved before choosing a strict policy.

The four classes at a glance #

Your taskClassResult when an SD is missing
Use a provisioned system or application filesystemfacs_deny_missingDeny SD-based access. Root, /home and /var are described as strict system mounts.
Read removable media, FAT/exFAT, or a volume without writing back synthesised SDsfacs_synthesize_ephemeralDerive an SD in memory; do not write it back. A cold inode needs synthesis again.
Adopt a filesystem into Peios and store descriptors as files are accessedfacs_synthesize_persistentDerive an SD and schedule write-back. Verify stored SDs before switching to deny-missing.
Use kernel pseudo-filesystems such as /proc and /sysunmanagedFACS does not apply; the kernel's per-operation checks still do.

Only the three managed classes are administratively settable. unmanaged is reserved for the kernel, and StrataFS has a fixed deny-missing policy. See Policy classes for failure and recovery conditions.

Why mount policies exist #

A managed access check needs an SD, but storage differs: ext4 needs ea_inode for large descriptors, XFS supports large xattrs, tmpfs loses its contents on unmount, FAT/exFAT cannot store xattrs, and an NFS client may not receive the server's descriptors. Choose a policy that fits both the filesystem's storage and whether you intend to change its metadata. Check SD storage by filesystem before adopting a volume.

Per-superblock, not per-path #

The policy belongs to the underlying filesystem instance (the superblock). All paths and bind mounts sharing that instance share its policy, including a read-only bind and its read-write source. Binding /etc/peios at /old/etc/peios does not create an independent policy boundary.

Separate superblock instances can have different policies. Do not assume that a second mount of the same device creates one: the mount reference describes superblock reuse and --exclusive, including its restrictions for writable block devices.

What the policy decides #

For managed filesystems, it selects the missing-SD behaviour, the optional mount-level synthesis template, and whether synthesised SDs are saved. Synthesis tries parent inheritance, then the mount template, then the fallback. The class applies to the whole superblock; it is not a per-file permission.

What the policy does not decide #

  • File data persistence and available operations still depend on the filesystem.
  • Changing policy does not rewrite stored SDs or change already-open handles' cached access masks. Future access checks use the new policy.
  • A policy change does not propagate into another mounted filesystem below the same directory tree.
  • Ephemeral SD synthesis prevents synthesis write-back, not other disk writes. Select read-only separately when required, and read the inspection warning: a read-only filesystem mount alone can still replay an ext4 journal.

Where to start #

  1. Choose the class using Policy classes.
  2. Check storage and preservation requirements in SD storage by filesystem.
  3. Use Managing mounts to apply the choice, verify the result and interpret failures.

The commands #

  • lsblk: inspect block devices, filesystems and SD-derived owner/mode.
  • mount: list mounts, or attach a filesystem with policy= and an optional synthesis template.
  • umount: detach by mount point or source. Read its lazy, forced, recursive and all-targets behaviour before using those variants.

Policy classes

Peios / Using Peios / Mount policies

Choose the class for the files you expect to find, then verify that expectation: use deny-missing for provisioned storage, ephemeral synthesis when SDs must not be written to the volume, and persistent synthesis to adopt existing files. Changing class is not a bulk conversion and does not repair corrupt descriptors.

The command-line spellings are policy=deny-missing, policy=synth-ephemeral and policy=synth-persist; see Managing mounts for application and privilege requirements.

facs_deny_missing #

Use this for a filesystem whose files are expected to carry valid SDs, including provisioned system mounts such as root, /home and /var. The base-image build is expected to supply descriptors, and subsequent creation inherits from the parent. A restore that skips security metadata breaks that expectation.

A missing SD produces -EACCES for operations requiring an SD-based access check. Ordinary reads, writes, deletion and permission changes can therefore fail before you can repair the file through the usual path.

Important

The original operator description says to use kacs_set_sd with WRITE_DAC, while warning that the caller may be unable to acquire the required access. The kernel reference separately documents an O_PATH/AT_EMPTY_PATH repair route under SeRestorePrivilege, and intermediate-traverse exceptions. Follow the documented repair contract for the deployed version; do not assume an inaccessible file can be repaired merely by changing its mount policy.

Before switching an adopted volume to this class, verify stored SDs on the files you need, including files that ordinary usage may never have touched.

facs_synthesize_ephemeral #

Use this when the filesystem cannot store SDs or when reading it must not add security metadata. Typical uses include removable media, FAT/exFAT and NFS client mounts. The kernel reads a stored SD if one exists; otherwise it derives one through the synthesis chain below and uses it for the access check.

The result is cached only while the inode is in memory. It is never written back. After eviction, a later open synthesises again; unchanged inputs produce the same SD. This costs work on a cold inode, but leaves on-disk metadata alone. It does not prohibit writes to file contents: read-only mounting is separate.

Earlier guidance also lists tmpfs/devtmpfs here. The kernel TRM documents stricter defaults for those filesystems; check the filesystem-specific notes rather than assuming their class.

facs_synthesize_persistent #

Use this to adopt a volume whose missing descriptors should become persistent. The first access derives an SD, uses the cached value immediately, and schedules write-back. A later access reads the stored SD after write-back succeeds.

Write-back is deferred until the triggering operation finishes, normally before its syscall returns to userspace. It is best-effort, not evidence that every file now has a stored descriptor. If the entry is evicted or the task exits first, the next access derives the same value and retries. A policy/template change before write-back discards the pending value and derives against the new inputs, rather than saving a superseded SD.

This is incremental adoption: regularly used files acquire SDs first; rarely-used files wait until accessed. Once all required files have stored SDs, you can switch to deny-missing. Any stragglers become inaccessible to normal SD-based operations. Existing stored descriptors are unaffected.

For the locking and task-work mechanism, use the kernel write-back reference.

unmanaged #

This class is reserved for kernel-managed pseudo-filesystems. It skips FACS, not all security checks:

  • /proc/<pid>/* uses process-SD and PIP checks under the two-check rule.
  • /sys uses the kernel's per-operation rules, including writes restricted to BUILTIN\Administrators and SYSTEM.
  • /sys/kernel/security/kacs/* has explicit descriptors maintained and read by the kernel's own logic.

kacs_set_mount_policy rejects unmanaged with -EINVAL; operators cannot use it to disable FACS on a regular filesystem. An ephemeral policy with a permissive template can grant broad access to files missing SDs, but still runs FACS and must be reviewed as a security change. It is not a substitute for repairing a broken descriptor.

The synthesis chain #

When a managed synthesis policy finds no SD, it tries these sources in order:

  1. Parent-directory inheritance, using inheritable ACEs as for a newly-created child. See Inheritance.
  2. The mount-level template, commonly needed at the filesystem root where no parent on that filesystem supplies a usable descriptor.
  3. The fallback: owner and group SYSTEM; GENERIC_ALL for SYSTEM and BUILTIN\Administrators; GENERIC_READ | GENERIC_EXECUTE for Everyone.

A missing template does not imply private access: the fallback grants other users read-and-execute. Review the template before exposing a volume. Earlier notes call the template limit 64 KB; the kernel contract specifies at most 65,535 bytes.

The kernel synthesis reference also specifies recursive parent synthesis, a 32-ancestor limit that fails closed with EACCES, and creator inputs independent of the accessor's token. Use that reference for implementation details.

Corrupt SD handling #

A stored SD that fails structural validation produces -EACCES under all three managed classes. Bad headers, malformed ACLs, invalid SIDs and oversized values do not trigger synthesis. Missing and corrupt are different conditions.

The kernel emits a corruption audit event once per inode per cache population, not on every repeated access. A restore producing many corrupt SDs may therefore produce a burst of events as files are first accessed.

Changing to a synthesising policy does not make a corrupt SD valid. Recovery requires fixing the descriptor or accepting denial. The kernel repair reference documents set-security under SeRestorePrivilege and offline xattr repair on an unmounted filesystem.

Class transitions #

TransitionCheck before changing
Persistent synthesis to deny-missingConfirm the required files have stored SDs; files still missing one will be denied.
Ephemeral to persistent synthesisConfirm that saving metadata is intended and supported. Each later missing-SD access saves its newly derived result.
Deny-missing to a synthesis classTreat this as a deliberate relaxation for recovery/adoption. Review the template; corrupt SDs remain denied.

A transition changes policy only; no files are touched at that moment. Future accesses re-evaluate stale synthesis state. Existing handles keep their masks, and stored SDs remain unchanged. See Managing mounts before applying the change.

Where to go next #

  • SD storage by filesystem: verify where descriptors can persist.
  • Managing mounts: apply and read back the class and template.
  • mount: exact attach-time options.

SD storage by filesystem

Peios / Using Peios / Mount policies

Before choosing a mount policy or restoring a backup, check whether the target can store security descriptors and whether your copy path preserved them. A successful file-data copy is not enough to make a deny-missing volume usable.

Validate descriptor preservation #

  1. Identify the source and destination filesystem types with lsblk and the live mount listing.

  2. For mounted files, inspect effective permissions through sd, which uses the security API. This does not establish that an SD is stored: a synthesis mount can return a usable in-memory descriptor while the canonical xattr is still absent. Direct operations on the canonical SD xattr are sealed.

  3. For an offline ext image or unmounted ext filesystem, check the root xattr:

    debugfs -R "ea_list <2>" /dev/vda2
    

    Replace the example device only after identifying the target. This confirms presence on inode 2, not validity or coverage of every copied file.

  4. Verify stored descriptors on child files and directories as well, using filesystem-appropriate offline inspection on an unmounted target; do not use mounted sd output alone as a persistence test. Include explicit ACLs, private data and rarely accessed files. Persistent synthesis schedules best-effort write-back, so a successful access is not proof it completed. The mke2fs -d path uses user.peios.sd as its source carrier; ordinary canonical-xattr copying is not a substitute for that population contract.

  5. If metadata is missing, choose a deliberate repair/adoption plan before enabling deny-missing. If it is corrupt, synthesis will not repair it.

The sections below retain filesystem-specific storage details. Where the operator guide and kernel reference disagree, the discrepancy is called out; verify the deployed version before depending on that behaviour.

The canonical xattr #

For filesystems that support extended attributes, Peios stores the SD in the security.peios.sd xattr. The name is in the security.* namespace, which requires privileged access to read or write at the filesystem layer — which doesn't matter for FACS-managed access (FACS denies direct xattr operations on the SD xattr unconditionally; access goes through kacs_get_sd / kacs_set_sd), but does mean the xattr survives operations that respect security xattrs.

For NTFS, the xattr name is system.ntfs_security — the native NTFS security attribute, accessed through the same xattr interface. Using the NTFS-native name means SDs round-trip cleanly between Peios and other operating systems that read NTFS.

The choice of xattr name is filesystem-specific:

Filesystemxattr name
ext4, XFS, Btrfs, tmpfs, others with generic xattr supportsecurity.peios.sd
NTFS (via the ntfs3 driver)system.ntfs_security

For other filesystems (with no xattr support or no convention), the SD is held in memory and re-synthesised on each cold open. See the per-filesystem sections below.

ext4 #

ext4 supports xattrs in the inode body and in a separate xattr block. The inode's available inline space is not 4 KB: it depends on inode size and other metadata. The separate block is commonly 4 KiB and also has overhead and may hold other attributes. See the upstream ext4 storage layout.

The ea_inode feature stores a large xattr value in a separate inode when it does not fit in the inode body or external block; see large extended attribute values. The Peios guide documents support up to the 65,535-byte SD limit with this feature, enabled at creation or later through tune2fs.

mke2fs on Peios enables ea_inode by default for ext4, and raises the inode size to 512 bytes so that a typical SD fits inline in the first place — see mke2fs. Complex or deeply inherited ACLs can outgrow the available xattr space; ea_inode accommodates large values without assuming a universal inline limit.

If an ext4 filesystem without ea_inode cannot fit an SD in its available inode-body or external-block xattr space, the filesystem's xattr write fails. The kernel handles this by either:

  • Refusing the kacs_set_sd call with an error indicating the filesystem cannot hold the SD.
  • Or, in the facs_synthesize_persistent case, refusing the write-back and treating the file as if it has no SD (re-synthesising next time).

Check whether ea_inode is enabled when large descriptors cannot be stored. Do not assume that a typical descriptor fitting inline proves every descriptor on the volume will fit.

XFS #

XFS supports xattrs natively, up to 64 KB per attribute by default. This is comfortably more than the SD size limit (65,535 bytes), so SDs fit without any special configuration.

XFS is a fine choice for FACS-managed filesystems. No ea_inode-style consideration is needed; SDs just work.

Btrfs #

Btrfs supports xattrs, but do not assume any practical SD size will fit. Upstream Btrfs documents xattr items in tree leaves, with attributes sharing a name hash required to fit in one leaf. This does not support the original guide's claim that large xattrs receive their own extents. Peios-specific support for larger descriptors has not been verified. Validate the actual descriptor sizes on the target before depending on a restore or persistent-synthesis workflow.

Btrfs's snapshot and clone behaviour is interesting for SDs: a Btrfs snapshot of a directory includes the SDs of every file within. A snapshot is a point-in-time view; the SDs in the snapshot reflect what they were when the snapshot was taken. If the original files' SDs are subsequently modified, the snapshot still has the old SDs. This is the expected behaviour but worth noting for backup/snapshot workflows.

tmpfs and devtmpfs #

Warning

The original guidance below describes ephemeral synthesis and udev-provided descriptors. The kernel reference instead documents deny-missing defaults for TMPFS_MAGIC, including devtmpfs, with kernel-seeded roots. Confirm the mounted instance's actual policy and descriptors; do not assume udev or synthesis supplied them.

tmpfs is an in-memory filesystem. It supports xattrs, but everything it stores lives in RAM and is lost on unmount or reboot. SDs on tmpfs are present while the filesystem is mounted; they vanish when it is unmounted.

tmpfs is typically mounted with facs_synthesize_ephemeral. The synthesis happens in memory anyway (the tmpfs storage is memory), so there's no operational difference between "store an SD in the tmpfs xattr" and "synthesise an SD into the kernel's per-inode cache".

devtmpfs is the kernel-managed filesystem for device nodes. SDs on devtmpfs are applied by udev rules, not by FACS-driven synthesis. The udev daemon (or its Peios equivalent) sets the SD on each device node as the node is created. This is a different model from the synthesis-based pattern other filesystems use; it works because the device-node population is controlled centrally and the SDs can be set deterministically.

devtmpfs uses the facs_synthesize_ephemeral class, but in practice the synthesis path is rarely hit because udev provides the SDs.

NTFS — round-trip via ntfs3 #

Note

An unknown principal and a missing descriptor are not interchangeable. The guide's rationale below mentions unrecognised Windows principals; the kernel reference identifies a specific missing-$Secure case. A valid stored SD is evaluated; a corrupt one is denied even under ephemeral synthesis.

NTFS is the Windows-native filesystem. Peios mounts it through the ntfs3 kernel driver, which exposes the NTFS security attribute via the standard xattr interface under the name system.ntfs_security.

The implications:

  • SDs written by Peios to an NTFS volume use the same on-disk format as Windows. A Windows system reading the same volume sees the SD natively.
  • SDs written by Windows to an NTFS volume are readable by Peios. Round-tripping a volume between the two operating systems preserves SDs.

This is the "binary-compatible" property the SD format gives. The wire format is the same; the filesystem driver translates between the xattr interface and the on-disk security attribute.

NTFS volumes are typically mounted facs_synthesize_ephemeral rather than facs_deny_missing. The reasoning: an NTFS volume from Windows may have files without Peios-recognised SDs (the SDs are Windows-native and may use principals that don't exist on the Peios system). Ephemeral synthesis lets such files be accessible without modifying the volume's stored SDs.

FAT and exFAT #

FAT and exFAT have no xattr support at all. There is no place to store an SD; the on-disk format simply doesn't have the metadata channel.

FACS handles this by using facs_synthesize_ephemeral for FAT/exFAT mounts. Every file gets a synthesised SD in memory; no SD is ever written back. The synthesised SD applies for the file's time in the inode cache; when the file is evicted, the SD is gone and will be re-synthesised on next access.

This means FAT/exFAT files cannot be given persistent KACS-style permissions. The synthesised SD is the same every time (assuming the same inputs — parent SD, mount template), so the access decision is deterministic, but there is no way to customise per-file.

For most FAT use cases this is fine — FAT is typically used for removable media or boot partitions where uniform-permissions semantics is acceptable. The mount-level SD template can be configured to grant whatever access pattern is appropriate for the mount as a whole.

NFS — synthesise locally, enforce remotely #

NFS client mounts are a unique case. The actual files live on a remote server; the local filesystem driver is a network protocol implementation, not a real filesystem.

The mount class is facs_synthesize_ephemeral. FACS synthesises a local SD per the synthesis chain (typically yielding a sensible default from the mount template) and uses it for local access control. The local FACS check decides whether to forward the operation to the server.

If the local check passes, the operation goes to the server. The server has its own access control (potentially also Peios with FACS, potentially another OS with different rules); the server's access control decides whether the operation actually proceeds. If the server denies, the operation fails with whatever error the protocol returns (typically -EACCES or -EIO).

This is "dual authority" — both client and server have a say. The client's denial is local-final; the server's denial is remote-final. There is no single source of truth for the access decision.

The implications were covered in Special cases under "NFS — dual authority": don't trust local FACS results for security, expect I/O errors from server-side denial, the local synthesised SD is not the server's actual SD.

/proc and /sys #

/proc and /sys are kernel pseudo-filesystems. Their mount-policy class is unmanaged — set by the kernel at boot, not changeable via the public ABI.

/proc doesn't have an SD per-file in the FACS sense. Access to /proc/<pid>/* is gated by the per-process rules (process SD + PIP, from the two-check rule). The kernel implements these checks directly when serving /proc file operations.

/sys similarly has its own per-file rules. The /sys/kernel/security/kacs/* entries have explicit SDs the kernel maintains; other /sys files have hardcoded rules ("writes restricted to BUILTIN\Administrators and SYSTEM").

The unmanaged class is what tells FACS to not interfere with these. The kernel knows what it is doing with its own pseudo-filesystems; FACS stays out of the way.

Stacked filesystems — overlayfs and StrataFS #

Warning

The forwarding description below includes StrataFS, but the StrataFS kernel contract says it does not ask a provider's policy to synthesise a missing descriptor: access through StrataFS is denied. Do not rely on a readable direct stratum path proving the merged path is readable. The live-boot example also assumes an explicitly synthesising squashfs; the kernel default is deny-missing and requires descriptors in the image.

A stacking filesystem presents files that physically live somewhere else. overlayfs merges a read-only lower layer with a writable upper one; StrataFS composes several directories into one view. Neither stores a security descriptor of its own, and neither needs to: the descriptor belongs to the file, and the file is on the layer underneath.

So a stack forwards. When the kernel needs the SD of a file in the merged view, it asks the layer that actually holds it, and what comes back is that layer's effective descriptor — which is to say, whatever an access check on the underlying file would have used. If the layer underneath stores an SD, the stack sees the stored one. If the layer underneath synthesises, the stack sees the synthesised one. Synthesis composes upward through the stack; it is not a private arrangement between the kernel and the bottom layer.

That is what makes the common live-boot arrangement work:

overlay          <- the merged root, facs_deny_missing
  upper: tmpfs   <- writable scratch, stores real SDs
  lower: squashfs <- read-only image with no SDs, facs_synthesize_ephemeral

The overlay stores nothing and can still be facs_deny_missing, because neither layer beneath it ever answers "missing": the tmpfs has stored descriptors, and the squashfs synthesises one for every inode.

Two consequences worth holding onto:

The stack's own policy class governs only what happens when every layer beneath it has nothing to offer. Pick it for that case. Over a synthesising lower, facs_deny_missing is the strict-and-correct choice; over an unmanaged lower it would lock the whole view.

A copy-up does not carry the lower's descriptor up with it. When overlayfs copies a file from the lower layer to the upper to make it writable, it creates a genuinely new inode in the upper, and that inode gets its descriptor by ordinary inheritance from its parent in the upper — not by duplicating the lower's. This is deliberate: security.peios.sd is not userspace-writable (SD mutation is kacs_set_sd's job), so a verbatim copy could not be performed even in principle, and the inherited answer is the right one anyway. Every other extended attribute is copied up normally.

Summary #

FilesystemSD storageTypical mount class
ext4security.peios.sd xattr; ea_inode for large valuesfacs_deny_missing (for system mounts)
XFSsecurity.peios.sd xattr, native large supportfacs_deny_missing
Btrfssecurity.peios.sd xattr; verify size limitsfacs_deny_missing
tmpfssecurity.peios.sd xattr in memoryfacs_synthesize_ephemeral
devtmpfsxattr in memory, populated by udevfacs_synthesize_ephemeral
NTFS (ntfs3)system.ntfs_security xattr, NTFS-nativefacs_synthesize_ephemeral (typical)
FAT / exFATNo SD storage; in-memory onlyfacs_synthesize_ephemeral
NFS clientNo client-side storage; synthesise locallyfacs_synthesize_ephemeral
squashfsNo SD storage unless the image was built with onefacs_synthesize_ephemeral
overlayfsNone of its own — reads the real layerfacs_deny_missing
StrataFSNone of its own — reads the providerfacs_deny_missing, not settable
/procn/a — no FACSunmanaged
/sysn/a — kernel-managed SDsunmanaged

Treat the table as the original guide's typical-policy summary, not proof of the policy on a running mount. tmpfs/devtmpfs, squashfs and StrataFS have important source discrepancies noted above. Read back the actual policy before relying on it.

Where to go next #

For what each policy class does with a missing SD, read Policy classes.

For setting and reading a mount's policy at runtime, read Managing mounts.

For the structure of the SD being stored, read Security descriptors.

Managing mounts

Peios / Using Peios / Mount policies

Identify the filesystem and inspect its current state before attaching storage or planning a policy change. Verify both the missing-descriptor class and the synthesis template. If it is already mounted, read the change limits before proceeding.

Inspect live mounts and policy #

Use these read-only listings first:

lsblk
mount

mount lists live state from the kernel; Peios has no /etc/fstab or /etc/mtab. The listing is limited to mounts your token may observe. An empty or partial listing does not prove that a device is unused.

Match the intended filesystem to a verified stable source name, then check its live source, target and filesystem type. To inspect its policy in Disk Manager:

  1. Open the launcher and type disk.
  2. Select Mounts, then the intended mount to see its options and policy.
  3. Open Permissions… to inspect the synthesis template. The UI policy labels explain the missing-descriptor choices.

Check both class and template; the ordinary mount listing is not a template dump. If Disk Manager cannot read the policy, verification remains incomplete. Missing details do not establish the intended policy, and the GUI does not bypass the privilege gate. See what Disk Manager may show.

Check policy access #

Warning

In kernel source 8e0e22de3a59cad506bbbf8873de456e16ad272d, both policy reads and writes accept enabled SeManageVolumePrivilege or SeTcbPrivilege; recording the privilege as used must also succeed. Administrator membership alone does not satisfy this gate. This is a pinned source finding, not a test of the kernel deployed on your machine or a historical release boundary.

The mount diagnostic in peiosutils 0.8.18 still names only SeTcbPrivilege. That hint is misleading for the pinned kernel. Check the deployed kernel and caller's effective token before changing privileges; do not automatically grant TCB or globally remap CAP_SYS_ADMIN to make the operation succeed. SeManageVolumePrivilege is narrower than TCB but still permits substantial authority over paths and synthesised policy.

Attach a filesystem #

Warning

Ephemeral synthesis avoids writing back synthesised security descriptors; it does not guarantee an unchanged disk. Even a read-only ext4 mount can replay its journal. If preservation requires no disk writes, use a supported inspection procedure for that filesystem. How the installer's disk scan stays read-only explains its additional safeguards; a policy choice alone is not that procedure.

For a new mount, the command shape is:

mount [-t TYPE] [-o OPTIONS] SOURCE TARGET

Choose -o policy=deny-missing, -o policy=synth-ephemeral, or -o policy=synth-persist using Policy classes. Use the verified stable source name and the intended target mount point. Use persistent synthesis only when writing SDs is intended; select read-only separately if file-data writes must be prevented.

--synth-sddl SDDL supplies a well-formed template with an owner, and is valid only with a synth-* policy. Review the synthesis chain and fallback before exposing the volume: parent inheritance takes precedence, and omitting a template does not imply private access.

If setting the attach-time policy fails, no mount with the unintended policy is attached. The mount reference describes that guarantee and the full option contract.

After success, inspect the live mount and policy again. Confirm the source, target, filesystem, writable state, class and template. Also inspect after a failure: target creation or attachment may already have happened before a later step fails. The source-verified execution limits explain why neither a nonzero status nor --fake proves nothing changed.

Before changing an already-mounted policy #

mount sets policy only for a new filesystem mount. Bind, move, remount, propagation and list mode reject policy=; mount -o remount is not a policy-change interface. Disk Manager cannot commit changes because its privileged disk service is missing, including changes offered by its forms.

The kernel exposes a privileged interface for an existing filesystem instance (the superblock), but these operator tools do not provide a ready-to-use command or working GUI flow for changing its policy. Confirm a supported privileged integration for the deployed system before proceeding, including its policy access requirements.

For integration authors, the kernel administration contract, SDK wrappers and syscall notes cover arguments, template validation, buffer handling, errors and generation semantics. The privilege disagreement is resolved for the pinned source above; other differences retained in the syscall notes are not resolved by that finding. A rejected policy change leaves the current class and template unchanged.

A second mount of the same device does not establish an independent policy boundary. Read the mount superblock-reuse restrictions before relying on a separate instance; detaching and reattaching is not a generic policy-change procedure.

What a policy change affects #

  • All bind paths sharing the filesystem instance share the new policy. Independent superblocks are unaffected, even when reached beneath this mount.
  • Stored descriptors remain unchanged. Already-open handles retain their granted rights; future access checks use the new policy.
  • No file tree is rewritten or provisioned. Changing ephemeral to persistent does not save every cached SD immediately; later missing-descriptor accesses derive under the new policy and schedule best-effort write-back.
  • Deny-missing can leave files without stored SDs inaccessible. Corrupt descriptors remain denied under every managed class; synthesis does not repair them.

Before hardening an adopted filesystem, check class transitions and validate descriptor preservation, including rarely accessed files. Persistent synthesis is incremental adoption, not a whole-tree guarantee; mounted sd output alone does not prove durable storage.

Mount non-root storage at startup #

The root filesystem is mounted by the initramfs before peinit takes over. A non-root data partition is mounted by an ordinary Oneshot service; peinit does not mount it directly. See Where peinit takes over.

Use Defining a service for the definition, validation and boot-trigger fields, and Oneshot services for the completion contract. A service using a stable device name needs a Requires dependency on the device manager so the boot-time device replay finishes before it opens that name.

These pages establish the service mechanism, but do not yet give a complete storage-specific recipe: the service identity, required privileges and mount arguments must be confirmed for the deployed system before creating a definition. There is no dedicated mount-registry schema established here, and Disk Manager cannot currently save startup mounts.

A complete integration must also define repeat-start, missing-device and partial-failure handling. In the reviewed mount implementation, --onlyonce supplies no existing-mount guard, and mkdir MODE is not applied. Do not use those options as proof of safe repeat activation or private target security. Device coldplug completion does not guarantee a particular disk stays present. A successful Oneshot becoming Inactive does not unmount the filesystem; command/service state and live mount state are separate.

After the service runs, inspect its status and logs. A successful Oneshot reports successful command completion and can then return to Inactive; its status alone does not establish the current mount or policy. Separately inspect the live mount, checking source, target and filesystem, and read the policy to confirm both class and template.

Check unexpected results #

  • Attachment failed: read the command's diagnostic and mount exit status. Check the source, options and reported permission or filesystem failure. A failed attach-time policy step does not publish a mount with an unintended policy.
  • Policy details are unavailable: check policy access and Disk Manager's visibility limits. Do not treat an unreadable class or template as successful verification.
  • A file is still denied: distinguish a missing descriptor from a corrupt one. Deny-missing rejects missing SDs, and switching to synthesis does not repair corrupt SDs.
  • Old access still works through an open handle: existing handles retain their granted rights. Check future access using a new handle.

unmanaged is reserved for the kernel and cannot be set administratively. StrataFS's policy is fixed; neither is a workaround for an access failure.

See also #

  • Policy classes: choose a class and diagnose missing or corrupt SDs.
  • SD storage by filesystem: check whether a descriptor can persist.
  • Privileges: understand the privilege gate.
  • File Descriptor Storage: kernel policy, caching, write-back and repair contract.
  • mount: attachment options and status codes.
  • umount: detachment options and status codes.

mount

Peios / Using Peios / Mount policies

mount attaches a filesystem to the Peios mount tree. With no operands it instead lists what is currently mounted. It is a faithful reworking of the util-linux mount(8) surface for Peios, with two structural differences: Peios has no /etc/fstab and no /etc/mtab, so every mount is described entirely on the command line and live mount state is read from the kernel; and a mount can apply a KACS mount policy to the new filesystem at attach time (see Mount policies).

mount [-t TYPE] [-o OPTIONS] SOURCE TARGET
mount [-o remount,OPTIONS] TARGET
mount --bind|--rbind|--move SOURCE TARGET
mount --make-shared|--make-private|... TARGET
mount [-l] [-t TYPE]

Internally mount uses the fd-based mount API (fsopen / fsconfig / fsmount / move_mount, plus open_tree and mount_setattr), never the classic single-shot mount(2). This matters in one place you can see: when a mount fails, the kernel's fs_context message log is drained and printed as the reason, even without -v.

Operands and argument shapes #

Because there is no fstab to consult, operand resolution is strict:

  • No operands, no verb — list mode (see below).
  • Two operands — SOURCE TARGET.
  • One operand — an error. In util-linux a lone operand is resolved through fstab; Peios has none, so a single operand cannot be turned into a SOURCE TARGET pair. Supply both, or use --source / --target.
  • A lone target is valid only for -o remount and for a standalone propagation change (--make-*), which act on an existing mount point.

--source SRC and --target DIR name the operands explicitly and may be combined with a single positional. --target-prefix DIR prepends DIR/ to the target after it is chosen. Options may be interspersed with operands (mount SRC -o ro TGT), matching util-linux.

Paths, -o key=value values, labels and UUIDs are handled as opaque byte strings, never assumed to be UTF-8; an embedded NUL is a usage error.

Canonicalisation #

By default source and target paths are canonicalised (made absolute, symlinks resolved). -c / --no-canonicalize disables that; X-mount.nocanonicalize[=source|target] is the -o form and can disable it for just one side. The final path handed to the kernel is protected against a TOCTOU symlink swap on its last component. This does not reject every symlink in the original input: default canonicalisation has already resolved it.

Operation modes (verbs) #

mount performs one of several operations. The structural verbs — bind, rbind, move, beneath and remount — are mutually exclusive with one another. A propagation change is not a structural verb: it may stand alone on a target, or trail another verb or a new mount in the same command (applied afterwards as one or more mount_setattr steps), and several may be combined.

VerbHow to request itWhat it does
New mountmount [-t T] SRC TGTAttach a fresh instance of the filesystem at SRC onto TGT.
Bind-B / --bind, or -o bindMake an existing subtree visible at a second location.
Recursive bind-R / --rbind, or -o rbindBind a subtree together with every mount underneath it.
Move-M / --move, or -o moveRelocate an existing mount to a new mount point.
Move beneath--beneath SRC TGTAttach SRC beneath the mount currently at TGT (the kernel enforces several constraints; violations surface as exit 32).
Remount-o remount[,...] TGTChange the options of an existing mount (see Remounting).
Propagation--make-* / --make-r*, or the -o tokens belowChange how mount/unmount events propagate across a subtree.
Listmount / mount -lPrint the current mounts.

Propagation flags #

Each of these sets the propagation type of the mount at the target. The --make-r* (and r-prefixed -o) forms apply recursively to the whole subtree; the recursive form is all-or-nothing (it either applies to the entire subtree or to none of it).

Flag-o tokenRecursive flagRecursive -o tokenMeaning
--make-sharedshared--make-rsharedrsharedEvents propagate to and from peer mounts.
--make-slaveslave--make-rslaverslaveEvents propagate in from the master but not back out.
--make-privateprivate--make-rprivaterprivateNo propagation either way.
--make-unbindableunbindable--make-runbindablerunbindablePrivate, and cannot be bind-mounted.

A freshly created mount, bind or move is private by default unless its destination's parent is shared, in which case it joins that peer group — the standard kernel rule.

Source specification #

FormResolution
Device path (/dev/sda1)Used directly.
-L LABEL / LABEL=, -U UUID / UUID=, PARTLABEL=, PARTUUID=Resolved to a device via libblkid. No match is a mount failure (exit 32).
A directory or regular fileUsed directly (a bind source or target; a file may be a bind target).
A pseudo source (tmpfs, proc, sysfs, none, …)Passed through; -t is required because it cannot be probed.
An image fileAttached through a loop device (see Loop devices).

Filesystem type #

-t TYPE names the type explicitly. -t auto, or omitting -t entirely, asks libblkid to safely probe the source; an ambiguous or multiply-signed device is refused (exit 32) rather than guessed at. X-mount.auto-fstypes=LIST constrains the probe candidates. Type lists and no<type> negation are not accepted in the mounting path (they remain meaningful only as a listing filter).

The -o option language #

-o takes a comma-separated list of key or key=value tokens and is repeatable (all occurrences are joined). A key="..." double-quoted value protects embedded commas; the key=value split is on the first =. Every token is sorted into one of the following categories.

Per-mount attributes #

Applied to the mount itself. Each accepts its negation; ro/rw additionally accept a =vfs / =fs / =recursive scope qualifier (bare is =vfs, non-recursive; =fs targets the superblock read-only flag; =recursive applies to the whole subtree).

OptionEffect
ro / rwRead-only / read-write.
suid / nosuidHonour / ignore set-user-ID bits.
dev / nodevAllow / disallow device nodes.
exec / noexecAllow / disallow execution.
atime / noatimeUpdate / never update access times.
relatime / norelatimeRelative-atime updates on or off.
strictatime / nostrictatimeStrict-atime updates on or off.
diratime / nodiratimeDirectory access-time updates on or off.
nosymfollowDo not follow symlinks on this mount. There is no positive symfollow token — the attribute is cleared only via a remount mask.

The atime tokens share a single mode field; the last one specified wins.

Superblock flags #

OptionEffect
sync / asyncSynchronous / asynchronous writes.
dirsyncSynchronous directory updates.
lazytime / nolazytimeLazy on-disk timestamp updates on or off.
iversion / noiversionInode version counting on or off.
silent / loudSuppress or emit certain kernel messages.
mand / nomandObsolete (removed from the kernel). Accepted and ignored with a note under -v.

Filesystem-specific parameters #

Any token not recognised above is forwarded verbatim to the filesystem: key=value as a string parameter, a bare key as a flag. There is no built-in allow-list and no length limit; a rejection by the filesystem is reported with the offending key and the kernel's message.

For example, StrataFS takes its precedence-ordered directory stack through strata=:

mount -t stratafs none /bin -o 'strata=/lcl/bin+create:/usr/bin+ro'

See StrataFS for the stack flags, merge and write-routing model, and the stratafs inspection command.

Userspace-only tokens #

These never reach the filesystem. They include the meta-verbs remount, bind, rbind, move; the loop controls loop / loop=/dev/loopN, offset=, sizelimit= (numeric values accept K/M/G/T and KiB/MiB/… suffixes); the propagation tokens listed above; and defaults, which expands to rw,suid,dev,exec,async (later tokens override it).

Functional X-mount.* options #

OptionEffect
X-mount.mkdir[=mode]Attempt to create missing target directories, like -m. In the reviewed implementation, the requested mode is not applied.
X-mount.subdir=DIRAttach subdirectory DIR of a freshly mounted filesystem at the target. Effective only for a new-instance mount; silently ignored (noted under -v) for bind/move/remount/propagation.
X-mount.noloopSuppress the implicit loop device for a regular-file source.
X-mount.auto-fstypes=LISTConstrain the -t auto probe to these types.
X-mount.nocanonicalize[=source|target]The -o form of -c; with =source or =target it disables canonicalisation for just that path.

X-mount.idmap and X-mount.owner / group / mode are not supported and are rejected with a usage error: Peios ownership is SID/security-descriptor based, so the fix is to add a SID/ACE to the descriptor rather than remap or chown.

KACS mount policy #

This is the genuinely Peios-specific part of mount. A mount policy is a per-superblock setting that governs how FACS treats the filesystem; the full model is described in Mount policies and its detail pages. mount can set that policy at attach time:

OptionPolicy class
-o policy=deny-missingfacs_deny_missing — a file with no SD is unreachable.
-o policy=synth-ephemeralfacs_synthesize_ephemeral — a missing SD is synthesised in memory only.
-o policy=synth-persistfacs_synthesize_persistent — a missing SD is synthesised and written back.
--synth-sddl SDDLProvide the mount-level SD template used during synthesis (only valid with a synth-* policy).

policy=unmanaged is not user-settable; only the kernel sets the unmanaged class, for its own pseudo-filesystems. policy= is valid only on a new mount of a real filesystem — combining it with bind/move/remount/propagation, or with list mode, is a usage error. See Policy classes for what each class does and SD storage by filesystem for how the SD is physically stored.

The policy is applied to the detached filesystem before it is attached: if setting it fails, that filesystem is not attached with an unintended policy. This is an attachment guarantee, not whole-command rollback: target creation may already have occurred. In kernel source 8e0e22de3a59cad506bbbf8873de456e16ad272d, the policy gate accepts enabled SeManageVolumePrivilege or SeTcbPrivilege and requires successful privilege-use marking. Failure of that gate gives EPERM (exit 1) and no attachment. --synth-sddl is validated client-side first — it must be well-formed SDDL and must include an owner.

Warning

The peiosutils 0.8.18 diagnostic still says the policy operation requires SeTcbPrivilege. That is not the full gate in the pinned kernel. See Check policy access before interpreting this as a need to grant TCB; administrator membership alone is not enough, and automatic escalation or a global CAP_SYS_ADMIN remap is not a remedy.

Peios applies no coarse uid==0 check anywhere: the mount applet is not installed set-user-ID, and every privileged action is authorised per-operation by KACS.

Remounting #

-o remount changes the options of an existing mount without detaching it. Peios does not perform the util-linux "read the old flags and re-supply them" dance — the fd-based API applies deltas rather than resetting, so each remount touches only what you name. Per-mount attributes (ro/rw, nosuid, atime, …) are changed via mount_setattr; superblock flags, filesystem parameters and ro=fs/rw=fs go through the superblock reconfigure path. =recursive remounts the whole subtree, all-or-nothing.

A bind mount shares its source's superblock, so any superblock-level option on a bind remount (a Category-B flag, a filesystem parameter, or ro=fs/rw=fs) is refused as a usage error rather than silently mutating the shared superblock for every mount of that filesystem. Only per-mount VFS attributes are valid on a bind remount.

Loop devices #

A regular-file source is backed by a loop device automatically when the type is unspecified or the filesystem is recognised by libblkid; X-mount.noloop suppresses this. -o loop forces auto-allocation of a free device, loop=/dev/loopN names one, and offset= / sizelimit= select a region of the file (they imply loop and are an error against a real block device). A backing file already attached at the same offset and size is reused rather than doubly attached, to avoid corruption. Loops created by mount are auto-cleared by the kernel on unmount, so they do not leak; umount -d force-clears the rest (see umount).

Other flags #

FlagEffect
-t, --types TYPEFilesystem type, or auto.
-o, --options LISTMount options (above); repeatable.
-r, --ro, --read-onlyMount read-only (-o ro).
-w, --rw, --read-writeMount read-write and forbid the automatic read-only fallback on a write-protected device (-o rw).
--source SRC / --target DIRName the operands explicitly.
--target-prefix DIRPrepend DIR/ to the target.
-B, --bind / -R, --rbind / -M, --move / --beneathThe structural verbs.
--make-*, --make-r*Propagation changes.
--exclusiveForce a unique superblock instance (no reuse). Meaningful only for multi-instance filesystems (e.g. tmpfs) or read-only block mounts; on an already-mounted writable block device it fails with EBUSY (exit 32).
-m, --mkdir[=MODE]Attempt to create missing target directories. The requested MODE is parsed but not applied at the reviewed source revision.
-L, --label LABEL / -U, --uuid UUIDSelect the source by filesystem label / UUID.
-c, --no-canonicalizeDo not canonicalise paths.
-f, --fakeSkip mount and policy syscalls; target preparation still runs. With --mkdir or X-mount.mkdir, directories may be created. See execution limits.
-v, --verboseNarrate resolved values and each syscall; drain the kernel fs_context log. Repeatable but -vv is the same as -v.
-l, --show-labelsIn list mode, append each filesystem's label.
--onlyonceAccepted and stored, but unused by the reviewed execution path. Do not rely on it to skip an existing mount or make repeat startup safe.
-N, --namespace NSOperate inside mount namespace NS (a PID, an ns file path, or a named namespace). Source resolution happens in the caller's namespace; the mount lands in the target namespace.
-i, --internal-onlyDo not invoke a mount.<type> helper.
-n, --no-mtabAccepted and ignored (Peios has no mtab).
--synth-sddl SDDLKACS synth-policy template SD (above).
-h, --help / -V, --versionStandard.

No external mount helpers ship in this version, so a network or FUSE type fails with "no helper for type" (exit 1) — a clean deferral, not a crash.

Source-verified execution limits #

These limits were checked in peiosutils 3344d4690476fd66bfaec99b1ae92190bbcba06f. They describe that implementation, not a runtime test or a historical release boundary; check the version in the image you operate.

  • No already-mounted guard from --onlyonce. The request parser stores it, but the executor never consults it. Inspect existing mounts before a repeat operation; this finding does not mean every repeat necessarily succeeds or creates an overmount.
  • --fake can create targets. Target preparation precedes the new-mount fake return. With either mkdir option it may write directories. It is not a zero-write preview or proof that a real mount's authority and filesystem checks will pass.
  • MODE is not target security. The creation helper discards the requested mode and ignores the directory-creation result before continuing path preparation. Do not rely on --mkdir=0700 for privacy. Establish and verify the target's native security separately; a parsed option is not a verified descriptor.
  • Failure can follow attachment. New-mount execution sets policy before attachment, but a subsequent propagation step can fail after the mount is attached. Retain diagnostics and inspect the live source, target, filesystem, writable state and policy before retrying. Do not infer an unchanged system from a nonzero exit status.

These gaps matter for startup integration: --onlyonce is not an idempotence mechanism, and a failed or stopped command is not by itself a verified detach or recovery procedure.

List mode #

With no operands, mount prints one line per mount, read from /proc/self/mountinfo:

SOURCE on TARGET type FSTYPE (OPTIONS)

mount -t TYPE with no operands filters the list by filesystem type instead of mounting; here type lists (-t ext4,xfs) and no<type> negation (-t nosysfs) are honoured. -l appends [LABEL] to each line when a label is known.

Details of the rendering: the option field is the positional VFS-then-superblock merge with a coalesced ro/rw, not sorted; mountinfo octal escapes are decoded; control characters in the mount point become ?; and the source is shown as the kernel recorded it, with /dev/loopN resolved to its backing file and /dev/dm-N to /dev/mapper/<name>. The listing shows only mounts the caller's token may observe; a partial or empty view is correct, not an error, and the paths of filtered-out parents are never reconstructed.

For a device-oriented view of what is available to mount, use lsblk.

Exit status #

CodeMeaning
0Success.
1Incorrect invocation or a permission denial — bad flags, mutually-exclusive verbs, a lone operand, an invalid policy= or --synth-sddl, an authorisation failure (EPERM/EACCES), an embedded NUL, or "no helper for type".
2System error (out of memory, no free loop device, cannot fork).
4Internal error (an invariant failure).
8Interrupted (SIGINT), after signal-safe cleanup.
32Mount failure — a syscall in the flow failed, a label/UUID had no match, a probe was undetermined, or a --beneath/move/--exclusive kernel refusal.
126An external mount.<type> helper was found but failed to execute (moot until a helper ships).

Code 16 (mtab) is never produced. Code 64 (some succeeded, some failed) only arises when several source arguments are given and at least one succeeds while another fails.

umount

Peios / Using Peios / Mount policies

umount detaches a filesystem from the Peios mount tree. It is the counterpart of mount and, like it, reads live mount state from the kernel (/proc/self/mountinfo) rather than any /etc/mtab — Peios has none. Each operand is resolved against that live state and unmounted with umount2(2).

umount [-lfRA] [-dr] TARGET|SOURCE...

Operands and how they are resolved #

Each operand is either a mount point or a source:

  • If the (canonicalised) operand is itself a mount point in the current mount table, it is unmounted directly. This is always unambiguous.
  • Otherwise the operand is treated as a source and matched against the sources in the mount table. If it is mounted in exactly one place, that place is unmounted. If it is mounted in several places, umount refuses with an error naming the candidates — resolve it by naming a specific mount point, or use -A to unmount all of them.

If an operand matches nothing, it is "not mounted": normally an error (exit 32), but -g makes that a success and -q suppresses the message.

Several operands may be given in one invocation, and options may be interspersed with them (umount /a -f /b). Paths are handled as opaque bytes; an embedded NUL is a usage error. By default each operand is canonicalised; -c disables that and additionally selects UMOUNT_NOFOLLOW so the kernel does not follow a symlink in the final component.

Recursive and all-targets unmounts #

Two flags expand a single operand into multiple unmounts. Within one operand the expansion stops on the first failure.

  • -R / --recursive unmounts the target and everything mounted underneath it, including any over-mount stack at a single point, ordered deepest-first.
  • -A / --all-targets unmounts every mount point of the given source in the current mount namespace. This is the live-mountinfo "unmount everywhere" complement to source resolution; it is not an fstab feature.
  • -A -R together compose: for each mount point of the source, recurse underneath it.

-R and -r are mutually exclusive (combining them is a usage error, exit 1).

Flags #

FlagEffect
-l, --lazyDetach the filesystem now and clean up references later (MNT_DETACH).
-f, --forceForce the unmount (MNT_FORCE), e.g. for an unreachable server.
-R, --recursiveUnmount the target and everything under it (see above).
-A, --all-targetsUnmount every mount point of the given source (see above).
-d, --detach-loopAfter unmounting, free the backing loop device. Best-effort and verified: it clears the device only if it still backs the mount just removed, so a recycled loop number is never clobbered. Usually redundant, since mount-created loops auto-clear on unmount.
-r, --read-onlyIf the unmount fails, remount the filesystem read-only instead (via mount_setattr). Mutually exclusive with -R.
-g, --gracefulExit 0 when the target is absent or not mounted (rather than failing). Applied unconditionally.
-q, --quietSuppress "not mounted" messages.
-c, --no-canonicalizeDo not canonicalise paths; selects UMOUNT_NOFOLLOW. Applied unconditionally.
-v, --verboseSay what is being unmounted. Repeatable.
-N, --namespace NSEnter mount namespace NS (a PID, an ns file path, or a named namespace) before reading its mount table and unmounting. All work happens inside that namespace.
-n, --no-mtabAccepted and ignored (no mtab on Peios).
-i, --internal-onlyDo not invoke a umount.<type> helper (none ship).
--fakeDry run: resolve operands and report, but skip the unmount syscalls.
-h, --help / -V, --versionStandard.

The umount2 flag mapping is direct: -l → MNT_DETACH, -f → MNT_FORCE, -c (or a symlinked final component) → UMOUNT_NOFOLLOW. MNT_EXPIRE is deliberately not exposed, matching util-linux.

On privilege #

As with mount, there is no coarse uid==0 check: the applet is not set-user-ID and every unmount is authorised per-operation by KACS. Where util-linux silently suppresses an option for non-root users (-c, and -g's effectiveness), Peios applies it unconditionally.

Exit status #

CodeMeaning
0Success (or a -g no-op on an absent target).
1Incorrect invocation or a permission denial — including -R with -r, a missing operand, an ambiguous source, an embedded NUL, or an authorisation failure.
2System error (e.g. cannot read the mount table).
8Interrupted (SIGINT).
32Unmount failed, or the target is not mounted (unless -g).
64Several source/target arguments were given and at least one succeeded while another failed.
126An external umount.<type> helper was found but failed to execute (moot until a helper ships).

A single -R / -A / -A -R invocation stops on the first failure and yields 32; the aggregate 64 only appears across multiple top-level arguments. To see what is currently mounted before unmounting, use mount with no arguments or lsblk.

lsblk

Peios / Using Peios / Mount policies

lsblk lists the block devices on the system and their relationships — disks, their partitions, and the device-mapper and loop devices layered on top. It is the device-oriented companion to mount: where mount with no arguments shows what is mounted, lsblk shows what is available to mount and what filesystem sits on each device.

lsblk [options] [DEVICE...]

By default it prints a tree, one row per device with children indented beneath their parent. Given one or more DEVICE operands (a name like sda, a full path like /dev/sda, or anything resolving to a device node), it re-roots the output at those devices.

Where the data comes from #

Each column is sourced from one of four places, and any that cannot be read degrades to an empty cell rather than aborting the run:

  • sysfs (/sys/block) — the device tree, sizes, and the topology/hardware columns. Peios leaves /sys/block unpatched, so this is the standard no-udev path.
  • libblkid — filesystem identity: FSTYPE, FSVER, UUID, LABEL, and the partition-table columns (PTTYPE, PTUUID, PARTTYPE, PARTLABEL, PARTUUID). libblkid is opened at runtime, and it reads the device itself, so these columns are empty for anyone who may not open it: as shipped, a disk's node lets only SYSTEM and Administrators open it.
  • The device node's security descriptor — OWNER and MODE, read the same way ls -l reads them.
  • The /dev/disk/by-* symlink farm — ID-LINK. Populated by the device manager once it has run; there is deliberately no /run/udev/data parser, so the column reads the links themselves and is empty in the initramfs, where no device manager runs.

Output modes #

The mode selects how the rows are formatted; it does not change which columns are shown.

FlagMode
(default)Indented tree.
-l, --listFlat list — the same columns, no tree glyphs.
-J, --jsonJSON. Flag columns render as bare booleans and MOUNTPOINTS as an array; children nest under a children key.
-P, --pairsKEY="value" pairs, one device per line.
-r, --rawRaw, space-separated. Values that could contain a space or control character are hex-escaped (\xNN) so fields stay parseable.
-T, --tree[=COLUMN]Force tree output even alongside -l, optionally attaching the tree glyphs to COLUMN instead of NAME.

Columns #

With no column flag, lsblk prints the default set: NAME, MAJ:MIN, RM, SIZE, RO, TYPE, MOUNTPOINTS. Three flags swap in a preset, and -o names an explicit list (which wins over all of them):

FlagColumn set
-o, --output LISTExactly the comma-separated columns named (case-insensitive; an unknown name is a usage error).
-O, --output-allEvery available column.
-f, --fsFilesystem view: NAME, FSTYPE, FSVER, LABEL, UUID, MOUNTPOINTS.
-m, --permsPermissions view: NAME, SIZE, OWNER, MODE.

The available columns are NAME, KNAME, PATH, MAJ:MIN, FSTYPE, FSVER, LABEL, UUID, PTUUID, PTTYPE, PARTTYPE, PARTLABEL, PARTUUID, MOUNTPOINT, MOUNTPOINTS, SIZE, RO, RM, HOTPLUG, TYPE, OWNER, MODE, MODEL, VENDOR, REV, SERIAL, TRAN, HCTL, ALIGNMENT, MIN-IO, OPT-IO, PHY-SEC, LOG-SEC, STATE, ROTA, SCHED, PKNAME, and ID-LINK.

The OWNER and MODE columns #

OWNER and MODE describe the device node, not the filesystem on it, and they mirror ls -l exactly — there is no GROUP column and no POSIX permission bits, because access to a device node is governed by its security descriptor, not by a mode. OWNER is the owner SID (S-1-…); MODE is a three-character [type][x][+]: the device-type character (b for a block device, c for a character device), an x slot (never set for a block device), and a + when the DACL is inheritance-protected. When the SD cannot be read — for instance on a non-Peios host with no KACS syscalls — OWNER shows ? and MODE degrades honestly.

Filtering, sorting and shaping #

FlagEffect
-a, --allInclude empty (zero-size) devices, which are hidden by default.
-d, --nodepsDo not print a device's holders or slaves (drop the children).
-I, --include LISTShow only devices with these major numbers (comma-separated).
-e, --exclude LISTExclude devices by major number. The default is 1 (RAM disks); an explicit -e replaces that default, and -a clears exclusions entirely.
-s, --inversePrint dependencies in inverse order (holders above the devices they depend on).
-M, --mergeCollapse a subtree shared by several parents (a multipath device) to a single occurrence.
-E, --dedup COLUMNDrop rows whose COLUMN value duplicates an earlier one.
-x, --sort COLUMNSort siblings by COLUMN (numeric columns sort by value, not text).

Formatting #

FlagEffect
-b, --bytesPrint SIZE as an exact byte count instead of a human-readable value.
-p, --pathsPrint full /dev paths in the NAME column.
-n, --noheadingsOmit the header row.
-i, --asciiDraw the tree with ASCII characters instead of box-drawing glyphs.
-y, --shellRender column keys shell-safe (MAJ:MIN becomes MAJ_MIN).
-w, --width NUMTruncate each table row to NUM columns wide.
--sysroot DIRRead sysfs, the mount table and /dev from DIR instead of / (chiefly for testing against a fixture).
-h, --help / -V, --versionStandard.

Exit status #

CodeMeaning
0Success.
1Incorrect invocation (an unknown column, a malformed major-number or width value) or a failed run (for example, /sys/block is unreadable).

lsblk uses this single non-zero code, matching util-linux. A per-device read failure is not fatal: it degrades the affected columns to empty or ? and the run continues. A broken output pipe (piping into head, for instance) is treated as success.

Peios Learn — documentation for the Peios project.

Built with Trail.