The digital integrity of a kernel can be verified by the boot loader on cold boot, and during kexec, by the current running kernel, before it is loaded. However, it is still possible that the new kernel being loaded is older then the current kernel, and/or has known vulnerabilities. Therefore, it is imperative that an attestation service be able to verify the version of the kernel being loaded on the client, from cold boot and subsequent kexec system calls, ensuring that only kernels with versions known to be good are loaded. Measure the kernel version using ima_measure_critical_data() early on in the boot sequence, reducing the chances of known kernel vulnerabilities being exploited. With IMA being part of the kernel, this overall approach makes the measurement itself more trustworthy. ima_measure_critical_data() also makes use of queuing, thus the version string stored in linux_banner can queued for measuring in ima_init, with the actual measurement taking place as soon as the IMA subsystem is ready. Adding the following line to the ima policy file (/etc/ima/ima-policy) will enable this measurement: measure func=CRITICAL_DATA data_sources=kernel_version template=ima-buf To extract the measured data after boot, the following command can be used: grep -m 1 "kernel_version" \ /sys/kernel/security/integrity/ima/ascii_runtime_measurements Sample output from the command above: 10 355335b64c90d5810cf0d869d84a4076ebcabd89 ima-buf sha256:05260b2 ddf63284697f9448898d9466e4ce26d409a6e2ec357f0ce0b7425695b kernel_version 4c696e75782076657273696f6e20352e392e302d7263322d313 63236372d676338623364356165346231612d64697274792028726170686140726 17068612d5669727475616c2d4d616368696e65292028616172636836342d6c696 e75782d676e752d67636320285562756e74752f4c696e61726f20372e352e302d3 37562756e7475317e31382e30342920372e352e302c20474e55206c642028474e5 52042696e7574696c7320666f72205562756e74752920322e33302920233136205 34d5020576564204f63742031342031353a35313a3339205044542032303230 The above corresponds to the following (decoded) version string: Linux version 5.9.0-rc2-16267-gc8b3d5ae4b1a-dirty (rapha@rapha -Virtual-Machine) (aarch64-linux-gnu-gcc (Ubuntu/Linaro 7.5.0- 3ubuntu1~18.04) 7.5.0, GNU ld (GNU Binutils for Ubuntu) 2.30) #16 SMP Wed Oct 14 15:51:39 PDT 2020 Signed-off-by: Raphael Gianotti <raphgi@xxxxxxxxxxxxxxxxxxx> --- security/integrity/ima/Kconfig | 10 ++++++++++ security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_main.c | 5 ++++- security/integrity/ima/ima_queue_data.c | 5 +++-- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index fec7e74978ed..7ad3ddb83c06 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -328,3 +328,13 @@ config IMA_SECURE_AND_OR_TRUSTED_BOOT help This option is selected by architectures to enable secure and/or trusted boot based on IMA runtime policies. + +config IMA_MEASURE_KERNEL_VERSION + bool + depends on IMA + default y + help + This option enables measuring the kernel version and causes it to + be measured during kernel boot. + This option requires the following IMA rule to be set: + measure func=CRITICAL_DATA data_sources=kernel_version template=ima-buf diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index e99e5e0db720..9d4b4a6027db 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -230,6 +230,7 @@ struct modsig; #define __ima_supported_kernel_data_sources(source) \ source(MIN_SOURCE, min_source) \ + source(KERNEL_VERSION, kernel_version) \ source(MAX_SOURCE, max_source) #define __ima_enum_stringify(ENUM, str) (#str), diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 5162917e6bf2..e128b27776e2 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -948,8 +948,11 @@ static int __init init_ima(void) if (error) pr_warn("Couldn't register LSM notifier, error %d\n", error); - if (!error) + if (!error) { ima_update_policy_flag(); + ima_measure_critical_data("kernel_version", "kernel_version", + linux_banner, strlen(linux_banner), false); + } return error; } diff --git a/security/integrity/ima/ima_queue_data.c b/security/integrity/ima/ima_queue_data.c index 4871ed3af436..fbd0a7bf668e 100644 --- a/security/integrity/ima/ima_queue_data.c +++ b/security/integrity/ima/ima_queue_data.c @@ -35,8 +35,9 @@ static bool timer_expired; static inline bool ima_queuing_enabled(void) { - return (IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) && - IS_ENABLED(CONFIG_SYSTEM_TRUSTED_KEYRING)); + return ((IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) && + IS_ENABLED(CONFIG_SYSTEM_TRUSTED_KEYRING)) || + IS_ENABLED(CONFIG_IMA_MEASURE_KERNEL_VERSION)); } /* -- 2.28.0