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 measuring the integrity of files that are loaded (including application code) before it is executed or mmaped to memory. The measured value (hash) is then registered in a log that can be consulted by administrators.

To support proven integrity of the files, the IMA subsystem can interact with the TPM chip within the system to protect the registered hashes from tampering by a rogue administrator or application. The IMA subsystem, as already supported by the Linux kernel, supports reporting on the hashes of files and commands ran by privileged accounts (and more if you create your own measurement policies).

Since kernel 3.7, an additional patch, called the IMA appraisal patch, has been merged within the IMA subsystem so it can even register the measured value as an extended attribute, and after subsequent measurement(s) validate this extended attribute against the measured value and refuse to load the file (or execute the application) if the hash does not match. In that case, the IMA subsystem allows files and applications to be loaded if the hashes match (and will save the updated hash if the file is modified) but refuse to load it if it doesn't. This provides some protection against offline tampering of the files.

Protection of the extended attribute itself is handled by EVM, which is discussed in a separate document.

Trusted Computing Base
The Trusted Computing Base defines a set of rules that a properly, integrity-protected system should adhere to. The Linux IMA subsystem supports this set of rules through the ima_tcb policy. This policy roughly states that all files read by root (applications, but also regular files, libraries, ...) need to be measured and registered against the security log, as well as application binaries when ran (or mmaped for execution) by any user.

The Big Fat Warnings
Using IMA on your system is currently only recommended for development purposes. Gentoo Hardened is working on integrating IMA properly, so please be aware that:


 * users might be able to have your machine run out of (kernel) memory by having (root-owned) processes generate new files over and over again, which all get measured and their hashes stored
 * the system might have issues booting if not all files have their hash registered properly; you are easily warned if this is the case through the Linux audit subsystem

We are working on fine-tuning the default policies so that measurements only occur on legitimate resources.

Kernel configuration
First of all, enable the IMA subsystem in the Linux kernel configuration. IMA is supported in the main tree since 2.6.30, and IMA appraisal (needed when you want the system to stop if it detects an off-line modified file) is merged in the main tree since 3.7.

Bootloader configuration
Next, configure the bootloader to enable the TCB policy:

Bootloader configuration to enable IMA TCB policy

We currently set  because the integrity hashes have not been stored yet. If we would run with  immediately, the system would simply refuse to boot properly as all file accesses would be denied. We will switch to  later.

Enable security file system
Finally, have the security file system mounted (if this is not already the case):

Enable i_version mount option
Mount all file systems with the i_version support (which, sadly, means you need to mount it with  mount option - without the underscore). This is needed for IMA to detect changes on files, allowing it to remeasure the hash of the file.

Enabling i_version on all mounts

For the root file system, you might want to enable it 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.

Using rootflags in the bootloader configuration

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, have all files on the file system checked and their value stored as an extended attribute. We use the  command for this (which is provided by the ima-evm-utils package). Note that this will take a long time and will take a lot of memory (as the measurement log for IMA is filled up).

You might also need to bind-mount the root file system somewhere (like on ) and do the same for the location as well as other locations that contain files but become hidden once the system mounts another file system on top of it.

When done, you should be able to see the registered hash value 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. If it does match, and afterwards the file is modified, then the new hash is stored as extended attribute.

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), you need to use the  command provided by the  package (currently only available in the hardened-dev overlay). 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. You will need to do this 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:

What you see here are:


 * The PCR (Process Control Register) in which the values are registered. This only makes sense if you have a TPM chip in use.
 * The hash of the hash of the file + filename (padded with null characters to the length of 255 bytes)
 * The subsystem that registered the integrity value (ima in our case)
 * The hash of the file content

Unless you have asked for a different hashing algorithm, the default one will be used which is the SHA-1 hashing algorithm.

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.

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 in my own, custom IMA policy?
You can load in an IMA policy by  'ing it into. If the policy is accepted, then the command will succeed and the (pseudo)file will disappear (this is by design, so that malicious users cannot alter the policy once loaded).

Below is an example custom policy, taken from the default one with one addition: ask it not to measure and appraise log files (through the use of the SELinux  attribute).

Example IMA custom policy

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:

Init script to load a custom ima policy

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.