Linux IMA (Integrity Measurement Architecture) is the kernel subsystem that hashes files as they are executed, mapped or read, records those hashes in a log anchored in TPM PCR 10, and can refuse to run a file whose signature or hash does not match. EVM (Extended Verification Module) protects the file metadata, including the stored IMA signature, so it cannot be swapped offline. Together they carry the chain of trust from measured boot into everything the running system loads, and remote attestation tools such as Keylime check that log from another machine.
This guide extends our posts on Secure Boot, trusted boot and measured boot, TPM 2.0 PCRs, unified kernel images and dm-verity. Those stop when the kernel starts; this one starts there.
Key takeaways
- IMA has three features driven by one policy: measurement (hash and log, extend PCR 10), appraisal (verify a hash or signature stored in the
security.imaextended attribute and deny access on failure) and audit (write file hashes into the system audit log). - IMA arrived in Linux 2.6.30 (June 2009), EVM in Linux 3.2 (January 2012), and appraisal, digital signature verification and audit hashes in Linux 3.7 (December 2012), according to the KernelNewbies release notes.
- The first log entry, the
boot_aggregate, hashes PCRs 0 to 9 and ties the runtime log to measured boot. Theima-sigtemplate adds file signatures to the log for remote signature checks. - EVM covers
security.ima, the LSM labels,security.capability, owner, group and mode. Without EVM, an attacker with offline disk access could rewrite the extended attribute that appraisal trusts. - Fedora accepted a change for Fedora Linux 37 to sign every file inside its RPMs with IMA signatures; the signatures land on disk only when
rpm-plugin-imais installed, and no policy is enabled by default. - Keylime, a CNCF sandbox project since 22 September 2020, polls TPM quotes over PCR 10 and checks the IMA log against a runtime policy of known good hashes and keys.
- The safe rollout order is measure, then appraise in
logmode, thenenforce. Skipping the middle step is the most common way to make a machine unbootable.
What do IMA measurement, appraisal and audit do?
The kernel documentation for the policy interface describes IMA in one sentence: it "maintains a list of hash values of executables and other sensitive system files" loaded into the running system. That list is the whole idea. The three features differ in what they do with each hash.
IMA measurement
When a file matches a measure rule in the IMA policy, the kernel reads its contents, computes a hash and appends a record to the measurement list. If the platform has a TPM, the kernel also extends that record's hash into a PCR, by default PCR 10. The IMA project documentation (ima-doc) compares this to pre-OS trusted boot: it records what ran, it does not stop anything from running.
A few properties matter in practice:
- Each file is measured once per content. A binary run a thousand times produces one entry until it changes.
- Measurement is useless without a verifier. The ima-doc concepts page says it "requires both a TPM and an independent verifier". An attacker who owns the machine can rewrite the log but not the PCR, and a remote verifier compares the log with a TPM signed quote.
- The IMA PCR cannot seal secrets. Because many processes run in parallel after boot, the order of extends differs on every boot and so does the final PCR 10 value. The ima-doc concepts page says the IMA PCR is "unsuitable for an unseal TPM authorization". Use PCRs from the pre-OS boot for sealing, and use PCR 10 only for attestation.
IMA appraisal
Appraisal is enforcement. When a file matches an appraise rule, the kernel computes the hash and compares it with what is stored in the file's security.ima extended attribute. The stored value can be:
- A hash (the format byte
0x04, followed by the hash algorithm and digest). This only proves the file has not changed since someone wrote the hash, so it is useful for configuration files that change through legitimate writes. - A signature made with a private key that is not on the machine. The kernel verifies it with a public key on the
.imakeyring. Signed files are effectively immutable and carry provenance.
If verification fails, the open or exec returns Permission denied. The ima-doc page compares appraisal to Secure Boot: it is local, and it "requires neither a TPM nor a separate verifier".
Appraisal has four modes set by the ima_appraise= boot parameter, documented in the kernel parameters list as off, enforce, fix and log, with enforce as the default:
| Mode | What happens on a mismatch | When to use it |
|---|---|---|
enforce | Access denied | Production, after a clean log run |
log | Access allowed, failure written to the audit log | Rollout, to see what would break |
fix | Hash attributes are created or repaired | One-time labeling of hash based appraisal |
off | Appraisal not applied | Debugging (requires the boot parameter to be compiled in) |
Note that fix cannot create signatures, because the private key should never be on the machine. It only writes hashes.
IMA audit
An audit rule writes the file hash into the Linux audit log as a type=INTEGRITY_RULE record with the path, process and user IDs and command. There are no built-in audit policies. It suits forensics and analytics without an attestation service.
Separately, IMA writes its own integrity events to the audit log, such as "open writers" violations (a file opened for read while someone holds it open for write) and "time of measure, time of use" violations (a file opened for write after it was measured).
When did each piece land in the kernel?
| Kernel | Release date | What arrived | Source |
|---|---|---|---|
| 2.6.30 | 9 June 2009 | IMA measurement list, with TPM PCR aggregate | KernelNewbies, Linux 2.6.30 |
| 3.2 | 4 January 2012 | EVM, protecting security extended attributes | KernelNewbies, Linux 3.2 |
| 3.7 | 10 December 2012 | IMA audit log hashes, digital signature verification, the integrity appraisal extension | KernelNewbies, Linux 3.7 |
Later additions such as templates, appended signatures (modsig), the .machine keyring and fs-verity digests arrived over many releases. The ABI file lists options without dates, so check the documentation for your kernel version.
How does the IMA measurement list extend PCR 10?
The log and its location
The measurement list lives in securityfs. The ima-doc event log page lists two formats in two places:
# Older path, still present as a link
/sys/kernel/security/ima/ascii_runtime_measurements
/sys/kernel/security/ima/binary_runtime_measurements
# Newer path
/sys/kernel/security/integrity/ima/ascii_runtime_measurements
/sys/kernel/security/integrity/ima/binary_runtime_measurements
Newer kernels (the page names a window between 6.10.6 and 6.10.11) also expose one log per TPM PCR bank, such as ascii_runtime_measurements_sha256.
A sample from the Keylime runtime integrity documentation shows the ASCII format:
PCR template-hash filedata-hash filename-hint
10 3c93cea361cd6892bc8b9e3458e22ce60ef2e632 ima-ng sha1:ac7dd11bf0e3bec9a7eb2c01e495072962fb9dfa boot_aggregate
10 3d1452eb1fcbe51ad137f3fc21d3cf4a7c2e625b ima-ng sha1:a212d835ca43d7deedd4ee806898e77eab53dafa /usr/lib/systemd/systemd
10 e213099a2bf6d88333446c5da617e327696f9eb4 ima-ng sha1:6da34b1b7d2ca0d5ca19e68119c262556a15171d /usr/lib64/ld-2.28.so
The columns are the PCR index (a rule can choose another with pcr=, but there is still one log), the template hash that was extended into the PCR, the template name, the file data hash, and the file name. The ima-doc page calls the name "a hint": it cannot be trusted alone, but it tells a verifier which approved hash to look up.
The boot aggregate
The first record is always the boot_aggregate. The ima-doc concepts page describes it as a hash of TPM PCRs 0 to 9. That entry is what links the runtime log to everything measured before the kernel took over: firmware, option ROMs, the boot loader and, with a UKI, the kernel and initrd. Our TPM PCR guide covers what lands in each of those PCRs. A verifier that checks the boot aggregate and then replays the rest of the log has one continuous chain from firmware to the last executed binary.
evmctl (from the ima-evm-utils project) has an ima_boot_aggregate command that recomputes the value from the TPM so you can compare it to the first log line.
How the PCR extend works
A PCR can only be extended: the new value is the hash of the old value concatenated with the new measurement. A verifier replays the log from zero, computes the expected PCR 10, and compares it with a quote the TPM signed. The ima-doc event log page lists the subtleties:
- Log append comes before the PCR extend, so a quote may trail the log by a few entries but never lead it. Replay until the quote matches and treat extra entries as pending, not as failure.
- On TPM 2.0 a quote and a PCR read are separate commands. Reading PCR 10 and sending it to the verifier adds nothing, because it is not atomic with the quote.
- Logs are large: about 50 events in a pre-OS log against 10,000 to 100,000 in an IMA log, with around 5,000 at boot. Attest incrementally, keeping the last verified PCR 10 value as state.
kexec and the log
kexec boots a new kernel without resetting the TPM, so PCR 10 keeps its old value. With CONFIG_IMA_KEXEC the old log is carried into the new kernel so a verifier can replay both; without it, PCR 10 proves nothing about the log. The ima-doc page warns that measurements taken between kexec load and execute are still lost. Test attestation across a kexec before relying on it.
What are IMA templates?
A template decides which fields go into each record. The kernel's template documentation explains that the original ima template was fixed length, with a 20 byte digest (MD5 or SHA-1) and a path capped at 255 characters, so a template mechanism was added to define new fields without rewriting the log code. The documented templates are:
| Template | Fields | What it adds | Typical use |
|---|---|---|---|
ima | d, n | Original fixed format | Legacy only |
ima-ng (default) | d-ng, n-ng | Any hash algorithm, unlimited name length | General measurement |
ima-ngv2 | d-ngv2, n-ng | Digest prefixed with type, "ima" or "verity" | fs-verity digests |
ima-sig | d-ng, n-ng, sig | The file signature from security.ima | Attestation with signature checks |
ima-sigv2 | d-ngv2, n-ng, sig | Typed digest plus signature | fs-verity signatures |
ima-buf | d-ng, n-ng, buf | A raw buffer, such as the kexec command line | Measuring data that is not a file |
ima-modsig | d-ng, n-ng, sig, d-modsig, modsig | Appended signature and its digest | Kernel modules and kexec images with appended signatures |
evm-sig | d-ng, n-ng, evmsig, xattr names, lengths, values, uid, gid, mode | The EVM signature and the metadata it covers | Verifying portable EVM signatures remotely |
The default comes from CONFIG_IMA_DEFAULT_TEMPLATE and can be overridden with ima_template= on the command line or template= on a measure rule. The ima-doc event log page frames the choice between ima-ng and ima-sig: a verifier with an approved hash list only needs the hash, while a verifier without one can check the signature, which proves who signed the file but not that this exact version is approved.
How are IMA policies written?
Rule syntax
The policy ABI document gives the grammar. Every rule is an action followed by conditions and options:
rule format: action [condition ...]
action: measure | dont_measure | appraise | dont_appraise |
audit | dont_audit | hash | dont_hash
base: func= mask= fsmagic= fsuuid= fsname= fs_subtype=
uid= euid= gid= egid= fowner= fgroup=
lsm: subj_user= subj_role= subj_type= obj_user= obj_role= obj_type=
option: digest_type= template= permit_directio appraise_type=
appraise_flag= appraise_algos= keyrings= pcr= label=
The func condition is the hook that triggers the rule. The main ones in the ABI:
| func | Fires when | Common action |
|---|---|---|
BPRM_CHECK | A program is executed | measure, appraise |
MMAP_CHECK (also written FILE_MMAP) | A file is mapped executable, such as a shared library | measure, appraise |
FILE_CHECK | A file is opened, filtered by mask | measure, appraise |
MODULE_CHECK | A kernel module is loaded | measure, appraise |
FIRMWARE_CHECK | Firmware is loaded | measure, appraise |
KEXEC_KERNEL_CHECK | A kexec kernel image is loaded | measure, appraise |
KEY_CHECK | A key is added to a keyring | measure |
CRITICAL_DATA | Kernel critical data, such as SELinux state | measure |
SETXATTR_CHECK | Something writes security.ima | appraise, to limit algorithms |
mask filters by access type (MAY_READ, MAY_WRITE, MAY_APPEND, MAY_EXEC). fsmagic and fsuuid scope rules to a filesystem type or one filesystem, and LSM conditions match SELinux or Smack labels, for example skipping var_log_t.
Order matters: rules are evaluated top to bottom, which is why the dont_measure and dont_appraise exclusions for pseudo filesystems come first in every sample policy.
Built-in policies
The kernel parameters documentation lists the built-in policies selected with ima_policy=:
| Policy | What it does |
|---|---|
tcb | Measures every executed program, every file mapped executable, and every file opened for read by uid 0 or euid 0 |
appraise_tcb | Appraises every file owned by root |
secure_boot | Appraises signatures on kexec kernel images, kernel modules, firmware and the IMA policy itself |
fail_securely | Forces signature failures on filesystems that the kernel marks as unverifiable, such as some FUSE mounts |
critical_data | Measures kernel integrity critical data |
You can give ima_policy= more than once and the kernel concatenates them in a fixed order. The older ima_tcb and ima_appraise_tcb parameters are deprecated in favor of ima_policy=.
The ABI file prints the default policy in full: exclusions for proc, sysfs, debugfs, tmpfs and other pseudo filesystems, then measure rules for exec, executable mmap, root reads, modules and firmware, and appraise fowner=0.
Where rules come from, and in what order
Rules come from several places, and some cannot be removed. The ima-doc policy page lists built-in rules from ima_policy=, build time rules from the CONFIG_IMA_APPRAISE_REQUIRE_*_SIGS options, and architecture rules from CONFIG_IMA_ARCH_POLICY. On x86 and Arm UEFI systems with Secure Boot on, the architecture rules require IMA signatures on kexec kernels and modules whenever the kernel's own kexec or module signature checks are not built in, and always measure both. A custom policy replaces the built-in rules, but the architecture and build time rules stay in front of it.
A custom policy is loaded by writing rules into /sys/kernel/security/ima/policy and closing the file. The ABI notes that the new policy takes effect when the file is closed. Unless the kernel was built with CONFIG_IMA_WRITE_POLICY, you get one write; after that the policy is fixed until reboot. systemd and dracut both have hooks to load a policy at boot, and the Keylime documentation notes that on Fedora and Debian the file systemd loads is /etc/ima/ima-policy. If CONFIG_IMA_APPRAISE_REQUIRE_POLICY_SIGS or the secure_boot policy is active, the policy file itself must be signed, and you load it by writing its path rather than its contents.
What does a sane starting policy look like?
The ima-doc policy design page says to measure stable, well known files (binaries, libraries, system configuration) and not fast changing ones (logs, databases): the TPM is slow, each record is around 300 bytes, and a verifier cannot approve a hash it has never seen. A first measurement policy, close to Keylime's documented sample:
# Pseudo filesystems: never measure or appraise
dont_measure fsmagic=0x9fa0 # proc
dont_measure fsmagic=0x62656572 # sysfs
dont_measure fsmagic=0x64626720 # debugfs
dont_measure fsmagic=0x01021994 # tmpfs
dont_measure fsmagic=0x858458f6 # ramfs
dont_measure fsmagic=0x73636673 # securityfs
dont_measure fsmagic=0xf97cff8c # selinuxfs
dont_measure fsmagic=0x27e0eb # cgroup
dont_measure fsmagic=0x63677270 # cgroup2
dont_measure fsmagic=0x6e736673 # nsfs
# Fast changing files, by SELinux type
dont_measure obj_type=var_log_t
dont_measure obj_type=auditd_log_t
dont_measure obj_type=tmp_t
# What to measure
measure func=BPRM_CHECK
measure func=FILE_MMAP mask=MAY_EXEC
measure func=MODULE_CHECK uid=0
This measures programs, libraries and modules and skips root's file reads, the noisiest part of tcb. It enforces nothing. A first appraisal policy, run in log mode at first:
# same dont_appraise exclusions as above, then:
appraise func=BPRM_CHECK appraise_type=imasig
appraise func=MMAP_CHECK mask=MAY_EXEC appraise_type=imasig
appraise func=MODULE_CHECK appraise_type=imasig|modsig
appraise func=SETXATTR_CHECK appraise_algos=sha256,sha384,sha512
The last rule, from the ABI examples, stops anyone writing a security.ima value that uses a weak hash.
What does EVM protect, and why does appraisal need it?
The problem EVM solves
IMA appraisal trusts security.ima. A signature there cannot be forged without the private key, but a hash can be rewritten by anyone who mounts the disk offline. Neither covers the other metadata that controls what a file can do, such as its SELinux label, file capabilities or setuid bit.
The ima-doc concepts page describes EVM as the component that "detects tampering of file meta-data". It covers this set:
security.imasecurity.selinux(when SELinux is enabled)security.SMACK64and, with an extra build flag, the other Smack attributessecurity.apparmor(when AppArmor is enabled)security.capability- uid, gid and mode
- inode number and generation, except in a portable signature
EVM appraisal checks security.evm first, then security.ima. Because security.ima is inside the EVM coverage, a valid EVM value protects both the metadata and, through the IMA hash or signature, the file data. EVM does not cover the file name. The ima-doc page gives the example that a binary renamed from mv to rm still passes appraisal, though the new name is measured.
The same appraise rules trigger EVM if EVM is enabled. There are no separate EVM policy rules.
EVM HMAC versus EVM signatures
security.evm comes in two forms, and they suit different jobs.
| EVM HMAC | EVM signature | |
|---|---|---|
| Format byte | 0x02 | 0x03 |
| Algorithm | HMAC-SHA1, fixed | Asymmetric, RSA or ECC |
| Key location | A symmetric key on the machine, wrapped by a TPM sealed master key | Private key off the machine, public key on the .evm keyring |
| Updates on write | Yes, the kernel recomputes it | No, the file must be re-signed elsewhere |
| Protects against | Offline tampering | Offline and runtime tampering |
| Portable across machines | Only if every machine shares the HMAC key | Yes, with a portable signature |
| Good for | Mutable files, configuration | Immutable files, binaries, packages |
For HMAC, the ima-doc page describes a TPM sealed master key that decrypts the HMAC key at boot, and notes that the unseal "typically does not currently use TPM authorization", so the key is not bound to a known good boot by default.
Portable signatures exclude the inode number and generation, which differ on every filesystem, so a package builder can sign a file once and the signature stays valid wherever it is installed. The ima-evm-utils documentation calls out the main use as putting the file data and metadata signature inside a distribution package.
Turning EVM on
EVM has no boot parameter for its policy. It starts off and is switched on by writing a bitmask to securityfs. The kernel's EVM ABI document lists the bits:
| Bit | Value | Effect |
|---|---|---|
| 0 | 0x1 | Enable HMAC validation and creation |
| 1 | 0x2 | Enable digital signature validation |
| 2 | 0x4 | Permit modification of EVM protected metadata at runtime (deprecated) |
| 3 | 0x8 | Require asymmetric signatures to be version 3 |
| 31 | 0x80000000 | Lock: no further changes to the EVM setting |
Writing 0x80000002 enables signature validation and locks it, which is the setting for a machine that uses signed, portable EVM signatures and loads no HMAC key. Writes are additive; bits cannot be cleared. The ABI document says keys should be loaded and EVM signaled "as early as possible", normally in the initramfs, and that dracut (through its 97masterkey and 98integrity modules) and systemd both support loading keys at boot. Until keys are loaded, EVM returns INTEGRITY_UNKNOWN for every file.
Keyrings: where trust actually comes from
Appraisal is only as trustworthy as the keys it accepts. The ima-doc concepts page lists the keyrings involved:
.builtin_trusted_keys: certificates compiled into the kernel..machineand.platform: populated at boot from UEFI Secure Bootdband from Machine Owner Keys (MOK) enrolled withmokutil. If Secure Boot is disabled, neither keyring gets keys..secondary_trusted_keys: certificates added at runtime, which must be signed by a key already on the built-in, machine or secondary keyring..ima: the keys IMA appraisal uses. Only certificates signed by a key on the built-in, secondary or machine keyrings can be added. They are loaded at boot from/etc/keys/imaby a dracut script, and cannot be compiled in..evm: keys for EVM signatures, loaded from/etc/keys/x509_evm.der, again only if signed by a trusted key..blacklist: revoked keys and hashes, from UEFIdbxand similar lists.
So to trust your own signing key you need a CA the kernel already trusts, usually enrolled as a MOK so it lands on .machine, and then an IMA certificate issued by that CA on .ima. A measure func=KEY_CHECK rule logs every key added, so a verifier can see which keys a machine accepted.
How do distributions ship file signatures in packages?
Fedora
Fedora is the clearest primary source. The Fedora change proposal "Signed RPM Contents", owned by Peter Robinson and Patrick Uiterwijk and categorized as accepted for Fedora Linux 37, says that during signing "the files in it will be signed with IMA signatures", using a key kept by Fedora Infrastructure. The design choices it documents are worth copying for any internal package pipeline:
- Signatures live in the RPM header, not in a side package. RPM writes them to
security.imaonly when therpm-plugin-imaplugin is installed. Without the plugin nothing changes on disk. - No policy is installed by default. The proposal says users "will need to deploy their own policy before anything is measured or appraised". Fedora IoT planned sample policies.
- The cost is small. In the proposal's measurement, binary RPMs for a default Server install grew by about 1.1 percent, and the installed system by about 0.3 percent, mostly from a larger RPM database. The key was a prime256v1 (P-256) ECDSA key.
- It is better than
rpm -V. The proposal points out that an attacker who can change files can also change the RPM binary or database to hide it, while IMA lets the kernel refuse the file.
To check a Fedora system, the proposal gives two commands:
# Is a signature present on the file?
getfattr -d -m security.ima /usr/bin/bash
# Verify it against Fedora's public certificate
evmctl ima_verify --key publiccert.der -v /usr/bin/bash
The proposal names Keylime as an attestation consumer and explains why fs-verity and the Digest Lists Integrity Module were not chosen instead.
RHEL, CentOS Stream and derivatives
Red Hat publishes a chapter on the kernel integrity subsystem in its RHEL documentation, and the Keylime documentation has an installation section for "RHEL 9 or later". Our scripted fetch of the Red Hat documentation was refused, so we do not restate which RHEL minor release first shipped signed package payloads or where its IMA certificates are installed. Check the "Enhancing security with the kernel integrity subsystem" chapter for your RHEL version and confirm with getfattr on a test system.
Debian and Ubuntu
Ubuntu packages ima-evm-utils (its evmctl manual page is on manpages.ubuntu.com), and the Keylime documentation describes /etc/ima/ima-policy as the policy location on both Fedora and Debian. We found no primary Debian or Ubuntu source saying .deb packages carry per-file IMA signatures, so treat signed payloads there as something you add yourself. The ima-doc utilities page shows the pattern: sign with a portable signature at build time and use an archive format that keeps the extended attributes.
evmctl sign --imasig -a sha256 --portable --m32 --key privkey_ima.pem ./tool
tar -c --xattrs-include security.ima --xattrs-include security.evm -f tool.tar tool
The ima-doc page warns that uid, gid and mode must be final before you sign, because a portable EVM signature covers them.
What this means for your own software
Distribution signatures cover distribution files. An internal agent, a Python virtual environment or a container root filesystem has no IMA signature until you add one, and an enforcing signature policy will stop it running. Add a signing step to your build pipeline with a key held in a hardware module or signing service, issued by an IMA CA enrolled through MOK.
How does remote attestation use the IMA log?
The general pattern
Remote attestation answers one question: is this machine running what I expect? With IMA, the steps are:
- The verifier sends a fresh nonce to an agent on the machine.
- The agent asks the TPM for a quote over PCR 10 (and usually the boot PCRs), signed by an attestation key, including the nonce.
- The agent sends the quote and the measurement log.
- The verifier checks the quote signature and nonce, replays the log to recompute PCR 10, checks that the boot aggregate matches the expected boot PCRs, and then checks every entry against policy.
- If anything fails, the verifier marks the machine as untrusted and triggers whatever response is configured.
Our TPM and software supply chain post and the remote attestation fundamentals post cover the TPM side in more depth.
Keylime
Keylime is the open source attestation system most often paired with IMA. Its site describes it as a "CNCF hosted project" for "remote boot attestation and runtime integrity measurement", originally from MIT Lincoln Laboratory, built on the Linux TPM2 software stack. The CNCF project page says Keylime was accepted on 22 September 2020 at the sandbox maturity level. The documentation at the time of writing is version 7.14.3.
Keylime has an agent on each machine, a registrar for agent TPM keys, a verifier that checks quotes, and a tenant command line for enrollment. Recent documentation adds a push model where agents send evidence.
For IMA, the verifier holds a runtime policy. The Keylime documentation defines it as "a set of 'golden' cryptographic hashes of files' un-tampered state or of keys that may be loaded onto keyrings for IMA verification". The verifier polls quotes over PCR 10 and compares every new log entry to the policy; a hash that is not in the policy, or a key loaded onto a keyring that is not allowed, fails attestation and can trigger revocation actions.
Keylime documents two ways to build the policy:
- From a known good system. Its tooling generates a policy from the initramfs, the IMA log and files on the root filesystem, or directly from an
ascii_runtime_measurementsfile. The documentation describes akeylime-policytool and shows the olderkeylime_create_policyandcreate_runtime_policy.shhelpers. - From signatures ("key learning"). If files carry IMA signatures from a trusted packager, Keylime can verify the signature carried in the log instead of matching every hash. This requires the
ima-sigtemplate. The Keylime documentation gives the Fedora command line for this setup:ima_appraise=fix ima_template=ima-sig ima_policy=tcb, and notes that signature enforcement on the machine is not needed, because measuring is enough for the verifier to check signatures remotely.
That second mode is where signed packages and attestation meet: a fleet can be attested against the distribution's key plus a short hash list for local files, rather than a hash list rebuilt after every update. Keep the verifier itself patched and on more trusted infrastructure than the machines it attests; we covered one Keylime flaw in a registrar TLS bypass post.
How does fs-verity relate to IMA?
fs-verity is a kernel feature for read-only files on a read-write filesystem. The kernel documentation describes it as working "on files rather than block devices", in the same spirit as dm-verity. When userspace enables verity on a file, the filesystem builds a Merkle tree for it and the file becomes read-only. Every read, including mmap reads, is verified against the tree as pages come in, and a corrupted read fails. Retrieving the file's verity digest takes constant time regardless of file size. ext4 has supported it since Linux 5.4; the documentation also lists f2fs and btrfs.
The key difference is timing. IMA hashes the whole file once at open; fs-verity verifies each page every time it is read from storage, so malicious disk firmware cannot change it unnoticed at runtime. The cost is that the file becomes immutable.
The two now work together. The fs-verity documentation says IMA "supports fs-verity file digests as an alternative to its traditional full file digests". The policy ABI shows how:
measure func=FILE_CHECK digest_type=verity template=ima-ngv2
measure func=BPRM_CHECK digest_type=verity template=ima-sigv3
appraise func=BPRM_CHECK digest_type=verity appraise_type=sigv3
With digest_type=verity, IMA uses the fs-verity digest instead of hashing the full file, and the v2 templates mark the digest type for the verifier. Signatures over verity digests use format version 3 (sigv3).
The fs-verity documentation also mentions the Integrity Policy Enforcement LSM (IPE), which makes allow or deny decisions from immutable file properties, including fs-verity built-in signatures and dm-verity root hashes. It is a separate LSM, an alternative to IMA appraisal on verity based systems.
Comparison: IMA, EVM, dm-verity, fs-verity, Secure Boot and module signing
| Mechanism | What it checks | When it checks | Granularity | Where the trust anchor lives | Enforces or records |
|---|---|---|---|---|---|
| UEFI Secure Boot | Signatures on boot loader, shim, kernel image | Once, at load during boot | Per boot image | UEFI db and dbx, MOK | Enforces |
| Measured boot (TPM PCRs 0 to 9) | Hashes of firmware, boot loader, kernel, initrd | Once, at load during boot | Per boot component | TPM, checked by remote verifier | Records |
| Kernel module signing | Appended signature on each module | At module load | Per module | Kernel built-in and machine keyrings | Enforces |
| IMA measurement | Hash of file content | First access per content version | Per file | TPM PCR 10, checked by remote verifier | Records |
| IMA appraisal | Hash or signature in security.ima | First access per content version | Per file | .ima keyring | Enforces |
| EVM | HMAC or signature over security xattrs and inode metadata | With IMA appraisal | Per file metadata | TPM sealed HMAC key or .evm keyring | Enforces |
| dm-verity | Merkle tree over a block device | Every block read from disk | Per block, whole volume | Root hash, often signed or in a UKI | Enforces |
| fs-verity | Merkle tree over one file | Every page read from disk | Per page, per file | File digest, checked by IMA, IPE or userspace | Enforces reads, authentication needs a policy |
Read it as layers. Secure Boot and measured boot cover the path to the kernel, module signing covers what the kernel loads into itself, and IMA with EVM covers what userspace runs from a mutable filesystem. A system with an immutable root on dm-verity gets most of appraisal's value for the root with less policy work, and can still use IMA for writable paths and attestation. Our Linux package signing post covers the package layer.
Step by step: measure, sign, appraise in log mode, then enforce
Warning: the steps below change the kernel command line and the kernel's file access policy. A wrong appraisal policy in
enforcemode can stopinit, the shell or the package manager from running, which leaves the machine unbootable. Do this in a disposable virtual machine with a snapshot first, keep a second boot entry without the IMA parameters, and keep console access. Never test on a machine you cannot reach physically or through an out of band console.
Step 1: check what your kernel supports
uname -r
grep -E 'CONFIG_IMA|CONFIG_EVM|CONFIG_INTEGRITY' /boot/config-$(uname -r)
# or, if the config is exposed through procfs
zgrep -E 'CONFIG_IMA|CONFIG_EVM' /proc/config.gz
Look for CONFIG_IMA, CONFIG_IMA_APPRAISE, CONFIG_IMA_APPRAISE_BOOTPARAM (for the log and fix modes), CONFIG_INTEGRITY_SIGNATURE, CONFIG_EVM and CONFIG_IMA_READ_POLICY. The ima-doc configuration page explains each.
Check for a TPM 2.0 the way the Keylime site does:
cat /sys/class/tpm/tpm*/tpm_version_major
Install the tools. On Fedora and Ubuntu the packages are ima-evm-utils and keyutils according to the ima-doc utilities page:
sudo dnf install ima-evm-utils keyutils attr # Fedora, RHEL family
sudo apt install ima-evm-utils keyutils attr # Debian, Ubuntu
Step 2: turn on measurement only
Add measurement parameters to the kernel command line. On Fedora and the RHEL family, grubby edits every installed kernel entry:
sudo grubby --update-kernel=ALL --args="ima_policy=tcb ima_template=ima-sig ima_hash=sha256"
On Debian and Ubuntu, add the same parameters to GRUB_CMDLINE_LINUX in /etc/default/grub and run sudo update-grub. Reboot and confirm:
cat /proc/cmdline
Set ima_hash=sha256 explicitly: the kernel parameters list still documents SHA-1 as the default.
If you prefer a custom measurement policy to tcb, write the policy from the earlier section to /etc/ima/ima-policy and drop the ima_policy= parameter. systemd loads that file early in boot.
Step 3: read the measurement list
sudo head -5 /sys/kernel/security/ima/ascii_runtime_measurements
sudo wc -l /sys/kernel/security/ima/ascii_runtime_measurements
sudo cat /sys/kernel/security/ima/policy # needs CONFIG_IMA_READ_POLICY
The first line must be boot_aggregate. Watch the line count over a day to understand how fast your log grows; if it keeps climbing, something frequently changing is matching a measure rule and should be excluded.
evmctl can recompute the boot aggregate and replay the binary log against the TPM. The general shape, per the ima-evm-utils usage text:
sudo evmctl ima_boot_aggregate --hwtpm
sudo evmctl ima_measurement --verify-bank sha256 \
/sys/kernel/security/ima/binary_runtime_measurements
Option names differ between ima-evm-utils releases, so check evmctl help ima_measurement on your version.
Step 4: create an IMA CA and a signing key
For a lab, follow the ima-doc utilities page: create an IMA CA, enroll it as a Machine Owner Key so the kernel trusts it, then issue a signing certificate from it. A trimmed version:
# CA key and self signed certificate (imacacert.cfg sets CA:TRUE and keyCertSign)
openssl req -new -x509 -out imacacert.pem -sha256 \
-pkeyopt rsa_keygen_bits:3072 -days 3650 -batch \
-config imacacert.cfg -keyout imacakey.pem
openssl x509 -in imacacert.pem -out imacacert.der -outform der
# Stage the CA for MOK enrollment; confirm it in the firmware menu at next boot
sudo mokutil --import imacacert.der
After the reboot, keyctl show %keyring:.machine should list your CA. The ima-doc page notes this needs Secure Boot and the CONFIG_INTEGRITY_CA_MACHINE_KEYRING_MAX option, or the CA lands on .platform, which cannot vouch for .ima certificates.
Then create a signing key and a certificate signed by the CA (the ima-doc page gives a full openssl configuration with digitalSignature key usage), convert it to DER, and load it:
sudo mkdir -p /etc/keys/ima
sudo cp imacert.der /etc/keys/ima/
# load now for testing; dracut's integrity module loads /etc/keys/ima at boot
sudo evmctl import imacert.der $(sudo keyctl show %keyring:.ima | awk 'NR==1{print $1}')
sudo keyctl show %keyring:.ima
In production the private keys belong in a hardware security module or signing service, never on the machine being protected. The ima-doc page says the same: "The private key should not be available on the system".
Step 5: sign a file and verify it
cp /usr/bin/true ./demo-tool
sudo evmctl ima_sign --key imakey.pem -a sha256 ./demo-tool
getfattr -m - -e hex -d ./demo-tool
evmctl ima_verify --key imacert.der ./demo-tool
ima_sign writes only security.ima. If you want EVM coverage as well, the ima-doc utilities page describes evmctl sign --imasig, which writes the IMA signature and then an EVM signature over the metadata, and the --portable flag for signatures that survive installation on another machine.
Step 6: turn on appraisal in log mode
Change the command line so appraisal runs but only logs:
sudo grubby --update-kernel=ALL --args="ima_appraise=log"
Add appraise rules to /etc/ima/ima-policy after the exclusions. Start narrow: one filesystem or one directory tree you have fully signed, scoped with fsuuid=, rather than everything owned by root. Reboot, then exercise the workload for long enough to cover startup, updates, cron jobs and shutdown.
Look for failures in the audit log and kernel messages:
sudo ausearch -m INTEGRITY_DATA,INTEGRITY_STATUS,INTEGRITY_RULE -ts boot
sudo dmesg | grep -i ima
Each file that would have been denied needs a decision: sign it, exclude it with dont_appraise because it is legitimately mutable, or remove it.
Step 7: enforce
When a full cycle of the workload produces no unexpected failures, remove ima_appraise=log. The kernel parameters list gives enforce as the default, so removing the parameter is enough; being explicit is clearer:
sudo grubby --update-kernel=ALL --remove-args="ima_appraise=log" --args="ima_appraise=enforce"
Keep the rescue entry until you have rebooted several times and applied a package update under enforcement.
Step 8: enable EVM signatures and lock
Once files carry EVM signatures and your EVM certificate is in /etc/keys/x509_evm.der, enable signature verification and lock the setting early in boot (the ABI documents both dracut and systemd support):
echo 0x80000002 | sudo tee /sys/kernel/security/integrity/evm/evm
Use HMAC mode (bit 0) only if you have set up the TPM sealed master key and encrypted HMAC key described earlier.
Step 9: attest
Install the Keylime agent on the machine and the registrar and verifier on a more trusted host, per Keylime's installation guide. Build a runtime policy or configure signature verification, enroll the agent with the tenant, and confirm that running an unlisted binary fails attestation.
Common mistakes
Enforcing before measuring. Turning on appraise in enforce mode on day one, without a log period, is the fastest way to an unbootable machine. The system will refuse the first unsigned helper script, systemd generator or local binary. Measure first, then appraise in log, then enforce.
Policies that brick boot. An appraise rule that covers files read by the initramfs, /sbin/init or the shell, without signatures on those files, stops the boot. So does a measure rule on a fast changing file that floods the log on a memory constrained device. Keep the pseudo filesystem exclusions at the top, test in a snapshot, and keep a boot entry without the IMA parameters.
Unsigned interpreters and scripts. With python3 script.py the kernel executes the interpreter and the script is just a file it reads, so a BPRM_CHECK rule does not appraise the script. Cover script locations with FILE_CHECK rules, or accept that signed interpreters running unsigned scripts are a gap.
Using hash appraisal without EVM. A hash in security.ima with no EVM protection can be rewritten offline. If you rely on hashes rather than signatures, enable EVM.
Measuring with SHA-1. The kernel parameter documentation still lists SHA-1 as the ima_hash default. Set SHA-256 or stronger explicitly, and restrict accepted algorithms with appraise func=SETXATTR_CHECK appraise_algos=.
No key rotation plan. Plan how a new certificate reaches /etc/keys/ima on every machine, how long old and new keys overlap, how files are re-signed, and how a revoked key reaches .blacklist or the verifier policy. A signed binary stays valid as long as its key is trusted.
Confusing signed with safe. A signature says who built a file. It says nothing about whether the file contains a known vulnerability. A signed library with a critical CVE passes appraisal every time.
FAQ
Does IMA require a TPM?
No for appraisal and audit, yes for meaningful measurement. Appraisal verifies hashes and signatures locally against keys on the .ima keyring and works without a TPM. Measurement still writes a log without one, but nothing anchors it, so a remote verifier cannot trust it.
What is the difference between IMA and EVM?
IMA covers file contents: it hashes them, logs them and checks them against a hash or signature. EVM covers file metadata: security extended attributes including security.ima, plus owner, group and mode. Appraisal without EVM leaves the stored IMA value open to offline tampering.
What is PCR 10 used for in Linux?
By default it holds the running aggregate of the IMA measurement list. The kernel extends each new log entry's template hash into PCR 10, and a TPM quote over PCR 10 lets a verifier prove the log was not edited. The PCR index can be changed at build time with CONFIG_IMA_MEASURE_PCR_IDX.
What is the difference between ima-ng and ima-sig?
ima-ng records the file hash and file name. ima-sig adds the file's signature from security.ima. Use ima-sig if your verifier checks signatures instead of, or as well as, a hash allowlist.
Does Fedora sign RPM files for IMA?
Yes. The "Signed RPM Contents" change, accepted for Fedora Linux 37, signs individual files in Fedora RPMs with IMA signatures. They are written to disk only with rpm-plugin-ima installed, and Fedora ships no enforcing policy by default.
Can IMA stop a script from running?
Only if your policy appraises the script file itself, typically with FILE_CHECK rules covering the script's location. A rule on program execution checks the interpreter binary, not the script it reads.
What does Keylime do with IMA?
Keylime's verifier polls TPM quotes over PCR 10 from an agent, replays the IMA log, and checks each entry against a runtime policy of approved hashes and keys or against trusted signing keys. A mismatch marks the machine as failed and can trigger revocation actions.
Does IMA protect against attacks in memory?
No. The ima-doc threat model lists memory attacks as out of scope. IMA checks files when they are accessed; changes to process memory after that are not seen.
Where Safeguard fits, honestly
Safeguard does not configure IMA, manage TPMs, run attestation or protect endpoints. The fit is upstream of the signature: IMA proves a file is the one your build produced, not that it is free of known vulnerabilities. Before you sign an internal agent, a container root filesystem or a Python environment for an IMA protected fleet, Safeguard can scan the repository, the image or an SBOM for vulnerable components and show which projects carry a given version, so the thing you sign is something you would also approve on a vulnerability basis. Remediation pull requests can move a dependency to a fixed version before the next signed build. The kernel, the IMA policy and the keys remain your platform team's job.
A signed package is only as good as what went into it, and a rebuilt, re-signed agent pulls its dependencies again. The open source components inside the software you sign for IMA are where the next fix will have to come from.
Fix it without waiting for upstream
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.
3. Gold Registry: start from components that are already fixed
Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | Safeguard policies and gates in CI |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
This demo is a real Safeguard CLI session: it finds a vulnerable lodash version in a repository, edits the manifest, runs the install and tests, and asks before any command that changes something. The same flow applies to the agent or tool you are about to sign for an IMA fleet: fix the vulnerable dependency in the source, then build and sign.
Click through it at your own pace, or open it full screen.
The local runner demo shows setting up the runner on your own machine, approving it with a device code and scanning from the terminal. For teams that build and sign packages on an isolated build host, this is the shape of running scans next to the build rather than on the protected machines.
Click through it at your own pace, or open it full screen.
The last demo connects Claude to the Safeguard MCP server with OAuth and chooses which tools Claude may use. A platform engineer can then ask which projects carry a vulnerable component before cutting a new signed release.
Click through it at your own pace, or open it full screen.
To try it yourself, download Safeguard or read the CLI documentation.
Quick check
Why can the IMA PCR not be used to seal a disk encryption key?
Because processes run in parallel after boot, the order of IMA extends, and therefore the final PCR 10 value, differs on every boot. Seal to pre-OS PCRs instead and use PCR 10 only for attestation.
An attacker mounts a disk offline, edits a root owned config file and updates its security.ima hash. What stops this?
EVM. With EVM enabled, security.ima is covered by an HMAC or signature in security.evm, so a rewritten hash no longer verifies. Hash based appraisal without EVM would accept the change.
Sources
- Linux kernel: IMA policy ABI (ima_policy)
- Linux kernel: EVM ABI
- Linux kernel: kernel parameters (ima_appraise, ima_policy, ima_template, ima_hash, evm)
- Linux kernel: IMA Template Management Mechanism
- Linux kernel: fs-verity
- Linux kernel: Integrity Policy Enforcement (IPE)
- IMA documentation: IMA and EVM concepts
- IMA documentation: IMA configuration
- IMA documentation: IMA policy
- IMA documentation: IMA event log
- IMA documentation: utilities (evmctl, keyctl, mokutil, keys)
- linux-integrity/ima-evm-utils on GitHub
- Ubuntu manual page: evmctl
- Fedora Project: Changes/Signed RPM Contents
- Keylime project site
- Keylime documentation
- Keylime documentation: Runtime Integrity Monitoring
- CNCF: Keylime project page
- KernelNewbies: Linux 2.6.30
- KernelNewbies: Linux 3.2
- KernelNewbies: Linux 3.7
Last reviewed: 25 October 2026. Kernel options, keyring behavior and distribution signing change between releases; check the kernel documentation for your version and your distribution's own guide before enforcing a policy.