A package manager can place an executable on a writable filesystem, close it, and later expect every byte returned from that file to match a previously approved object. Ordinary permissions can stop cooperative writers, but they do not turn file contents into a cryptographically identified object. Linux fs-verity supplies that narrower property for individual files: after verity is enabled, file data becomes read-only and reads are checked against a Merkle tree rooted in a stable file digest.
The boundary is integrity verification, not automatic trust. A Merkle tree can detect data that no longer matches its root, but a verifier still needs an authenticated expectation for the resulting fs-verity digest. Treating those two roles as one can turn a sound integrity mechanism into an incomplete authenticity policy.
Enabling verity freezes the data plane
Userspace enables the feature with FS_IOC_ENABLE_VERITY on a regular file hosted by a filesystem that implements fs-verity. The caller supplies parameters including the hash algorithm, block size, and optional salt. The filesystem builds and persists the Merkle tree and a verity descriptor, then marks the file as a verity file.
The transition has strict write-side conditions. The ioctl is issued on an O_RDONLY descriptor, the caller still needs write access to the inode, and no process may hold the file open for writing. A writable memory mapping also prevents the transition. These constraints keep the file stable while the tree is built and prevent a writable descriptor from surviving after activation.
Once activation succeeds, the file cannot be opened for writing or truncated. The operation is intentionally one-way for that inode. Replacing content requires creating another file and enabling verity on that new object rather than mutating the existing verity file.
This immutability applies to file data, not every inode property. Ownership, mode bits, timestamps, and extended attributes can still change. The file may also be renamed, linked, or deleted. A security design that binds authorization to pathnames or mutable metadata therefore needs controls beyond the verity digest.
The digest commits to more than a root hash
File data is divided into fixed-size blocks. Each data block is hashed, hashes are packed into blocks and hashed again, and the process continues until one root remains. On reads, the kernel can verify a data block along its path through this tree instead of hashing the complete file for every access.
The externally measurable identity is not merely that Merkle root. fs-verity hashes a descriptor that includes the root hash together with parameters such as file size, hash algorithm, block size, and salt. FS_IOC_MEASURE_VERITY returns this fs-verity file digest in constant time with respect to file size.
Committing to the descriptor closes structural ambiguity that a bare tree root could leave. A trusted catalog can consequently bind an expected artifact to the digest produced by the same fs-verity construction rather than to an informal combination of size and a separately managed tree root.
The hash algorithm remains part of the identity. A digest value without its algorithm identifier is not a complete fs-verity identity, and signature formats used with the facility include the algorithm and digest size.
Verification occurs on the read path
For page-cache-based filesystems, data is verified before the corresponding folio is made available as up-to-date data. This placement matters because file content can reach a process through interfaces other than read(), including memory mappings.
When verification of file data fails, ordinary reads can fail with EIO; access through an mmap() mapping can raise SIGBUS. The mechanism therefore changes runtime failure behavior. Applications that consume verity files need an error model that treats storage corruption or failed verification as a possible read failure rather than assuming that a successfully opened immutable file remains readable forever.
Verified Merkle blocks can be cached, so the kernel does not need to traverse every level from storage for every adjacent data block. That optimization does not alter the trust root: cached hash blocks are useful only after they have been verified through a path anchored in the file digest.
Direct I/O is not used for verity-file reads because an unverified path around the page-cache verification machinery would break the property. DAX is likewise incompatible with verity files. The enforcement claim depends on every supported data-read path passing through verification.
Integrity does not authenticate the expected digest
If an attacker can replace both file data and an unauthenticated expected digest, successful Merkle verification says only that the new data is internally consistent with the new digest. Authenticity requires a separate trust decision.
One model keeps approved fs-verity digests in trusted userspace metadata. Trusted code measures the file with FS_IOC_MEASURE_VERITY, compares the result with the approved digest, and only then treats the object as authenticated. The security boundary includes protection of that catalog and the code performing the comparison.
Another model uses a signature over the fs-verity digest. Linux can optionally store and verify a built-in PKCS#7 signature using certificates in the .fs-verity keyring when the relevant kernel support is enabled. IMA appraisal can also use fs-verity digests, and IPE can make policy decisions using fs-verity properties.
These mechanisms are not interchangeable policy statements. Built-in signature verification proves that a configured trusted key signed a digest, but by itself it does not require arbitrary files on the system to have verity enabled. A deployment still needs a policy that determines which operations require authenticated verity files.
Path replacement remains outside the file digest
A verity inode is immutable in its data, yet its directory entry is not a permanent name binding. A privileged or otherwise authorized actor may unlink it and place another file at the same pathname. The replacement can be a different verity file or, absent a separate enforcement rule, a non-verity file.
This separates content identity from pathname identity. A consumer that authenticates a file by digest should perform the check on the same opened object it will use, or rely on a kernel policy that enforces the required property at access time. Measuring one pathname and later reopening that pathname recreates a name-resolution race that fs-verity does not solve.
Hard links expose the same distinction from another direction. Multiple names can refer to one verity inode and therefore the same protected data. The digest identifies content under the fs-verity construction; it does not encode a canonical directory location.
Copying does not automatically preserve verity state
The Merkle tree and descriptor are filesystem-managed metadata associated with the verity inode. A normal file copy reads the verified bytes and creates a new ordinary file; it does not automatically create another verity inode with equivalent metadata.
Backup, image-building, and distribution systems therefore need an explicit provisioning model. They may copy bytes, then enable verity on the destination and compare the resulting digest, or use specialized tooling capable of transporting compatible verity metadata under controlled conditions.
This operational boundary prevents a useful but false assumption: identical payload bytes do not imply identical enforcement state. The destination filesystem must support fs-verity, the feature must be enabled there as required by that filesystem, and the destination inode must enter verity state.
Filesystem support defines the deployment boundary
fs-verity is a common kernel support layer with filesystem-specific integration. ext4, f2fs, and btrfs support it, but their on-disk storage of verity metadata differs. Kernel configuration and filesystem feature state also determine availability.
That division is security-relevant because the guarantee is not created by the ioctl name alone. Successful activation means the active filesystem implementation has accepted the verity state and will route supported reads through verification. An application that requires the property should treat ENOTTY, EOPNOTSUPP, and other activation failures as failure to establish the boundary, not as optional optimization failures.
fs-verity is strongest when its claim remains narrow: immutable file data, block-level verification anchored in a measurable digest, and explicit composition with a trusted authenticity policy. It does not freeze inode metadata, bind a pathname permanently, preserve itself through ordinary copies, or decide which signer should be trusted. Those surrounding decisions determine whether verified bytes also represent the artifact a system intended to execute or consume.