Menu Close

Chapter 20. Enhancing security with the kernel integrity subsystem

You can increase the protection of your system by utilizing components of the kernel integrity subsystem. The following sections introduce the relevant components and provide guidance on their configuration.

20.1. The kernel integrity subsystem

The integrity subsystem is a part of the kernel which is responsible for maintaining the overall system’s data integrity. This subsystem helps to keep the state of a certain system the same from the time it was built thereby it prevents undesired modification on specific system files from users.

The kernel integrity subsystem consists of two major components:

Integrity Measurement Architecture (IMA)
  • Measures files' content whenever it is executed or opened. Users can change this behavior by applying custom policies.
  • Places the measured values within the kernel’s memory space thereby it prevents any modification from the users of the system.
  • Allows local and remote parties to verify the measured values.
Extended Verification Module (EVM)
  • Protects files' extended attributes (also known as xattr) that are related to the system’s security, like IMA measurements and SELinux attributes, by cryptographically hashing their corresponding values.

Both IMA and EVM also contain numerous feature extensions that bring additional functionality. For example:

  • Provides local validation of the current file’s content against the values previously stored in the measurement file within the kernel memory. This extension forbids any operation to be performed over a specific file in case the current and the previous measure do not match.
EVM Digital Signatures
  • Allows digital signatures to be used through cryptographic keys stored into the kernel’s keyring.

The feature extensions complement each other, but you can configure and use them independently of one another.

The kernel integrity subsystem can harness the Trusted Platform Module (TPM) to harden the system security even more. TPM is a specification by the Trusted Computing Group (TCG) for important cryptographic functions. TPMs are usually built as dedicated hardware that is attached to the platform’s motherboard and prevents software-based attacks by providing cryptographic functions from a protected and tamper-proof area of the hardware chip. Some of the TPM features are:

  • Random-number generator
  • Generator and secure storage for cryptographic keys
  • Hashing generator
  • Remote attestation

20.2. Integrity measurement architecture

Integrity Measurement Architecture (IMA) is a component of the kernel integrity subsystem. IMA aims to maintain the contents of local files. Specifically, IMA measures, stores, and appraises files' hashes before they are accessed, which prevents the reading and execution of unreliable data. Thereby, IMA enhances the security of the system.

20.3. Extended verification module

Extended Verification Module (EVM) is a component of the kernel integrity subsystem, which monitors changes in files' extended attributes (xattr). Many security-oriented technologies, including Integrity Measurement Architecture (IMA), store sensitive file information, such as content hashes, in the extended attributes. EVM creates another hash from these extended attributes and from a special key, which is loaded at boot time. The resulting hash is validated every time the extended attribute is used. For example, when IMA appraises the file.

RHEL 9 accepts the special encrypted key under the evm-key keyring. The key was created by a master key held in the kernel keyrings.

20.4. Trusted and encrypted keys

The following section introduces trusted and encrypted keys as an important part of enhancing system security.

Trusted and encrypted keys are variable-length symmetric keys generated by the kernel that utilize the kernel keyring service. The fact that this type of keys never appear in the user space in an unencrypted form means that their integrity can be verified, which in turn means that they can be used, for example, by the extended verification module (EVM) to verify and confirm the integrity of a running system. User-level programs can only access the keys in the form of encrypted blobs.

Trusted keys need a hardware component: the Trusted Platform Module (TPM) chip, which is used to both create and encrypt (seal) the keys. The TPM seals the keys using a 2048-bit RSA key called the storage root key (SRK).


To use a TPM 1.2 specification, enable and activate it through a setting in the machine firmware or by using the tpm_setactive command from the tpm-tools package of utilities. Also, the TrouSers software stack needs to be installed and the tcsd daemon needs to be running to communicate with the TPM (dedicated hardware). The tcsd daemon is part of the TrouSers suite, which is available through the trousers package. The more recent and backward incompatible TPM 2.0 uses a different software stack, where the tpm2-tools or ibm-tss utilities provide access to the dedicated hardware.

In addition to that, the user can seal the trusted keys with a specific set of the TPM’s platform configuration register (PCR) values. PCR contains a set of integrity-management values that reflect the firmware, boot loader, and operating system. This means that PCR-sealed keys can only be decrypted by the TPM on the same system on which they were encrypted. However, once a PCR-sealed trusted key is loaded (added to a keyring), and thus its associated PCR values are verified, it can be updated with new (or future) PCR values, so that a new kernel, for example, can be booted. A single key can also be saved as multiple blobs, each with different PCR values.

Encrypted keys do not require a TPM, as they use the kernel Advanced Encryption Standard (AES), which makes them faster than trusted keys. Encrypted keys are created using kernel-generated random numbers and encrypted by a master key when they are exported into user-space blobs. The master key is either a trusted key or a user key. If the master key is not trusted, the encrypted key is only as secure as the user key used to encrypt it.

20.5. Working with trusted keys

The following section describes how to create, export, load or update trusted keys with the keyctl utility to improve the system security.



  1. To create a trusted key using a TPM, execute:

    # keyctl add trusted <name> "new <key_length> [options]" <key_ring>
    • Based on the syntax, construct an example command as follows:

      # keyctl add trusted kmk "new 32" @u

      The command creates a trusted key called kmk with the length of 32 bytes (256 bits) and places it in the user keyring (@u). The keys may have a length of 32 to 128 bytes (256 to 1024 bits).

  2. To list the current structure of the kernel keyrings:

    # keyctl show
    Session Keyring
           -3 --alswrv    500   500  keyring: _ses
     97833714 --alswrv    500    -1   \_ keyring: _uid.1000
    642500861 --alswrv    500   500       \_ trusted: kmk
  3. To export the key to a user-space blob, execute:

    # keyctl pipe 642500861 > kmk.blob

    The command uses the pipe subcommand and the serial number of kmk.

  4. To load the trusted key from the user-space blob, use the add subcommand with the blob as an argument:

    # keyctl add trusted kmk "load `cat kmk.blob`" @u
  5. Create secure encrypted keys based on the TPM-sealed trusted key:

    # keyctl add encrypted <pass:quotes[name]> "new [format] <pass:quotes[key_type]>:<pass:quotes[primary_key_name]> <pass:quotes[keylength]>" <pass:quotes[key_ring]>
    • Based on the syntax, generate an encrypted key using the already created trusted key:

      # keyctl add encrypted encr-key "new trusted:kmk 32" @u

      The command uses the TPM-sealed trusted key (kmk), produced in the previous step, as a primary key for generating encrypted keys.

20.6. Working with encrypted keys

The following section describes managing encrypted keys to improve the system security on systems where a Trusted Platform Module (TPM) is not available.


  • For the 64-bit ARM architecture and IBM Z, the encrypted-keys kernel module needs to be loaded. For more information on how to load kernel modules, see Managing kernel modules.


  1. Use a random sequence of numbers to generate a user key:

    # keyctl add user kmk-user "$(dd if=/dev/urandom bs=1 count=32 2>/dev/null)" @u

    The command generates a user key called kmk-user which acts as a primary key and is used to seal the actual encrypted keys.

  2. Generate an encrypted key using the primary key from the previous step:

    # keyctl add encrypted encr-key "new user:kmk-user 32" @u
  3. Optionally, list all keys in the specified user keyring:

    # keyctl list @u
    2 keys in keyring:
    427069434: --alswrv  1000  1000 user: kmk-user
    1012412758: --alswrv  1000  1000 encrypted: encr-key

Keep in mind that encrypted keys that are not sealed by a trusted primary key are only as secure as the user primary key (random-number key) that was used to encrypt them. Therefore, the primary user key should be loaded as securely as possible and preferably early during the boot process.

Additional resources

20.7. Enabling integrity measurement architecture and extended verification module

Integrity measurement architecture (IMA) and extended verification module (EVM) belong to the kernel integrity subsystem and enhance the system security in various ways. The following section describes how to enable and configure IMA and EVM to improve the security of the operating system.


  • Verify that the securityfs filesystem is mounted on the /sys/kernel/security/ directory and the /sys/kernel/security/integrity/ima/ directory exists.

    # mount
    securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
  • Verify that the systemd service manager is already patched to support IMA and EVM on boot time:

    # dmesg | grep -i -e EVM -e IMA
    [    0.000000] Command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.14.0-1.el9.x86_64 root=/dev/mapper/rhel-root ro crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M resume=/dev/mapper/rhel-swap rhgb quiet
    [    0.000000] kvm-clock: cpu 0, msr 23601001, primary cpu clock
    [    0.000000] Using crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M, the size chosen is a best effort estimation.
    [    0.000000] Kernel command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.14.0-1.el9.x86_64 root=/dev/mapper/rhel-root ro crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M resume=/dev/mapper/rhel-swap rhgb quiet
    [    0.911527] ima: No TPM chip found, activating TPM-bypass!
    [    0.911538] ima: Allocated hash algorithm: sha1
    [    0.911580] evm: Initialising EVM extended attributes:
    [    0.911581] evm: security.selinux
    [    0.911581] evm: security.ima
    [    0.911582] evm: security.capability
    [    0.911582] evm: HMAC attrs: 0x1
    [    1.715151] systemd[1]: systemd 239 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=legacy)
    [    3.824198] fbcon: qxldrmfb (fb0) is primary device
    [    4.673457] PM: Image not found (code -22)
    [    6.549966] systemd[1]: systemd 239 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=legacy)


  1. Add the following kernel command line parameters:

    # grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="ima_policy=appraise_tcb ima_appraise=fix evm=fix"

    The command enables IMA and EVM in the fix mode for the current boot entry and allows users to gather and update the IMA measurements.

    The ima_policy=appraise_tcb kernel command line parameter ensures that the kernel uses the default Trusted Computing Base (TCB) measurement policy and the appraisal step. The appraisal part forbids access to files, whose prior and current measures do not match.

  2. Reboot to make the changes come into effect.
  3. Optionally, verify that the parameters have been added to the kernel command line:

    # cat /proc/cmdline
    BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.14.0-1.el9.x86_64 root=/dev/mapper/rhel-root ro crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M resume=/dev/mapper/rhel-swap rhgb quiet ima_policy=appraise_tcb ima_appraise=fix evm=fix
  4. Create a kernel master key to protect the EVM key:

    # keyctl add user kmk "$(dd if=/dev/urandom bs=1 count=32 2> /dev/null)" @u

    The kernel master key (kmk) is kept entirely in the kernel space memory. The 32-byte long value of the kernel master key kmk is generated from random bytes from the /dev/urandom file and placed in the user (@u) keyring. The key serial number is on the second line of the previous output.

  5. Create an encrypted EVM key based on the kmk key:

    # keyctl add encrypted evm-key "new user:kmk 64" @u

    The command uses kmk to generate and encrypt a 64-byte long user key (named evm-key) and places it in the user (@u) keyring. The key serial number is on the second line of the previous output.


    It is necessary to name the user key as evm-key because that is the name the EVM subsystem is expecting and is working with.

  6. Create a directory for exported keys:

    # mkdir -p /etc/keys/
  7. Search for the kmk key and export its value into a file:

    # keyctl pipe $(keyctl search @u user kmk) > /etc/keys/kmk

    The command places the unencrypted value of the kernel master key (kmk) into a file of previously defined location (/etc/keys/).

  8. Search for the evm-key user key and export its value into a file:

    # keyctl pipe $(keyctl search @u encrypted evm-key) > /etc/keys/evm-key

    The command places the encrypted value of the user evm-key key into a file of arbitrary location. The evm-key has been encrypted by the kernel master key earlier.

  9. Optionally, view the newly created keys:

    # keyctl show
    Session Keyring
    974575405   --alswrv     0        0      keyring: _ses
    299489774   --alswrv     0    65534       \_ keyring: _uid.0
    748544121   --alswrv     0        0           \_ user: kmk
    641780271   --alswrv     0        0           \_ encrypted: evm-key

    You should be able to see a similar output.

  10. Activate EVM:

    # echo 1 > /sys/kernel/security/evm
  11. Optionally, verify that EVM has been initialized:

    # dmesg | tail -1
    […​] evm: key initialized

20.8. Collecting file hashes with integrity measurement architecture

The first level of operation of integrity measurement architecture (IMA) is the measurement phase, which allows to create file hashes and store them as extended attributes (xattrs) of those files. The following section describes how to create and inspect the files' hashes.


  • Enable integrity measurement architecture (IMA) and extended verification module (EVM) as described in Enabling integrity measurement architecture and extended verification module.
  • Verify that the ima-evm-utils, attr, and keyutils packages are already installed:

    # dnf install ima-evm-utils attr keyutils
    Updating Subscription Management repositories.
    This system is registered to Red Hat Subscription Management, but is not receiving updates. You can use subscription-manager to assign subscriptions.
    Last metadata expiration check: 0:58:22 ago on Fri 14 Feb 2020 09:58:23 AM CET.
    Package ima-evm-utils-1.1-5.el8.x86_64 is already installed.
    Package attr-2.4.48-3.el8.x86_64 is already installed.
    Package keyutils-1.5.10-7.el8.x86_64 is already installed.
    Dependencies resolved.
    Nothing to do.


  1. Create a test file:

    # echo <Test_text> > test_file

    IMA and EVM ensure that the example file test_file is assigned hash values, which are stored as its extended attributes.

  2. Inspect extended attributes of the file:

    # getfattr -m . -d test_file
    # file: test_file

    The previous example output shows extended attributes related to SELinux and the IMA and EVM hash values. EVM actively adds a security.evm extended attribute and detects any offline tampering to xattrs of other files such as security.ima that are directly related to content integrity of files. The value of the security.evm field is in Hash-based Message Authentication Code (HMAC-SHA1), which was generated with the evm-key user key.