From 394c61416c19bcc3231d3f717b72ef9d90b89ee7 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Sat, 14 Sep 2024 14:27:53 +0200 Subject: [PATCH] core: load IPE policy on boot IPE is a new LSM being introduced in 6.12. Like IMA, it works based on a policy file that has to be loaded at boot, the earlier the better. So like IMA, if such a policy is present, load it and activate it. If there are any .p7b files in /etc/ipe/, load them as policies. The files have to be inline signed in DER format as per IPE documentation. For more information on the details of IPE: https://microsoft.github.io/ipe/ --- meson.build | 1 + meson_options.txt | 2 + src/basic/build.c | 6 +++ src/core/ipe-setup.c | 112 +++++++++++++++++++++++++++++++++++++++++++ src/core/ipe-setup.h | 4 ++ src/core/main.c | 7 +++ src/core/meson.build | 1 + 7 files changed, 133 insertions(+) create mode 100644 src/core/ipe-setup.c create mode 100644 src/core/ipe-setup.h diff --git a/meson.build b/meson.build index 724c48adc81..e258a65a1ac 100644 --- a/meson.build +++ b/meson.build @@ -1661,6 +1661,7 @@ foreach term : ['analyze', 'hwdb', 'idn', 'ima', + 'ipe', 'initrd', 'kernel-install', 'ldconfig', diff --git a/meson_options.txt b/meson_options.txt index 46e3ac55f78..ec3688ab33c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -388,6 +388,8 @@ option('polkit', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : description : 'polkit support') option('ima', type : 'boolean', description : 'IMA support') +option('ipe', type : 'boolean', + description : 'IPE support') option('acl', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, description : 'libacl support') diff --git a/src/basic/build.c b/src/basic/build.c index bb9b4185f01..97249ba14f1 100644 --- a/src/basic/build.c +++ b/src/basic/build.c @@ -45,6 +45,12 @@ const char* const systemd_features = " -IMA" #endif +#if ENABLE_IMA + " +IPE" +#else + " -IPE" +#endif + #if ENABLE_SMACK " +SMACK" #else diff --git a/src/core/ipe-setup.c b/src/core/ipe-setup.c new file mode 100644 index 00000000000..4648d438298 --- /dev/null +++ b/src/core/ipe-setup.c @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "conf-files.h" +#include "copy.h" +#include "fd-util.h" +#include "fileio.h" +#include "ipe-setup.h" +#include "nulstr-util.h" +#include "path-util.h" + +#define IPE_SECFS_DIR "/sys/kernel/security/ipe" +#define IPE_SECFS_NEW_POLICY IPE_SECFS_DIR "/new_policy" +#define IPE_SECFS_POLICIES IPE_SECFS_DIR "/policies/" + +int ipe_setup(void) { +#if ENABLE_IPE + _cleanup_strv_free_ char **policies = NULL; + int r; + + /* Very quick smoke tests first: this is in the citical, sequential boot path, and in most cases it + * is unlikely this will be configured, so do the fastest existence checks first and immediately + * return if there's nothing to do. */ + + if (access(IPE_SECFS_DIR, F_OK) < 0) { + log_debug_errno(errno, "IPE support is disabled in the kernel, ignoring: %m"); + return 0; + } + + r = conf_files_list_nulstr( + &policies, + ".p7b", + /* root= */ NULL, + CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, + CONF_PATHS_NULSTR("ipe")); + if (r < 0) + return log_error_errno(r, "Failed to assemble list of IPE policies: %m"); + + STRV_FOREACH(policy, policies) { + _cleanup_free_ char *policy_name = NULL, *file_name = NULL, *output_path = NULL, *activate_path = NULL; + _cleanup_close_ int input = -EBADF, output = -EBADF; + const char *suffix; + + r = path_extract_filename(*policy, &file_name); + if (r < 0) + return log_error_errno(r, "Failed to extract filename from IPE policy path %s: %m", *policy); + + /* Filtered by conf_files_list_nulstr() */ + suffix = ASSERT_PTR(endswith(file_name, ".p7b")); + + policy_name = strndup(file_name, suffix - file_name); + if (!policy_name) + return log_oom(); + + if (!filename_is_valid(policy_name)) + return log_error_errno( + SYNTHETIC_ERRNO(EINVAL), + "Invalid IPE policy name %s", + policy_name); + + input = open(*policy, O_RDONLY|O_NOFOLLOW|O_CLOEXEC); + if (input < 0) + return log_error_errno( + errno, + "Failed to open the IPE policy file %s: %m", + *policy); + + /* If policy is already installed, try to update it */ + output_path = path_join(IPE_SECFS_POLICIES, policy_name, "update"); + if (!output_path) + return log_oom(); + + output = open(output_path, O_WRONLY|O_CLOEXEC); + if (output < 0 && errno == ENOENT) + /* Policy is not installed, install it and activate it */ + output = open(IPE_SECFS_NEW_POLICY, O_WRONLY|O_CLOEXEC); + if (output < 0) + return log_error_errno( + errno, + "Failed to open the IPE policy handle for writing: %m"); + + /* The policy is inline signed in binary format, so it has to be copied in one go, otherwise the + * kernel will reject partial inputs with -EBADMSG. */ + r = copy_bytes(input, output, UINT64_MAX, /* copy_flags= */ 0); + if (r < 0) + return log_error_errno( + r, + "Failed to copy the IPE policy %s to %s: %m", + *policy, + output_path); + + output = safe_close(output); + + activate_path = path_join(IPE_SECFS_POLICIES, policy_name, "active"); + if (!activate_path) + return log_oom(); + + r = write_string_file(activate_path, "1", WRITE_STRING_FILE_DISABLE_BUFFER); + if (r == -ESTALE) { + log_debug_errno(r, + "IPE policy %s is already loaded with a version that is equal or higher, skipping.", + policy_name); + continue; + } + if (r < 0) + return log_error_errno(r, "Failed to activate the IPE policy %s: %m", policy_name); + + log_info("Successfully loaded and activated the IPE policy %s.", policy_name); + } + +#endif /* ENABLE_IPE */ + return 0; +} diff --git a/src/core/ipe-setup.h b/src/core/ipe-setup.h new file mode 100644 index 00000000000..dae1fadb830 --- /dev/null +++ b/src/core/ipe-setup.h @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +int ipe_setup(void); diff --git a/src/core/main.c b/src/core/main.c index b9dc4506366..e526c37e6a5 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -57,6 +57,7 @@ #include "ima-setup.h" #include "import-creds.h" #include "initrd-util.h" +#include "ipe-setup.h" #include "killall.h" #include "kmod-setup.h" #include "limits-util.h" @@ -2920,6 +2921,12 @@ static int initialize_security( return r; } + r = ipe_setup(); + if (r < 0) { + *ret_error_message = "Failed to load IPE policy"; + return r; + } + dual_timestamp_now(security_finish_timestamp); return 0; } diff --git a/src/core/meson.build b/src/core/meson.build index 28c10703ea0..84cade9ae75 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -146,6 +146,7 @@ systemd_sources = files( 'kmod-setup.c', 'apparmor-setup.c', 'ima-setup.c', + 'ipe-setup.c', 'selinux-setup.c', 'smack-setup.c', )