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:
parent
31f8c8682f
commit
ba199dc909
@ -55,6 +55,7 @@ targets += module.lds
|
||||
subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
|
||||
subdir-$(CONFIG_MODVERSIONS) += genksyms
|
||||
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
|
||||
subdir-$(CONFIG_SECURITY_IPE) += ipe
|
||||
|
||||
# Let clean descend into subdirs
|
||||
subdir- += basic dtc gdb kconfig mod
|
||||
|
2
scripts/ipe/Makefile
Normal file
2
scripts/ipe/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
subdir-y := polgen
|
2
scripts/ipe/polgen/.gitignore
vendored
Normal file
2
scripts/ipe/polgen/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
polgen
|
5
scripts/ipe/polgen/Makefile
Normal file
5
scripts/ipe/polgen/Makefile
Normal 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
145
scripts/ipe/polgen/polgen.c
Normal 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
2
security/ipe/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
boot_policy.c
|
@ -21,6 +21,16 @@ menuconfig SECURITY_IPE
|
||||
If unsure, answer N.
|
||||
|
||||
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"
|
||||
|
||||
config IPE_PROP_DM_VERITY
|
||||
|
@ -5,7 +5,16 @@
|
||||
# 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) += \
|
||||
boot_policy.o \
|
||||
digest.o \
|
||||
eval.o \
|
||||
hooks.o \
|
||||
@ -15,3 +24,5 @@ obj-$(CONFIG_SECURITY_IPE) += \
|
||||
policy_fs.o \
|
||||
policy_parser.o \
|
||||
audit.o \
|
||||
|
||||
clean-files := boot_policy.c \
|
||||
|
@ -190,6 +190,7 @@ static const struct file_operations enforce_fops = {
|
||||
static int __init ipe_init_securityfs(void)
|
||||
{
|
||||
int rc = 0;
|
||||
struct ipe_policy *ap;
|
||||
|
||||
if (!ipe_enabled)
|
||||
return -EOPNOTSUPP;
|
||||
@ -220,6 +221,13 @@ static int __init ipe_init_securityfs(void)
|
||||
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);
|
||||
if (IS_ERR(np)) {
|
||||
rc = PTR_ERR(np);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "hooks.h"
|
||||
#include "eval.h"
|
||||
|
||||
extern const char *const ipe_boot_policy;
|
||||
bool ipe_enabled;
|
||||
|
||||
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)
|
||||
{
|
||||
struct ipe_policy *p = NULL;
|
||||
|
||||
security_add_hooks(ipe_hooks, ARRAY_SIZE(ipe_hooks), &ipe_lsmid);
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user