Linux IMA and EVM: Kernel-Level File Integrity with TPM Attestation in 2026
Deploy Linux IMA and EVM for kernel-enforced file integrity. Learn appraisal policy, EVM key sealing to TPM 2.0, IMA digest lists, and Keylime remote attestation with working configs.
Linux IMA (Integrity Measurement Architecture) is a kernel subsystem that hashes files as they are read or executed and, in appraisal mode, refuses to use any file whose digest doesn't match a signature or HMAC stored in extended attributes. It was merged in 2.6.30 and substantially extended across the 6.x series. Paired with EVM (Extended Verification Module), which protects those xattrs from tampering, and anchored to a TPM 2.0 for measurement attestation, IMA gives you kernel-enforced file integrity that survives offline disk edits. That's something userspace tools like AIDE simply cannot promise.
IMA measures (and optionally appraises) files at open(), mmap(), and execve() via LSM hooks, recording SHA-256/SHA-512 digests into a TPM PCR (default PCR 10) for remote attestation.
EVM signs or HMACs the security xattrs themselves (security.ima, security.selinux, ownership, mode) so an offline attacker can't rewrite a file's expected hash.
Appraisal mode (ima_appraise=enforce) blocks execution of any file without a valid signature; in 6.6+ this works with both per-file IMA signatures and fs-verity Merkle trees.
Kernel 6.6 added support for IMA namespaces, allowing per-container appraisal policies (a long-standing gap for OCI workloads).
IMA digest lists (introduced in 5.13, refined in 6.x) let you ship a single signed catalog instead of stamping every binary, dramatically reducing the cost of integrity enforcement on a populated filesystem.
For most servers, the pragmatic deployment is: measurement-only in production, appraisal-enforce on bastion hosts, and signing keys live offline in an HSM or YubiHSM.
What is IMA and EVM in Linux?
IMA is the kernel's measurement and appraisal engine. Measurement means: every time a file in scope is opened, mapped, or executed, the kernel computes its digest (the default since 5.10 is SHA-256, configurable via ima_hash=) and appends an entry to an in-kernel measurement log. That log is replayed into TPM PCR 10, so a remote verifier can later cryptographically prove which binaries actually ran on the box. Appraisal goes further: the kernel compares the live hash against the file's security.ima xattr, and on mismatch returns -EPERM from the syscall. That's enforcement, not detection. The bad binary never executes.
EVM exists because xattrs are themselves writable. Without EVM, an attacker with offline disk access could rewrite security.ima to the hash of their tampered binary and IMA appraisal would happily accept it. (I hit this exact gap during a forensic engagement years ago, before EVM was widely deployed.) EVM computes an HMAC (or asymmetric signature) over the security xattrs plus ownership/mode and stores it as security.evm. The HMAC key is sealed to TPM PCR values, so it's only released to a kernel that booted in the expected state. The combination of IMA for content, EVM for metadata, and TPM for the root of trust is what differentiates this from every userspace integrity scanner.
How IMA works at the kernel level
IMA is implemented as an LSM module (since 5.1 it can stack with SELinux and AppArmor under the LSM infrastructure work led by Casey Schaufler). It registers hooks on file_check, mmap_file, bprm_check_security, and kernel_read_file. When a hook fires, IMA consults its in-kernel policy to decide whether the access is in scope, computes the digest if it is, and updates both the measurement log and PCR 10 via a TPM2 extend operation.
The measurement log lives at /sys/kernel/security/ima/ascii_runtime_measurements. A typical entry looks like this:
10 a8b1c2... ima-ng sha256:1f3e... /usr/bin/sshd
The first field is the PCR index; the second is the template hash; ima-ng is the template name; then the file digest and path. The ima-sig template additionally records the file's signature, which Keylime and similar attestation services consume directly. Appraisal mode reads security.ima, recomputes the digest, and if they match, lets the syscall proceed.
There's real overhead here. A cold cache execve on a 50 MB binary is dominated by the SHA-256, which is why most production deployments combine IMA with fs-verity for large files: fs-verity hashes the Merkle root once at file creation and IMA appraises that root, not the whole file.
How does IMA differ from AIDE and Tripwire?
AIDE, Tripwire, and Samhain are userspace file integrity monitors. They snapshot a known-good state of the filesystem into a database, then periodically rescan and report differences. They're excellent for forensics, but they're detective, not preventive, and they trust the filesystem layer they read from. An attacker with root or with offline disk access can rewrite both the file and its database entry; AIDE only catches it on the next scheduled scan, which might be hours or days later. We have an existing breakdown of these tools in our multi-layer intrusion detection system guide.
IMA, in contrast, runs in the kernel on every relevant syscall and refuses non-compliant files outright when configured to enforce. The comparison matters for threat modeling:
Property
IMA + EVM
AIDE / Tripwire
fs-verity (alone)
Enforcement model
Preventive (blocks execve)
Detective (post-hoc scan)
Preventive but read-only files only
Evaluation point
Every open/mmap/exec
Scheduled cron
Every read of a verity file
Root of trust
TPM 2.0 / kernel keyring
Read-only DB on disk
Kernel keyring
Offline-attacker resistant
Yes (EVM HMAC sealed to TPM)
No
Yes (Merkle root signed)
Per-file granularity
Yes (policy by mask, uid, path)
Yes
Whole file only
Performance cost
Hash on first access (cached)
Spike at scan time
Near-zero (per-block)
Remote attestation
Native via PCR 10
None
Indirect
In practice, the three are complementary. fs-verity protects large read-only assets (container images, APKs); IMA+EVM cover system binaries and configuration; AIDE catches drift on data directories where IMA appraisal would be too disruptive.
How to enable IMA measurement and appraisal
Most stock distribution kernels (Fedora 39+, RHEL 9, Ubuntu 24.04 LTS, Debian 12) ship IMA built in but with policy disabled. Start by confirming compile-time support:
# Confirm IMA is compiled in
grep -E 'CONFIG_IMA=|CONFIG_IMA_APPRAISE=|CONFIG_EVM=' /boot/config-$(uname -r)
# Expected on a modern distro kernel:
# CONFIG_IMA=y
# CONFIG_IMA_APPRAISE=y
# CONFIG_IMA_APPRAISE_BOOTPARAM=y
# CONFIG_EVM=y
IMA is driven primarily by kernel command-line parameters and a policy file. The minimum useful boot line for a measurement-only deployment looks like:
The built-in tcb policy measures every executable, every mmap(PROT_EXEC), every file opened for read by root, and every kernel module. After reboot, verify:
sudo head -5 /sys/kernel/security/ima/ascii_runtime_measurements
sudo cat /sys/kernel/security/integrity/ima/policy # active policy (read-only here)
To move to appraisal, you must first label every file in scope with a hash or signature in security.ima. Booting straight into ima_appraise=enforce on an unlabeled rootfs will brick the box. (Ask me how I know.) The accepted procedure is a two-boot rollout: first boot with ima_appraise=fix, which causes IMA to populate missing xattrs as files are accessed; then audit; then switch to enforce.
Writing an IMA policy that doesn't break userspace
The default tcb policy is a sledgehammer. For a production server you almost always write a custom policy. Policies are rule lists evaluated top-to-bottom; the first match wins. Each rule has an action (measure, dont_measure, appraise, dont_appraise, audit) and a set of conditions.
A sensible starting policy for an internet-facing application server:
# /etc/ima/ima-policy
# Skip pseudo filesystems entirely - matching them causes spurious churn
dont_measure fsmagic=0x9fa0 # proc
dont_measure fsmagic=0x62656572 # securityfs
dont_measure fsmagic=0x64626720 # debugfs
dont_measure fsmagic=0x01021994 # tmpfs
dont_measure fsmagic=0x858458f6 # ramfs
dont_appraise fsmagic=0x9fa0
dont_appraise fsmagic=0x01021994
# Measure every executable file mapped or run
measure func=BPRM_CHECK
measure func=MMAP_CHECK mask=MAY_EXEC
# Measure kernel modules and firmware - critical for attestation
measure func=MODULE_CHECK
measure func=FIRMWARE_CHECK
measure func=KEXEC_KERNEL_CHECK
measure func=POLICY_CHECK
# Appraise the same scope: refuse to run unsigned binaries
appraise func=BPRM_CHECK appraise_type=imasig
appraise func=MMAP_CHECK mask=MAY_EXEC appraise_type=imasig
appraise func=MODULE_CHECK appraise_type=imasig
appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig
# Optional: appraise reads by root of sensitive configs
appraise func=FILE_CHECK mask=MAY_READ uid=0 obj_type=etc_t
Load it on the running kernel. You only get one shot per boot, since the file is write-then-sealed:
EVM operates in one of two modes. HMAC mode uses a symmetric key loaded into the kernel's .evm keyring; the key is typically sealed to TPM PCRs so it is only released after a known-good boot. Signature mode uses an asymmetric public key (the private key never touches the host) and works well for immutable read-only filesystems.
For HMAC mode, generate the key once and seal it to TPM 2.0:
# Create a 32-byte key, encrypted under the TPM's SRK
keyctl add trusted kmk "new 32" @u
keyctl pipe $(keyctl search @u trusted kmk) > /etc/keys/kmk.blob
# Derive the EVM HMAC key from it
keyctl add encrypted evm-key "new trusted:kmk 64" @u
keyctl pipe $(keyctl search @u encrypted evm-key) > /etc/keys/evm-key.blob
# On every boot: reload from blob and install into .evm
keyctl add trusted kmk "load $(cat /etc/keys/kmk.blob)" @u
keyctl add encrypted evm-key "load $(cat /etc/keys/evm-key.blob)" @u
keyctl link @u %keyring:.evm
# Activate EVM
echo 1 | sudo tee /sys/kernel/security/integrity/evm/evm
Wire the load step into a systemd unit that runs before local-fs.target. The linux-ima wiki publishes a working unit you can adapt. For systems already using LUKS2 with TPM2 auto-unlock, the same PCR policy (PCRs 0, 2, 4, 7) is reused so a boot configuration change invalidates both the disk key and the EVM key.
Signing files and shipping digest lists
Use evmctl from the ima-evm-utils package (1.5 is current as of 2026) to stamp files. Two flows matter:
# Sign a single binary with an RSA/EC key in PEM format
sudo evmctl ima_sign --key /etc/keys/privkey_ima.pem /usr/bin/sshd
# Hash-only mode (no signature) - useful for early fix runs
sudo evmctl ima_hash /usr/local/bin/myservice
# Generate EVM HMAC over the security xattrs
sudo evmctl hmac --hmackey /etc/keys/evm-hmac-key /usr/bin/sshd
# Verify everything is in place
getfattr -m '^security\.' -d /usr/bin/sshd
For a populated rootfs, individually signing every file is operationally painful and a maintenance nightmare. Since kernel 5.13, IMA supports digest lists: a single signed catalog mapping (path, digest) tuples, with appraisal looking up the runtime digest in the list rather than reading security.ima off every file. RPM 4.18+ and recent dpkg builds emit IMA digest lists at package build time; the ELISA project's tooling demonstrates the end-to-end pipeline from build host to runtime appraisal.
Remote attestation with PCR 10 and Keylime
Measurement is only useful if a separate party can verify what ran. The Linux measurement log plus a TPM quote over PCR 10 is exactly the input a remote attestation service consumes. Keylime, originally from MIT Lincoln Lab and now a CNCF incubating project, is the dominant open-source verifier; release 7.10 (March 2026) added support for IMA digest list verification and IMA namespaces.
The verification flow is roughly: agent on the host sends the measurement log; verifier replays each entry into a software PCR; verifier requests a TPM quote signed by the host's AK; verifier confirms the replayed PCR equals the quoted PCR; verifier then walks the log entries against an allowlist of known-good (path, digest) pairs. Anything outside the allowlist trips an alert.
This is where IMA earns its keep relative to host-local integrity. A compromised root user can read and rewrite local AIDE databases, but cannot forge a TPM quote without the AK private key, which never leaves the chip. NIST's recent draft on hardware roots of trust treats this exact pattern as the reference design for platform integrity. Combine it with kernel hardening via sysctl, and you have a host whose state you can prove, not just hope for.
IMA namespaces for containers in kernel 6.6+
Until 2024, IMA was global to the host kernel. One policy for everything, which meant containers shared the host's appraisal rules and couldn't have their own measurement log. Stefan Berger's IMA namespace work, partially merged in 6.4 and significantly extended in 6.6 and 6.8, changes that. Each user namespace can now load its own policy, maintain its own measurement log under /sys/kernel/security/integrity/ima/ns_$INO/, and extend a per-namespace virtual PCR.
The runtime side is still catching up. containerd 2.0 and CRI-O 1.30 expose namespace creation hooks, but vendor distributions of Kubernetes don't yet wire IMA-NS into pod security policies by default. For now, the realistic deployment is: standalone Podman with --security-opt=ima-policy=/path/to/policy for high-assurance workloads. Full integration into Kubernetes admission controllers remains 2026 forward-looking work. Pair this with our container security guide for the broader runtime story.
Troubleshooting common failures
The single most common failure is "I rebooted into ima_appraise=enforce and now nothing executes". The fix is to add ima_appraise=off at the GRUB prompt for one boot, run evmctl ima_hash --recursive / with the appropriate excludes, and switch back to enforce. Other recurring issues:
"Operation not permitted" on a freshly built binary. The file has no security.ima. Either sign it during the build, or temporarily switch to fix mode.
EVM rejects after package upgrade. RPM/dpkg replaced the file but did not re-emit the EVM HMAC. Re-stamp with evmctl hmac in a post-install hook, or use a distribution with native EVM support (openSUSE Tumbleweed and Fedora 40+ both ship it).
Measurement log gaps after suspend/resume. Known TPM quirk on some firmwares; mitigate by adding ima.ahash_minsize=4096 to disable async hashing on suspend-prone laptops.
Performance degradation on first boot. IMA is hashing every page-cache-cold file on first access. Pre-warm by running find / -type f -exec cat {} + > /dev/null after rollout; subsequent reads hit the IMA cache.
The kernel's IMA template documentation covers the ima-modsig, ima-buf, and evm-sig templates that you will need for advanced deployments, particularly when feeding logs into a SIEM that demands structured records.
Frequently Asked Questions
Does IMA require a TPM?
No. IMA can operate without a TPM, but you lose remote attestation. The kernel will still build the measurement log in memory and enforce appraisal, but PCR 10 is not extended into hardware, so a verifier has no cryptographic proof that the log itself was not tampered with. For local-only hardening (no attestation), TPM-less operation is acceptable; for any compliance regime (FedRAMP High, IEC 62443, the EU CRA's integrity requirements), a TPM 2.0 is effectively mandatory.
What is the ima_policy kernel parameter?
ima_policy= selects one of the kernel's built-in policy templates at boot. Valid values include tcb (measure all executable content read by root), appraise_tcb (the same scope, but enforce), secure_boot (measure and appraise kernel modules and kexec), and fail_securely. Multiple can be combined comma-separated. The built-in policies are starting points only; production deployments override them with a custom file written to /sys/kernel/security/ima/policy early in boot.
Can I use IMA alongside SELinux?
Yes, and you should. Since the LSM stacking work in 5.1, IMA, SELinux, AppArmor, and Landlock all coexist on the security chain. IMA hooks fire before the file content is returned to userspace, SELinux enforces type and role transitions, and Landlock can further restrict a process's filesystem reach. Our companion guide on SELinux and AppArmor hardening shows how to layer the MAC policies; IMA sits below both, at the integrity layer.
How do I recover a system bricked by IMA enforce mode?
At the GRUB menu, press e, append ima_appraise=off ima_policy= to the kernel command line, and boot once. From the recovered system, fix the missing or invalid signatures with evmctl ima_hash --recursive, then re-enable appraisal. Keep a known-good rescue kernel that boots with appraisal disabled; it's much faster than booting installation media.
Is IMA worth deploying on a single-tenant cloud VM?
Generally yes, in measurement-only mode, paired with cloud-provider vTPMs. Azure, GCP, and AWS Nitro all expose virtual TPM 2.0 devices that Keylime can attest. The deployment cost is one boot parameter and a Keylime agent. Appraisal-enforce on cloud VMs is harder to justify because the threat model usually assumes you trust the hypervisor; but for regulated workloads where you do not, enforce mode plus confidential computing (SEV-SNP or TDX) closes that loop.
A hands-on auditd guide for 2026: write persistent audit.rules, search events with ausearch, ship records to Wazuh, Elastic, or Splunk, and tune performance.
A practical, layered guide to Linux USB security in 2026: block rogue devices with USBGuard, udev rules, and kernel module blacklisting. Includes BadUSB defense, audit logging, and SIEM integration.
Deploy confidential VMs on Linux with AMD SEV-SNP and Intel TDX. Covers BIOS setup, QEMU launch flags, remote attestation with snpguest and configfs-tsm, attested LUKS unlock, and an operational hardening checklist for production workloads in 2026.