1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-22 17:35:35 +03:00

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/
This commit is contained in:
Luca Boccassi 2024-09-14 14:27:53 +02:00 committed by Lennart Poettering
parent 3cb93ebcf2
commit 394c61416c
7 changed files with 133 additions and 0 deletions

View File

@ -1661,6 +1661,7 @@ foreach term : ['analyze',
'hwdb',
'idn',
'ima',
'ipe',
'initrd',
'kernel-install',
'ldconfig',

View File

@ -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')

View File

@ -45,6 +45,12 @@ const char* const systemd_features =
" -IMA"
#endif
#if ENABLE_IMA
" +IPE"
#else
" -IPE"
#endif
#if ENABLE_SMACK
" +SMACK"
#else

112
src/core/ipe-setup.c Normal file
View File

@ -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;
}

4
src/core/ipe-setup.h Normal file
View File

@ -0,0 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
int ipe_setup(void);

View File

@ -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;
}

View File

@ -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',
)