scripts: add boot policy generation program

Enables an IPE policy to be enforced from kernel start, enabling access
control based on trust from kernel startup. This is accomplished by
transforming an IPE policy indicated by CONFIG_IPE_BOOT_POLICY into a
c-string literal that is parsed at kernel startup as an unsigned policy.

Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
Signed-off-by: Fan Wu <wufan@linux.microsoft.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
This commit is contained in:
Deven Bowers 2024-08-02 23:08:31 -07:00 committed by Paul Moore
parent 31f8c8682f
commit ba199dc909
10 changed files with 198 additions and 0 deletions

View File

@ -55,6 +55,7 @@ targets += module.lds
subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
subdir-$(CONFIG_MODVERSIONS) += genksyms subdir-$(CONFIG_MODVERSIONS) += genksyms
subdir-$(CONFIG_SECURITY_SELINUX) += selinux subdir-$(CONFIG_SECURITY_SELINUX) += selinux
subdir-$(CONFIG_SECURITY_IPE) += ipe
# Let clean descend into subdirs # Let clean descend into subdirs
subdir- += basic dtc gdb kconfig mod subdir- += basic dtc gdb kconfig mod

2
scripts/ipe/Makefile Normal file
View File

@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
subdir-y := polgen

2
scripts/ipe/polgen/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
polgen

View File

@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
hostprogs-always-y := polgen
HOST_EXTRACFLAGS += \
-I$(srctree)/include \
-I$(srctree)/include/uapi \

145
scripts/ipe/polgen/polgen.c Normal file
View File

@ -0,0 +1,145 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
*/
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
static void usage(const char *const name)
{
printf("Usage: %s OutputFile (PolicyFile)\n", name);
exit(EINVAL);
}
static int policy_to_buffer(const char *pathname, char **buffer, size_t *size)
{
size_t fsize;
size_t read;
char *lbuf;
int rc = 0;
FILE *fd;
fd = fopen(pathname, "r");
if (!fd) {
rc = errno;
goto out;
}
fseek(fd, 0, SEEK_END);
fsize = ftell(fd);
rewind(fd);
lbuf = malloc(fsize);
if (!lbuf) {
rc = ENOMEM;
goto out_close;
}
read = fread((void *)lbuf, sizeof(*lbuf), fsize, fd);
if (read != fsize) {
rc = -1;
goto out_free;
}
*buffer = lbuf;
*size = fsize;
fclose(fd);
return rc;
out_free:
free(lbuf);
out_close:
fclose(fd);
out:
return rc;
}
static int write_boot_policy(const char *pathname, const char *buf, size_t size)
{
int rc = 0;
FILE *fd;
size_t i;
fd = fopen(pathname, "w");
if (!fd) {
rc = errno;
goto err;
}
fprintf(fd, "/* This file is automatically generated.");
fprintf(fd, " Do not edit. */\n");
fprintf(fd, "#include <linux/stddef.h>\n");
fprintf(fd, "\nextern const char *const ipe_boot_policy;\n\n");
fprintf(fd, "const char *const ipe_boot_policy =\n");
if (!buf || size == 0) {
fprintf(fd, "\tNULL;\n");
fclose(fd);
return 0;
}
fprintf(fd, "\t\"");
for (i = 0; i < size; ++i) {
switch (buf[i]) {
case '"':
fprintf(fd, "\\\"");
break;
case '\'':
fprintf(fd, "'");
break;
case '\n':
fprintf(fd, "\\n\"\n\t\"");
break;
case '\\':
fprintf(fd, "\\\\");
break;
case '\t':
fprintf(fd, "\\t");
break;
case '\?':
fprintf(fd, "\\?");
break;
default:
fprintf(fd, "%c", buf[i]);
}
}
fprintf(fd, "\";\n");
fclose(fd);
return 0;
err:
if (fd)
fclose(fd);
return rc;
}
int main(int argc, const char *const argv[])
{
char *policy = NULL;
size_t len = 0;
int rc = 0;
if (argc < 2)
usage(argv[0]);
if (argc > 2) {
rc = policy_to_buffer(argv[2], &policy, &len);
if (rc != 0)
goto cleanup;
}
rc = write_boot_policy(argv[1], policy, len);
cleanup:
if (policy)
free(policy);
if (rc != 0)
perror("An error occurred during policy conversion: ");
return rc;
}

2
security/ipe/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
boot_policy.c

View File

@ -21,6 +21,16 @@ menuconfig SECURITY_IPE
If unsure, answer N. If unsure, answer N.
if SECURITY_IPE if SECURITY_IPE
config IPE_BOOT_POLICY
string "Integrity policy to apply on system startup"
help
This option specifies a filepath to an IPE policy that is compiled
into the kernel. This policy will be enforced until a policy update
is deployed via the $securityfs/ipe/policies/$policy_name/active
interface.
If unsure, leave blank.
menu "IPE Trust Providers" menu "IPE Trust Providers"
config IPE_PROP_DM_VERITY config IPE_PROP_DM_VERITY

View File

@ -5,7 +5,16 @@
# Makefile for building the IPE module as part of the kernel tree. # Makefile for building the IPE module as part of the kernel tree.
# #
quiet_cmd_polgen = IPE_POL $(2)
cmd_polgen = scripts/ipe/polgen/polgen security/ipe/boot_policy.c $(2)
targets += boot_policy.c
$(obj)/boot_policy.c: scripts/ipe/polgen/polgen $(CONFIG_IPE_BOOT_POLICY) FORCE
$(call if_changed,polgen,$(CONFIG_IPE_BOOT_POLICY))
obj-$(CONFIG_SECURITY_IPE) += \ obj-$(CONFIG_SECURITY_IPE) += \
boot_policy.o \
digest.o \ digest.o \
eval.o \ eval.o \
hooks.o \ hooks.o \
@ -15,3 +24,5 @@ obj-$(CONFIG_SECURITY_IPE) += \
policy_fs.o \ policy_fs.o \
policy_parser.o \ policy_parser.o \
audit.o \ audit.o \
clean-files := boot_policy.c \

View File

@ -190,6 +190,7 @@ static const struct file_operations enforce_fops = {
static int __init ipe_init_securityfs(void) static int __init ipe_init_securityfs(void)
{ {
int rc = 0; int rc = 0;
struct ipe_policy *ap;
if (!ipe_enabled) if (!ipe_enabled)
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -220,6 +221,13 @@ static int __init ipe_init_securityfs(void)
goto err; goto err;
} }
ap = rcu_access_pointer(ipe_active_policy);
if (ap) {
rc = ipe_new_policyfs_node(ap);
if (rc)
goto err;
}
np = securityfs_create_file("new_policy", 0200, root, NULL, &np_fops); np = securityfs_create_file("new_policy", 0200, root, NULL, &np_fops);
if (IS_ERR(np)) { if (IS_ERR(np)) {
rc = PTR_ERR(np); rc = PTR_ERR(np);

View File

@ -9,6 +9,7 @@
#include "hooks.h" #include "hooks.h"
#include "eval.h" #include "eval.h"
extern const char *const ipe_boot_policy;
bool ipe_enabled; bool ipe_enabled;
static struct lsm_blob_sizes ipe_blobs __ro_after_init = { static struct lsm_blob_sizes ipe_blobs __ro_after_init = {
@ -74,9 +75,20 @@ static struct security_hook_list ipe_hooks[] __ro_after_init = {
*/ */
static int __init ipe_init(void) static int __init ipe_init(void)
{ {
struct ipe_policy *p = NULL;
security_add_hooks(ipe_hooks, ARRAY_SIZE(ipe_hooks), &ipe_lsmid); security_add_hooks(ipe_hooks, ARRAY_SIZE(ipe_hooks), &ipe_lsmid);
ipe_enabled = true; ipe_enabled = true;
if (ipe_boot_policy) {
p = ipe_new_policy(ipe_boot_policy, strlen(ipe_boot_policy),
NULL, 0);
if (IS_ERR(p))
return PTR_ERR(p);
rcu_assign_pointer(ipe_active_policy, p);
}
return 0; return 0;
} }