Integrity Measurement Architecture

The Linux IMA subsystem is responsible for calculating the hashes of files and programs before they are loaded, and supports reporting on the hashes and validate if they adhere to a predefined list. In this guide, we introduce this technology and how it can be enabled in Gentoo Linux.

Introduction
The Linux IMA subsystem introduces hooks within the Linux kernel to support creating and collecting hashes of files when opened, before their contents are accessed for read or execute. The IMA subsystem has 2 subsystems within in it - measure and appraise. Measurement collects the hashes of files, while appraisal compares a collected hash to a stored hash and denies access in the event of a mismatch

To support proven integrity of the files, the IMA measurement subsystem can interact with the TPM chip within the system to protect the collected hashes from tampering by a rogue administrator or application.

The IMA measurement subsystem was added in linux-2.6.30. Appraisal came later, in linux-3.7.

Protection of the extended attribute itself is handled by EVM.

Trusted Computing Base
The Trusted Computing Base defines a set of rules that a properly, integrity-protected system should adhere to. Linux defines 2 policies for this: The policy, which performs measurement, and  which performs appraisal.

Kernel configuration
First of all, enable the IMA subsystem in the Linux kernel configuration.

Kernel command line options
There are 2 important IMA command line options: and

can take 1 of 4 values:
 * enforce causes IMA to appraise files according to policy. Access is denied to the appraised file if the store hash is missing or does not match the collected value. IMA generates new stored hashes for new files and changed files with valid hashes.
 * log is similar to enforce except access is not denied but only logged.
 * off disables all appraisal. The stored hashes aren't checked and new stored hashes are not generated or updated.
 * fix disabled all appraisal, but generates new stored hashes for any file opened for read or without one. Incorrect stored hashes are not fixed, however.

can take 1 of 3 values:
 * tcb measures all executables run, all mmap'd files for execution (such as shared libraries), all kernel modules loaded, and all firmware loaded. Additonally, a files opened for read by root are measured as well.
 * appraise_tcb appraises all files owned by root.
 * secure_boot appraises all loaded modules, firmware, kexec'd kernel, and IMA policies. It also requires them to have an IMA signature as well. This is normally used with the CONFIG_INTEGRITY_TRUSTED_KEYRING option in the kernel in "secure boot" scenario, with the public key obtained from the OEM in firmware or via the MOK (Machine Owner Key) in shim.

can be specified multiple times, and the result is the union of the policies.

Enable i_version mount option (optional)
Mount all file systems with the support (which, sadly, means you need to mount it with  mount option - without the underscore). This is an optimization for IMA, allowing it to only recompute the hash of file when it actually changes instead of every time the file is opened.

For the root file system, it can be enabled through the kernel parameter as well so that it gets mounted immediately with i_version support when the Linux kernel mounts the root file system.

Note that the underscore needs to be present here, unlike in the fstab case.

Registering the file hashes for the system
First boot with the boot option. This will allow the system to boot up even when no (or wrong) hashes are registered.

Next, all files that will be appraised need read Its also possible to use the utility which is part of

However, this will hash all files even if the file has a rule.

When done, the stored hash value should show as an extended attribute:

Finally, reboot with. The system should now run with appraisal enabled, causing the system to validate the hash against the stored value before using it. If it doesn't match, then the file is not loaded and any access towards it will be denied with a Permission denied error.

You can check if this works by booting with and changing the contents of a root-owned file (or the value of the extended attribute) and reboot with, or by directly editing virtual guest images.

Using digital signatures for immutable files
The IMA appraisal code also supports immutable files. In this case, an RSA-key based signature is taken of the file and stored in the extended attribute. The private key is used to sign the files, whereas the public key is used to verify the signature. This provides additional protection against tampering as the private key does not need to be available on the system while its running (only during the initial marking).

To sign such immutable files (like kernel modules and application code),the command provided by the  package needs be used. But first, setup the kernel keyring:

This allows the IMA subsystem to validate the signature (which is also needed when initially setting the signature) by loading the public key onto the IMA keyring. This needs to be done every time the system boots, so it makes sense to do so within an initramfs (early in the boot process):

This private key can be generated first using :

To generate an unencrypted private key (non-protected):

Or an encrypted private key (password-protected):

To generate the public key:

Immutable file support is mainly used to digitally sign the Linux kernel and the kernel modules and is supported through the EVM technology (which we will discuss in different documentation) but works well on ELF and other binaries as well.

Reading the integrity log
To read the integrity log as registered by the IMA subsystem, look at the file:

The columns (from left to right) are:


 * PCR (Platform Configuration Register) in which the values are registered. This only makes sense if a TPM chip is in use.
 * Template hash of the entry, which is a hash that combines the length and values of the file content hash and the pathname
 * Template that registered the integrity value (ima-ng the case)
 * File content hash which is the hash of the file itself

The default hash algorithm is SHA-1.

How do I know IMA with appraisal is working?
This is as simple as finding a file that does not have its hash value stored as an extended attribute while ima_appraise is in enforcing mode.

In the above example, the IMA subsystem reports that the file misses its hash value (which should be stored as security.ima ) and as such is denying the   application access to it.

If you can miss the file (such as with ) you can remove it and regenerate it if you wish:

If you are using SELinux:

Next:

I was able to edit an 'immutable' file and still run it. How come?
If you digitally signed a script using and then edited the file with, then this behavior is to be expected. removes the original file and replaces it with a new one. The newly created file is given an appropriate hash (but no digital signature of course) and thus you can still execute it. Integrity Measurement Architecture/Recipes The use of digital signatures is more for kernel modules and ELF binaries. But below an example of how it does work - if you edit the file rather than replace it.

How do I load a custom IMA policy?
It is possible, and recommended to use a custom IMA policy. A breakdown of the default rules and snippets to rules for be included can by found in Integrity Measurement Architecture/Recipes

Make sure no empty lines are in the policy; if not, it will be refused. You can check the output of for hints why the policy was refused (it shows what was accepted, so the next line would be a not-accepted line), or the audit logs (but you will need to have  running) if you get lines such as audit_printk_skb: XX callbacks suppressed as you then might not have all the information you need.

Have the policy be loaded in as soon as possible, either in an initramfs or early in the boot process through an init script in the sysinit runlevel. I keep my policy in and use the following small init script to load it early on:

Online resources tell me I can use head -n 1 to regenerate the hashes
I have bad experiences with this method. Some files are left without a hash, or when I later enable EVM the EVM hash itself remains missing. The use of the  command does the trick pretty well.