Re: [PATCH 1/2] audit: remove redundant data_len check
On 08/06/22 1:31 am, Paul Moore wrote: > On Sun, May 15, 2022 at 7:35 PM Paul Moore wrote: >> >> On Sun, May 15, 2022 at 3:31 AM Shreenidhi Shedi wrote: >>> >>> data_len is already getting checked if it's less than 2 earlier in this >>> function. >>> >>> Signed-off-by: Shreenidhi Shedi >>> --- >>> kernel/audit.c | 2 +- >>> 1 file changed, 1 insertion(+), 1 deletion(-) >> >> Thanks, this patch looks okay, but since we are already at v5.18-rc7 >> this patch will have to wait until after the upcoming merge window as >> it isn't a critical bug fix. > > ... and it's now merged into audit/next, thanks! > You are welcome and Thank you as well. -- Shedi -- Linux-audit mailing list Linux-audit@redhat.com https://listman.redhat.com/mailman/listinfo/linux-audit
[RFC PATCH v8 15/17] 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 --- v2: + No Changes v3: + No Changes v4: + No Changes v5: + No Changes v6: + No Changes v7: + Move from 01/11 to 14/16 + Don't return errno directly. + Make output of script more user-friendly + Add escaping for tab and '?' + Mark argv pointer const + Invert return code check in the boot policy parsing code path. v8: + No signfiicant chances. --- MAINTAINERS | 1 + scripts/Makefile | 1 + scripts/ipe/Makefile | 2 + scripts/ipe/polgen/.gitignore | 1 + scripts/ipe/polgen/Makefile | 6 ++ scripts/ipe/polgen/polgen.c | 145 ++ security/ipe/.gitignore | 1 + security/ipe/Kconfig | 10 +++ security/ipe/Makefile | 11 +++ security/ipe/ctx.c| 18 + security/ipe/fs.c | 10 +++ 11 files changed, 206 insertions(+) create mode 100644 scripts/ipe/Makefile create mode 100644 scripts/ipe/polgen/.gitignore create mode 100644 scripts/ipe/polgen/Makefile create mode 100644 scripts/ipe/polgen/polgen.c create mode 100644 security/ipe/.gitignore diff --git a/MAINTAINERS b/MAINTAINERS index 965fdac6d609..f7333d07a9df 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9797,6 +9797,7 @@ INTEGRITY POLICY ENFORCEMENT (IPE) M: Deven Bowers M: Fan Wu S: Supported +F: scripts/ipe/ F: security/ipe/ INTEL 810/815 FRAMEBUFFER DRIVER diff --git a/scripts/Makefile b/scripts/Makefile index f084f08ed176..4f1a8f37a83f 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -38,6 +38,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 diff --git a/scripts/ipe/Makefile b/scripts/ipe/Makefile new file mode 100644 index ..e87553fbb8d6 --- /dev/null +++ b/scripts/ipe/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +subdir-y := polgen diff --git a/scripts/ipe/polgen/.gitignore b/scripts/ipe/polgen/.gitignore new file mode 100644 index ..80f32f25d200 --- /dev/null +++ b/scripts/ipe/polgen/.gitignore @@ -0,0 +1 @@ +polgen diff --git a/scripts/ipe/polgen/Makefile b/scripts/ipe/polgen/Makefile new file mode 100644 index ..066060c22b4a --- /dev/null +++ b/scripts/ipe/polgen/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +hostprogs-always-y := polgen +HOST_EXTRACFLAGS += \ + -I$(srctree)/include \ + -I$(srctree)/include/uapi \ + diff --git a/scripts/ipe/polgen/polgen.c b/scripts/ipe/polgen/polgen.c new file mode 100644 index ..40b6fe07f47b --- /dev/null +++ b/scripts/ipe/polgen/polgen.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Microsoft Corporation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +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) +{ + int rc = 0; + FILE *fd; + char *lbuf; + size_t fsize; + size_t read; + + 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 \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,
[RFC PATCH v8 10/17] block|security: add LSM blob to block_device
block_device structures can have valuable security properties, based on how they are created, and what subsystem manages them. By adding LSM storage to this structure, this data can be accessed at the LSM layer. Signed-off-by: Deven Bowers --- v2: + No Changes v3: + Minor style changes from checkpatch --strict v4: + No Changes v5: + Allow multiple callers to call security_bdev_setsecurity v6: + Simplify security_bdev_setsecurity break condition v7: + Squash all dm-verity related patches to two patches, the additions to dm-verity/fs, and the consumption of the additions. v8: + Split dm-verity related patches squashed in v7 to 3 commits based on topic: + New LSM hook + Consumption of hook outside LSM + Consumption of hook inside LSM. + change return of security_bdev_alloc / security_bdev_setsecurity to LSM_RET_DEFAULT instead of 0. + Change return code to -EOPNOTSUPP, bring inline with other setsecurity hooks. --- block/bdev.c | 7 include/linux/blk_types.h | 1 + include/linux/lsm_hook_defs.h | 5 +++ include/linux/lsm_hooks.h | 12 ++ include/linux/security.h | 22 +++ security/security.c | 70 +++ 6 files changed, 117 insertions(+) diff --git a/block/bdev.c b/block/bdev.c index 5fe06c1f2def..e7ef2c7a22c9 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "../fs/internal.h" @@ -397,6 +398,11 @@ static struct inode *bdev_alloc_inode(struct super_block *sb) if (!ei) return NULL; memset(&ei->bdev, 0, sizeof(ei->bdev)); + + if (unlikely(security_bdev_alloc(&ei->bdev))) { + kmem_cache_free(bdev_cachep, ei); + return NULL; + } return &ei->vfs_inode; } @@ -406,6 +412,7 @@ static void bdev_free_inode(struct inode *inode) free_percpu(bdev->bd_stats); kfree(bdev->bd_meta_info); + security_bdev_free(bdev); if (!bdev_is_partition(bdev)) { if (bdev->bd_disk && bdev->bd_disk->bdi) diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index a24d4078fb21..a014ffa14b2d 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -68,6 +68,7 @@ struct block_device { #ifdef CONFIG_FAIL_MAKE_REQUEST boolbd_make_it_fail; #endif + void*security; } __randomize_layout; #define bdev_whole(_bdev) \ diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index eafa1d2489fd..3449c004bd84 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -407,3 +407,8 @@ LSM_HOOK(int, 0, perf_event_write, struct perf_event *event) LSM_HOOK(int, 0, uring_override_creds, const struct cred *new) LSM_HOOK(int, 0, uring_sqpoll, void) #endif /* CONFIG_IO_URING */ + +LSM_HOOK(int, 0, bdev_alloc_security, struct block_device *bdev) +LSM_HOOK(void, LSM_RET_VOID, bdev_free_security, struct block_device *bdev) +LSM_HOOK(int, 0, bdev_setsecurity, struct block_device *bdev, const char *name, +const void *value, size_t size) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 91c8146649f5..9f011d705ea8 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1550,6 +1550,17 @@ * * @what: kernel feature being accessed * + * @bdev_alloc_security: + * Initialize the security field inside a block_device structure. + * + * @bdev_free_security: + * Cleanup the security information stored inside a block_device structure. + * + * @bdev_setsecurity: + * Set a security property associated with @name for @bdev with + * value @value. @size indicates the size of @value in bytes. + * If a @name is not implemented, return -EOPNOTSUPP. + * * Security hooks for perf events * * @perf_event_open: @@ -1610,6 +1621,7 @@ struct lsm_blob_sizes { int lbs_ipc; int lbs_msg_msg; int lbs_task; + int lbs_bdev; }; /* diff --git a/include/linux/security.h b/include/linux/security.h index 7fc4e9f49f54..30b663de301f 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -473,6 +473,11 @@ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen); int security_locked_down(enum lockdown_reason what); +int security_bdev_alloc(struct block_device *bdev); +void security_bdev_free(struct block_device *bdev); +int security_bdev_setsecurity(struct block_device *bdev, + const char *name, const void *value, + size_t size); #else /* CONFIG_SECURITY */ static inline int call_blocking_lsm_notifier(enum lsm_event event, v
[RFC PATCH v8 14/17] ipe: enable support for fs-verity as a trust provider
From: Fan Wu Enable IPE policy authors to indicate trust for a singular fsverity file, identified by the digest information, through "fsverity_digest" and all files using fsverity's builtin signatures via "fsverity_signature". This enables file-level integrity claims to be expressed in IPE, allowing individual files to be authorized, giving some flexibility for policy authors. Such file-level claims are important to be expressed for enforcing the integrity of packages, as well as address some of the scalability issues in a sole dm-verity based solution (# of loop back devices, etc). This solution cannot be done in userspace as the minimum threat that IPE should mitigate is an attacker downloads malicious payload with all required dependencies. These dependencies can lack the userspace check, bypassing the protection entirely. A similar attack succeeds if the userspace component is replaced with a version that does not perform the check. As a result, this can only be done in the common entry point - the kernel. Signed-off-by: Fan Wu Signed-off-by: Deven Bowers --- v1-v6: + Not present v7: Introduced v8: * Undo squash of 08/12, 10/12 - separating drivers/md/ from security/ * Use common-audit function for fsverity_signature. + Change fsverity implementation to use fsverity_get_digest + prevent unnecessary copy of fs-verity signature data, instead just check for presence of signature data. + Remove free_inode_security hook, as the digest is now acquired at runtime instead of via LSM blob. --- security/ipe/eval.c | 1 + security/ipe/eval.h | 5 +++ security/ipe/hooks.c | 29 + security/ipe/hooks.h | 5 +++ security/ipe/ipe.c| 7 security/ipe/ipe.h| 1 + security/ipe/modules/Kconfig | 23 + security/ipe/modules/Makefile | 2 ++ security/ipe/modules/fsverity_digest.c| 39 +++ security/ipe/modules/fsverity_signature.c | 34 10 files changed, 146 insertions(+) create mode 100644 security/ipe/modules/fsverity_digest.c create mode 100644 security/ipe/modules/fsverity_signature.c diff --git a/security/ipe/eval.c b/security/ipe/eval.c index 9b29d83cd466..e8205a6fce44 100644 --- a/security/ipe/eval.c +++ b/security/ipe/eval.c @@ -95,6 +95,7 @@ static struct ipe_eval_ctx *build_ctx(const struct file *file, ctx->ci_ctx = ipe_current_ctx(); ctx->from_init_sb = from_pinned(file); if (file) { + ctx->ipe_inode = ipe_inode(file->f_inode); if (FILE_BLOCK_DEV(file)) ctx->ipe_bdev = ipe_bdev(FILE_BLOCK_DEV(file)); } diff --git a/security/ipe/eval.h b/security/ipe/eval.h index 57b7b2b424f8..541251125e8e 100644 --- a/security/ipe/eval.h +++ b/security/ipe/eval.h @@ -22,6 +22,10 @@ struct ipe_bdev { const char *digest_algo; }; +struct ipe_inode { + bool fs_verity_signed; +}; + struct ipe_eval_ctx { enum ipe_operation op; @@ -29,6 +33,7 @@ struct ipe_eval_ctx { struct ipe_context *ci_ctx; const struct ipe_bdev *ipe_bdev; + const struct ipe_inode *ipe_inode; bool from_init_sb; }; diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c index 1072ee5bb8f6..7c99afad4924 100644 --- a/security/ipe/hooks.c +++ b/security/ipe/hooks.c @@ -267,3 +267,32 @@ int ipe_bdev_setsecurity(struct block_device *bdev, const char *key, return -EOPNOTSUPP; } + +/** + * ipe_inode_setsecurity: Sets the a certain field of a inode security + * blob, based on @key. + * @inode: The inode to source the security blob from. + * @name: The name representing the information to be stored. + * @value: The value to be stored. + * @size: The size of @value. + * @flags: unused + * + * Saves fsverity signature & digest into inode security blob + * + * Return: + * 0 - OK + * !0 - Error + */ +int ipe_inode_setsecurity(struct inode *inode, const char *name, + const void *value, size_t size, + int flags) +{ + struct ipe_inode *inode_sec = ipe_inode(inode); + + if (!strcmp(name, FS_VERITY_INODE_SEC_NAME)) { + inode_sec->fs_verity_signed = size > 0 && value; + return 0; + } + + return -EOPNOTSUPP; +} diff --git a/security/ipe/hooks.h b/security/ipe/hooks.h index 0d1589e47f8f..1edcc91d6d33 100644 --- a/security/ipe/hooks.h +++ b/security/ipe/hooks.h @@ -10,6 +10,7 @@ #include #include #include +#include #include int ipe_task_alloc(struct task_struct *task, @@ -37,4 +38,8 @@ void ipe_bdev_free_security(struct block_device *bdev); int ipe_bdev_setsecurity(struct block_device *bdev, const char *key, const void *value, size_t len); +int ipe_inode_setsecurity(struct inode *inode, const char
[RFC PATCH v8 05/17] ipe: add LSM hooks on execution and kernel read
IPE's initial goal is to control both execution and the loading of kernel modules based on the system's definition of trust. It accomplishes this by plugging into the security hooks for bprm_check_security, file_mprotect, mmap_file, kernel_load_data, and kernel_read_data. Signed-off-by: Deven Bowers --- v2: + Split evaluation loop, access control hooks, and evaluation loop from policy parser and userspace interface to pass mailing list character limit v3: + Move ipe_load_properties to patch 04. + Remove useless 0-initializations + Prefix extern variables with ipe_ + Remove kernel module parameters, as these are exposed through sysctls. + Add more prose to the IPE base config option help text. + Use GFP_KERNEL for audit_log_start. + Remove unnecessary caching system. + Remove comments from headers + Use rcu_access_pointer for rcu-pointer null check + Remove usage of reqprot; use prot only. + Move policy load and activation audit event to 03/12 v4: + Remove sysctls in favor of securityfs nodes + Re-add kernel module parameters, as these are now exposed through securityfs. + Refactor property audit loop to a separate function. v5: + fix minor grammatical errors + do not group rule by curly-brace in audit record, reconstruct the exact rule. v6: + No changes v7: + Further split lsm creation, the audit system, the evaluation loop and access control hooks into separate commits. v8: + Rename hook functions to follow the lsmname_hook_name convention + Remove ipe_hook enumeration, can be derived from correlation with syscall audit record. --- security/ipe/hooks.c | 150 ++ security/ipe/hooks.h | 16 + security/ipe/ipe.c| 5 ++ security/ipe/policy.c | 23 +++ security/ipe/policy.h | 12 +++- 5 files changed, 204 insertions(+), 2 deletions(-) diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c index dd9606962fa5..d20de25bbd40 100644 --- a/security/ipe/hooks.c +++ b/security/ipe/hooks.c @@ -6,11 +6,15 @@ #include "ipe.h" #include "ctx.h" #include "hooks.h" +#include "eval.h" +#include #include #include #include #include +#include +#include /** * ipe_task_alloc: Assign a new context for an associated task structure. @@ -52,3 +56,149 @@ void ipe_task_free(struct task_struct *task) ipe_put_ctx(ctx); rcu_read_unlock(); } + +/** + * ipe_bprm_check_security: LSM hook called when a process is loaded through the exec + * family of system calls. + * @bprm: Supplies a pointer to a linux_binprm structure to source the file + * being evaluated. + * + * Return: + * 0 - OK + * !0 - Error + */ +int ipe_bprm_check_security(struct linux_binprm *bprm) +{ + return ipe_process_event(bprm->file, ipe_operation_exec); +} + +/** + * ipe_mmap_file: LSM hook called when a file is loaded through the mmap + * family of system calls. + * @f: File being mmap'd. Can be NULL in the case of anonymous memory. + * @reqprot: The requested protection on the mmap, passed from usermode. + * @prot: The effective protection on the mmap, resolved from reqprot and + * system configuration. + * @flags: Unused. + * + * Return: + * 0 - OK + * !0 - Error + */ +int ipe_mmap_file(struct file *f, unsigned long reqprot, unsigned long prot, + unsigned long flags) +{ + if (prot & PROT_EXEC || reqprot & PROT_EXEC) + return ipe_process_event(f, ipe_operation_exec); + + return 0; +} + +/** + * ipe_file_mprotect: LSM hook called when a mmap'd region of memory is changing + * its protections via mprotect. + * @vma: Existing virtual memory area created by mmap or similar + * @reqprot: The requested protection on the mmap, passed from usermode. + * @prot: The effective protection on the mmap, resolved from reqprot and + * system configuration. + * + * Return: + * 0 - OK + * !0 - Error + */ +int ipe_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, + unsigned long prot) +{ + /* Already Executable */ + if (vma->vm_flags & VM_EXEC) + return 0; + + if (prot & PROT_EXEC) + return ipe_process_event(vma->vm_file, ipe_operation_exec); + + return 0; +} + +/** + * ipe_kernel_read_file: LSM hook called when a file is being read in from + * disk. + * @file: Supplies a pointer to the file structure being read in from disk + * @id: Supplies the enumeration identifying the purpose of the read. + * @contents: Unused. + * + * Return: + * 0 - OK + * !0 - Error + */ +int ipe_kernel_read_file(struct file *file, enum kernel_read_file_id id, +bool contents) +{ + enum ipe_operation op; + + switch (id) { + case READING_FIRMWARE: + op = ipe_operation_firmware; + break; + case READING_MODULE: + op = ipe_operation_ker
[RFC PATCH v8 06/17] uapi|audit: add ipe audit message definitions
Introduce new definitions to audit.h centered around trust decisions and policy loading and activation, as an extension of the mandatory access control fields. Signed-off-by: Deven Bowers --- v2: + Split evaluation loop, access control hooks, and evaluation loop from policy parser and userspace interface to pass mailing list character limit v3: + Move ipe_load_properties to patch 04. + Remove useless 0-initializations + Prefix extern variables with ipe_ + Remove kernel module parameters, as these are exposed through sysctls. + Add more prose to the IPE base config option help text. + Use GFP_KERNEL for audit_log_start. + Remove unnecessary caching system. + Remove comments from headers + Use rcu_access_pointer for rcu-pointer null check + Remove usage of reqprot; use prot only. + Move policy load and activation audit event to 03/12 v4: + Remove sysctls in favor of securityfs nodes + Re-add kernel module parameters, as these are now exposed through securityfs. + Refactor property audit loop to a separate function. v5: + fix minor grammatical errors + do not group rule by curly-brace in audit record, reconstruct the exact rule. v6: + No changes v7: + Further split audit system patch into two separate patches; one for include/uapi, and the usage of the new defines. + Change audit records to MAC region (14XX) from Integrity region (18XX), as IPE is an effectively a MAC system around authenticity versus an extension to the integrity subsystem. + Generalize the #defines to support the class of trust-based access-control LSMs. v8: + Change audit type: + AUDIT_TRUST_RESULT -> AUDIT_IPE_ACCESS + Remove audit types (replaced by existing types): + AUDIT_TRUST_POLICY_LOAD + AUDIT_TRUST_POLICY_ACTIVATE + AUDIT_TRUST_STATUS --- include/uapi/linux/audit.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index 7c1dc818b1d5..78b9a04d5b41 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -143,6 +143,7 @@ #define AUDIT_MAC_UNLBL_STCDEL 1417/* NetLabel: del a static label */ #define AUDIT_MAC_CALIPSO_ADD 1418/* NetLabel: add CALIPSO DOI entry */ #define AUDIT_MAC_CALIPSO_DEL 1419/* NetLabel: del CALIPSO DOI entry */ +#define AUDIT_IPE_ACCESS 1420/* IPE Denial or Grant */ #define AUDIT_FIRST_KERN_ANOM_MSG 1700 #define AUDIT_LAST_KERN_ANOM_MSG1799 -- 2.25.1 -- Linux-audit mailing list Linux-audit@redhat.com https://listman.redhat.com/mailman/listinfo/linux-audit
[RFC PATCH v8 01/17] security: add ipe lsm & initial context creation
Integrity Policy Enforcement (IPE) is an LSM that provides an complimentary approach to Mandatory Access Control than existing LSMs today. Existing LSMs have centered around the concept of access to a resource should be controlled by the current user's credentials. IPE's approach, is that access to a resource should be controlled by the system's trust of a current resource. The basis of this approach is that every process in the kernel is associated with a context that determines the policy for what is trusted by said process and its descendents, starting with 'init'. Signed-off-by: Deven Bowers --- v2: + Split evaluation loop, access control hooks, and evaluation loop from policy parser and userspace interface to pass mailing list character limit v3: + Move ipe_load_properties to patch 04. + Remove useless 0-initializations + Prefix extern variables with ipe_ + Remove kernel module parameters, as these are exposed through sysctls. + Add more prose to the IPE base config option help text. + Use GFP_KERNEL for audit_log_start. + Remove unnecessary caching system. + Remove comments from headers + Use rcu_access_pointer for rcu-pointer null check + Remove usage of reqprot; use prot only. + Move policy load and activation audit event to 03/12 v4: + Remove sysctls in favor of securityfs nodes + Re-add kernel module parameters, as these are now exposed through securityfs. + Refactor property audit loop to a separate function. v5: + fix minor grammatical errors + do not group rule by curly-brace in audit record, reconstruct the exact rule. v6: + No changes v7: + Further split lsm creation into a separate commit from the evaluation loop and audit system, for easier review. + Introduce the concept of an ipe_context, a scoped way to introduce execution policies, used initially for allowing for kunit tests in isolation. v8: + Follow lsmname_hook_name convention for lsm hooks. + Move LSM blob accessors to ipe.c and mark LSM blobs as static. --- MAINTAINERS | 6 ++ security/Kconfig | 11 ++-- security/Makefile | 1 + security/ipe/Kconfig | 17 + security/ipe/Makefile | 11 security/ipe/ctx.c| 145 ++ security/ipe/ctx.h| 28 security/ipe/hooks.c | 54 security/ipe/hooks.h | 16 + security/ipe/ipe.c| 73 + security/ipe/ipe.h| 17 + 11 files changed, 374 insertions(+), 5 deletions(-) create mode 100644 security/ipe/Kconfig create mode 100644 security/ipe/Makefile create mode 100644 security/ipe/ctx.c create mode 100644 security/ipe/ctx.h create mode 100644 security/ipe/hooks.c create mode 100644 security/ipe/hooks.h create mode 100644 security/ipe/ipe.c create mode 100644 security/ipe/ipe.h diff --git a/MAINTAINERS b/MAINTAINERS index a6d3bd9d2a8d..965fdac6d609 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9793,6 +9793,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git F: security/integrity/ima/ F: security/integrity/ +INTEGRITY POLICY ENFORCEMENT (IPE) +M: Deven Bowers +M: Fan Wu +S: Supported +F: security/ipe/ + INTEL 810/815 FRAMEBUFFER DRIVER M: Antonino Daplas L: linux-fb...@vger.kernel.org diff --git a/security/Kconfig b/security/Kconfig index f29e4c656983..7d4c641313ca 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -218,6 +218,7 @@ source "security/yama/Kconfig" source "security/safesetid/Kconfig" source "security/lockdown/Kconfig" source "security/landlock/Kconfig" +source "security/ipe/Kconfig" source "security/integrity/Kconfig" @@ -257,11 +258,11 @@ endchoice config LSM string "Ordered list of enabled LSMs" - default "landlock,lockdown,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor,bpf" if DEFAULT_SECURITY_SMACK - default "landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf" if DEFAULT_SECURITY_APPARMOR - default "landlock,lockdown,yama,loadpin,safesetid,integrity,tomoyo,bpf" if DEFAULT_SECURITY_TOMOYO - default "landlock,lockdown,yama,loadpin,safesetid,integrity,bpf" if DEFAULT_SECURITY_DAC - default "landlock,lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor,bpf" + default "landlock,lockdown,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor,bpf,ipe" if DEFAULT_SECURITY_SMACK + default "landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf,ipe" if DEFAULT_SECURITY_APPARMOR + default "landlock,lockdown,yama,loadpin,safesetid,integrity,tomoyo,bpf,ipe" if DEFAULT_SECURITY_TOMOYO + default "landlock,lockdown,yama,loadpin,safesetid,integrity,bpf,ipe" if DEFAULT_SECURITY_DAC + default "landlock,lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor,bpf,i
[RFC PATCH v8 16/17] ipe: kunit tests
Add various happy/unhappy unit tests for both IPE's parser and evaluation loop, testing the core of IPE. The missing test gap remains the interface with userspace. Signed-off-by: Deven Bowers --- v1-v6: + Not present v7: Introduced v8: + Remove the kunit tests with respect to the fsverity digest, as these require significant changes to work with the new method of acquiring the digest at runtime. --- security/ipe/Kconfig | 17 + security/ipe/Makefile | 3 + security/ipe/ctx_test.c| 718 + security/ipe/eval.c| 4 + security/ipe/policy_parser_tests.c | 313 + 5 files changed, 1055 insertions(+) create mode 100644 security/ipe/ctx_test.c create mode 100644 security/ipe/policy_parser_tests.c diff --git a/security/ipe/Kconfig b/security/ipe/Kconfig index 619bf179af43..8746022f147b 100644 --- a/security/ipe/Kconfig +++ b/security/ipe/Kconfig @@ -81,4 +81,21 @@ config IPE_AUDIT_HASH_ALG source "security/ipe/modules/Kconfig" +config SECURITY_IPE_KUNIT_TEST + bool "Build KUnit tests for IPE" if !KUNIT_ALL_TESTS + depends on KUNIT=y + default KUNIT_ALL_TESTS + help + This builds the IPE KUnit tests. + + KUnit tests run during boot and output the results to the debug log + in TAP format (https://testanything.org/). Only useful for kernel devs + running KUnit test harness and are not for inclusion into a + production build. + + For more information on KUnit and unit tests in general please refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + + If unsure, say N. + endif diff --git a/security/ipe/Makefile b/security/ipe/Makefile index 1a1f7484caee..c91672a05d5f 100644 --- a/security/ipe/Makefile +++ b/security/ipe/Makefile @@ -31,4 +31,7 @@ obj-$(CONFIG_SECURITY_IPE) += \ obj-$(CONFIG_IPE_AUDIT) += audit.o +obj-$(CONFIG_SECURITY_IPE_KUNIT_TEST) += \ + policy_parser_tests.o \ + clean-files := boot-policy.c \ diff --git a/security/ipe/ctx_test.c b/security/ipe/ctx_test.c new file mode 100644 index ..1bbf5d5320e0 --- /dev/null +++ b/security/ipe/ctx_test.c @@ -0,0 +1,718 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Microsoft Corporation. All rights reserved. + */ +#include +#include +#include +#include +#include "ctx.h" +#include "policy.h" +#include "hooks.h" + +struct eval_case { + const char *const desc; + const char *const policy; + int errno; + + const struct file *fake_file; + const struct ipe_bdev *bdev_sec; + const struct ipe_inode *inode_sec; + bool initsb; +}; + +static const u8 fake_digest[] = { 0xDE, 0xAD, 0xBE, 0xEF }; + +static const struct ipe_bdev fake_bdev_no_data = {}; +static const struct ipe_bdev fake_bdev_no_sig = { + .digest = fake_digest, + .digest_len = ARRAY_SIZE(fake_digest), + .digest_algo = "test", +}; + +static const struct ipe_bdev fake_bdev_signed = { + .dm_verity_signed = true, + .digest = fake_digest, + .digest_len = ARRAY_SIZE(fake_digest), + .digest_algo = "test", +}; + +static const struct ipe_inode fake_ino_no_data = {}; +static const struct ipe_inode fake_ino_signed = { + .fs_verity_signed = true, +}; + +static struct inode fake_inode = { + .i_flags = S_VERITY +}; + +static const struct file fake_verity = { + .f_inode = &fake_inode, +}; + +static const struct eval_case cases[] = { + { + "boot_verified_trust_no_source", + "policy_name='Test' policy_version=0.0.0\n" + "DEFAULT action=DENY\n" + "op=EXECUTE boot_verified=TRUE action=ALLOW\n" + "op=KERNEL_READ boot_verified=TRUE action=ALLOW\n", + -EACCES, NULL, NULL, NULL, false + }, + { + "boot_verified_distrust", + "policy_name='Test' policy_version=0.0.0\n" + "DEFAULT action=DENY\n" + "op=EXECUTE boot_verified=FALSE action=ALLOW\n" + "op=KERNEL_READ boot_verified=FALSE action=ALLOW\n", + 0, NULL, NULL, NULL, false + }, + { + "boot_verified_trust", + "policy_name='Test' policy_version=0.0.0\n" + "DEFAULT action=DENY\n" + "op=EXECUTE boot_verified=TRUE action=ALLOW\n" + "op=KERNEL_READ boot_verified=TRUE action=ALLOW\n", + 0, NULL, NULL, NULL, true + }, + { + "boot_verified_trust", + "policy_name='Test' policy_version=0.0.0\n" + "DEFAULT action=DENY\n" + "op=EXECUTE boot_verified=FALSE action=ALLOW\n" + "op=KERNEL_READ boot_verified=FALSE action=ALLOW\n", + -EACCES, NULL, NULL, NULL, true + }, + { + "dmverity_signature_trust_no_bdev", + "po
[RFC PATCH v8 11/17] dm-verity: consume root hash digest and signature data via LSM hook
dm-verity provides a strong guarantee of a block device's integrity. As a generic way to check the integrity of a block device, it provides those integrity guarantees to its lower layers, including the filesystem level. An LSM that control access to a resource on the system based on the available integrity claims can use this transitive property of dm-verity, by querying the underlying block_device of a particular file. The digest and signature information need to be stored in the block device to fulfill the next requirement of authorization via LSM policy. This will enable the LSM being able to perform revocation of devices that are still mounted, prohibiting execution of files that are no longer authorized by the LSM in question. Signed-off-by: Deven Bowers --- v2: + No Changes v3: + No changes v4: + No changes v5: + No changes v6: + Fix an improper cleanup that can result in a leak v7: + Squash patch 08/12, 10/12 to [11/16] + Use part0 for block_device, to retrieve the block_device, when calling security_bdev_setsecurity v8: + Undo squash of 08/12, 10/12 - separating drivers/md/ from security/ & block/ + Use common-audit function for dmverity_signature. + Change implementation for storing the dm-verity digest to use the newly introduced dm_verity_digest structure introduced in patch 14/20. + Create new structure, dm_verity_digest, containing digest algorithm, size, and digest itself to pass to the LSM layer. V7 was missing the algorithm. + Create an associated public header containing this new structure and the key values for the LSM hook, specific to dm-verity. + Additional information added to commit, discussing the layering of the changes and how the information passed will be used. --- drivers/md/dm-verity-target.c | 25 +++-- drivers/md/dm-verity-verify-sig.c | 16 +--- drivers/md/dm-verity-verify-sig.h | 10 ++ include/linux/dm-verity.h | 19 +++ 4 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 include/linux/dm-verity.h diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index d6dbd47492a8..0d499441e780 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -13,12 +13,16 @@ * access behavior. */ +#include "dm-core.h" #include "dm-verity.h" #include "dm-verity-fec.h" #include "dm-verity-verify-sig.h" #include #include #include +#include +#include +#include #define DM_MSG_PREFIX "verity" @@ -1060,6 +1064,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) sector_t hash_position; char dummy; char *root_hash_digest_to_validate; + struct block_device *bdev; + struct dm_verity_digest root_digest; v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL); if (!v) { @@ -1093,6 +1099,13 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) } v->version = num; + bdev = dm_table_get_md(ti->table)->disk->part0; + if (!bdev) { + ti->error = "Mapped device lookup failed"; + r = -ENOMEM; + goto bad; + } + r = dm_get_device(ti, argv[1], FMODE_READ, &v->data_dev); if (r) { ti->error = "Data device lookup failed"; @@ -1225,7 +1238,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) } /* Root hash signature is a optional parameter*/ - r = verity_verify_root_hash(root_hash_digest_to_validate, + r = verity_verify_root_hash(bdev, root_hash_digest_to_validate, strlen(root_hash_digest_to_validate), verify_args.sig, verify_args.sig_size); @@ -1298,12 +1311,20 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) ti->per_io_data_size = roundup(ti->per_io_data_size, __alignof__(struct dm_verity_io)); + root_digest.digest = v->root_digest; + root_digest.digest_len = v->digest_size; + root_digest.algo = v->alg_name; + + r = security_bdev_setsecurity(bdev, DM_VERITY_ROOTHASH_SEC_NAME, &root_digest, + sizeof(root_digest)); + if (r) + goto bad; + verity_verify_sig_opts_cleanup(&verify_args); return 0; bad: - verity_verify_sig_opts_cleanup(&verify_args); verity_dtr(ti); diff --git a/drivers/md/dm-verity-verify-sig.c b/drivers/md/dm-verity-verify-sig.c index db61a1f43ae9..06c15c555a4b 100644 --- a/drivers/md/dm-verity-verify-sig.c +++ b/drivers/md/dm-verity-verify-sig.c @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include "dm-core.h" #include "dm-verity.h" #include "dm-verity-verify-sig.h" @@ -97,14 +
[RFC PATCH v8 09/17] ipe: introduce 'boot_verified' as a trust provider
IPE is designed to provide system level trust guarantees, this usually implies that trust starts from bootup with a hardware root of trust, which validates the bootloader. After this, the bootloader verifies the kernel and the initramfs. As there's no currently supported integrity method for initramfs, and it's typically already verified by the bootloader, introduce a property that causes the first superblock to have an execution to be "pinned", which is typically initramfs. Signed-off-by: Deven Bowers --- v2: + No Changes v3: + Remove useless caching system + Move ipe_load_properties to this match + Minor changes from checkpatch --strict warnings v4: + Remove comments from headers that was missed previously. + Grammatical corrections. v5: + No significant changes v6: + No changes v7: + Reword and refactor patch 04/12 to [09/16], based on changes in the underlying system. + Add common audit function for boolean values + Use common audit function as implementation. v8: + No changes --- security/ipe/Kconfig | 2 + security/ipe/Makefile| 1 + security/ipe/eval.c | 71 security/ipe/eval.h | 5 ++ security/ipe/hooks.c | 14 ++ security/ipe/hooks.h | 2 + security/ipe/ipe.c | 1 + security/ipe/modules.c | 30 security/ipe/modules/Kconfig | 20 security/ipe/modules/Makefile| 8 security/ipe/modules/boot_verified.c | 26 ++ security/ipe/modules/ipe_module.h| 3 ++ 12 files changed, 183 insertions(+) create mode 100644 security/ipe/modules/Kconfig create mode 100644 security/ipe/modules/Makefile create mode 100644 security/ipe/modules/boot_verified.c diff --git a/security/ipe/Kconfig b/security/ipe/Kconfig index 1ad2f34b98ec..69345fa49be5 100644 --- a/security/ipe/Kconfig +++ b/security/ipe/Kconfig @@ -69,4 +69,6 @@ config IPE_AUDIT_HASH_ALG default "sha384" if IPE_AUDIT_HASH_SHA384 default "sha512" if IPE_AUDIT_HASH_SHA512 +source "security/ipe/modules/Kconfig" + endif diff --git a/security/ipe/Makefile b/security/ipe/Makefile index 25a7d7c8f07c..0d970236efc4 100644 --- a/security/ipe/Makefile +++ b/security/ipe/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_SECURITY_IPE) += \ fs.o \ hooks.o \ ipe.o \ + modules/ \ modules.o \ parsers/ \ parsers.o \ diff --git a/security/ipe/eval.c b/security/ipe/eval.c index eafa670558e3..ccf9b843040b 100644 --- a/security/ipe/eval.c +++ b/security/ipe/eval.c @@ -11,10 +11,62 @@ #include "modules/ipe_module.h" #include "audit.h" +#include +#include #include #include #include #include +#include + +static struct super_block *pinned_sb; +static DEFINE_SPINLOCK(pin_lock); + +#define FILE_SUPERBLOCK(f) ((f)->f_path.mnt->mnt_sb) + +/** + * pin_sb: pin the underlying superblock of @f, marking it as trusted + * @f: Supplies a file structure to source the super_block from. + */ +static void pin_sb(const struct file *f) +{ + if (!f) + return; + + spin_lock(&pin_lock); + + if (pinned_sb) + goto out; + + pinned_sb = FILE_SUPERBLOCK(f); + +out: + spin_unlock(&pin_lock); +} + +/** + * from_pinned: determine whether @f is source from the pinned super_block. + * @f: Supplies a file structure to check against the pinned super_block. + * + * Return: + * true - @f is sourced from the pinned super_block + * false - @f is not sourced from the pinned super_block + */ +static bool from_pinned(const struct file *f) +{ + bool rv; + + if (!f) + return false; + + spin_lock(&pin_lock); + + rv = !IS_ERR_OR_NULL(pinned_sb) && pinned_sb == FILE_SUPERBLOCK(f); + + spin_unlock(&pin_lock); + + return rv; +} /** * build_ctx: Build an evaluation context. @@ -40,6 +92,7 @@ static struct ipe_eval_ctx *build_ctx(const struct file *file, ctx->file = file; ctx->op = op; ctx->ci_ctx = ipe_current_ctx(); + ctx->from_init_sb = from_pinned(file); return ctx; } @@ -148,6 +201,9 @@ int ipe_process_event(const struct file *file, enum ipe_operation op) int rc = 0; struct ipe_eval_ctx *ctx = NULL; + if (op == ipe_operation_exec) + pin_sb(file); + ctx = build_ctx(file, op); if (IS_ERR(ctx)) return PTR_ERR(ctx); @@ -157,3 +213,18 @@ int ipe_process_event(const struct file *file, enum ipe_operation op) free_ctx(ctx); return rc; } + +/** + * ipe_invalidate_pinned_sb: if @mnt_sb is the pinned superblock, ensure + * nothing can match it again. + * @mnt_sb: super_block to check against the pinned super_block + */ +void ipe_invalidate_pinned_sb(const struct super_block *mnt_sb) +{ + spin_lock(&pin_lock); + + if (!IS_ERR_
[RFC PATCH v8 04/17] ipe: add userspace interface
As is typical with LSMs, IPE uses securityfs as its interface with userspace. for a complete list of the interfaces and the respective inputs/outputs, please see the documentation under admin-guide/LSM/ipe.rst Signed-off-by: Deven Bowers --- v2: + Split evaluation loop, access control hooks, and evaluation loop from policy parser and userspace interface to pass mailing list character limit v3: + Move policy load and activation audit event to 03/12 + Fix a potential panic when a policy failed to load. + use pr_warn for a failure to parse instead of an audit record + Remove comments from headers + Add lockdep assertions to ipe_update_active_policy and ipe_activate_policy + Fix up warnings with checkpatch --strict + Use file_ns_capable for CAP_MAC_ADMIN for securityfs nodes. + Use memdup_user instead of kzalloc+simple_write_to_buffer. + Remove strict_parse command line parameter, as it is added by the sysctl command line. + Prefix extern variables with ipe_ v4: + Remove securityfs to reverse-dependency + Add SHA1 reverse dependency. + Add versioning scheme for IPE properties, and associated interface to query the versioning scheme. + Cause a parser to always return an error on unknown syntax. + Remove strict_parse option + Change active_policy interface from sysctl, to securityfs, and change scheme. v5: + Cause an error if a default action is not defined for each operaiton. + Minor function renames v6: + No changes v7: + Propogating changes to support the new ipe_context structure in the evaluation loop. + Further split the parser and userspace interface changes into separate commits. + "raw" was renamed to "pkcs7" and made read only + "raw"'s write functionality (update a policy) moved to "update" + introduced "version", "policy_name" nodes. + "content" renamed to "policy" + changes to allow the compiled-in policy to be treated identical to deployed-after-the-fact policies. Introduced in v8: + Prevent securityfs initialization if the LSM is disabled --- security/ipe/Makefile | 2 + security/ipe/ctx.c | 121 + security/ipe/ctx.h | 6 + security/ipe/fs.c | 173 + security/ipe/fs.h | 13 + security/ipe/ipe.c | 3 + security/ipe/ipe.h | 2 + security/ipe/policy.c | 41 security/ipe/policy.h | 4 + security/ipe/policyfs.c | 528 10 files changed, 893 insertions(+) create mode 100644 security/ipe/fs.c create mode 100644 security/ipe/fs.h create mode 100644 security/ipe/policyfs.c diff --git a/security/ipe/Makefile b/security/ipe/Makefile index 0db69f13e82a..d5660a17364c 100644 --- a/security/ipe/Makefile +++ b/security/ipe/Makefile @@ -10,9 +10,11 @@ ccflags-y := -I$(srctree)/security/ipe/modules obj-$(CONFIG_SECURITY_IPE) += \ ctx.o \ eval.o \ + fs.o \ hooks.o \ ipe.o \ modules.o \ parsers/ \ parsers.o \ policy.o \ + policyfs.o \ diff --git a/security/ipe/ctx.c b/security/ipe/ctx.c index 97305ddc2ff7..177f60f02ed4 100644 --- a/security/ipe/ctx.c +++ b/security/ipe/ctx.c @@ -13,6 +13,29 @@ #include #include +/** + * ver_to_u64: convert an internal ipe_policy_version to a u64 + * @p: Policy to extract the version from + * + * Bits (LSB is index 0): + * [48,32] -> Major + * [32,16] -> Minor + * [16, 0] -> Revision + * + * Return: + * u64 version of the embedded version structure. + */ +static inline u64 ver_to_u64(const struct ipe_policy *const p) +{ + u64 r = 0; + + r = (((u64)p->parsed->version.major) << 32) + | (((u64)p->parsed->version.minor) << 16) + | ((u64)(p->parsed->version.rev)); + + return r; +} + /** * ipe_current_ctx: Helper to retrieve the ipe_context for the current task. * @@ -80,6 +103,7 @@ static void free_ctx_work(struct work_struct *const work) list_for_each_entry(p, &ctx->policies, next) ipe_put_policy(p); + securityfs_remove(ctx->policy_root); kfree(ctx); } @@ -144,6 +168,9 @@ void ipe_remove_policy(struct ipe_policy *p) * ipe_add_policy: Associate @p with @ctx * @ctx: Supplies a pointer to the ipe_context structure to associate @p with. * @p: Supplies a pointer to the ipe_policy structure to associate. + * + * This will increase @p's reference count by one. + * */ void ipe_add_policy(struct ipe_context *ctx, struct ipe_policy *p) { @@ -152,7 +179,101 @@ void ipe_add_policy(struct ipe_context *ctx, struct ipe_policy *p) list_add_tail(&p->next, &ctx->policies); refcount_inc(&p->refcount); spin_unlock(&ctx->lock); +} + +/** + * ipe_replace_policy: Replace @old with @new in the list of policies in @ctx + * @ctx: Supplies the context object to manipulate. + * @old: Supplies a pointer to the ipe_policy to replace with @new + * @new: Supplies a pointer to the i
[RFC PATCH v8 08/17] ipe: add permissive toggle
IPE, like SELinux, supports a permissive mode. This mode allows policy authors to test and evaluate IPE policy without it effecting their programs. When the mode is changed, a 1423 AUDIT_TRUST_STATUS will be reported. Signed-off-by: Deven Bowers --- This patch adds the following audit records: type=1404 audit(1653425689.008:55): permissive=1 type=1404 audit(1653425689.008:55): permissive=0 These records are emitted within the following events: type=1404 audit(1653425689.008:55): permissive=1 type=1300 audit(1653425689.008:55): arch=c03e syscall=1 success=yes exit=2 a0=1 a1=55c1065e5c60 a2=2 a3=0 items=0 ppid=405 pid=441 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=) type=1327 audit(1653425689.008:55): proctitle="-bash" --- v2: + Split evaluation loop, access control hooks, and evaluation loop from policy parser and userspace interface to pass mailing list character limit v3: + Move ipe_load_properties to patch 04. + Remove useless 0-initializations + Prefix extern variables with ipe_ + Remove kernel module parameters, as these are exposed through sysctls. + Add more prose to the IPE base config option help text. + Use GFP_KERNEL for audit_log_start. + Remove unnecessary caching system. + Remove comments from headers + Use rcu_access_pointer for rcu-pointer null check + Remove usage of reqprot; use prot only. + Move policy load and activation audit event to 03/12 v4: + Remove sysctls in favor of securityfs nodes + Re-add kernel module parameters, as these are now exposed through securityfs. + Refactor property audit loop to a separate function. v5: + fix minor grammatical errors + do not group rule by curly-brace in audit record, reconstruct the exact rule. v6: + No changes v7: + Further split lsm creation into a separate commit from the evaluation loop and audit system, for easier review. + Propogating changes to support the new ipe_context structure in the evaluation loop. + Split out permissive functionality into a separate patch for easier review. + Remove permissive switch compile-time configuration option - this is trivial to add later. v8: + Remove "IPE" prefix from permissive audit record + align fields to the linux-audit field dictionary. This causes the following fields to change: enforce -> permissive + Remove duplicated information correlated with syscall record, that will always be present in the audit event. + Change audit types: + AUDIT_TRUST_STATUS -> AUDIT_MAC_STATUS + There is no significant difference in meaning between these types. --- security/ipe/audit.c | 43 security/ipe/audit.h | 5 +++ security/ipe/ctx.c | 6 security/ipe/ctx.h | 1 + security/ipe/eval.c | 6 security/ipe/fs.c| 78 6 files changed, 139 insertions(+) diff --git a/security/ipe/audit.c b/security/ipe/audit.c index 0442cc51a4bd..cf0ccea32c90 100644 --- a/security/ipe/audit.c +++ b/security/ipe/audit.c @@ -182,3 +182,46 @@ void ipe_audit_policy_load(const struct ipe_policy *const p) audit_log_end(ab); } + +/** + * ipe_audit_enforce: Audit a change in IPE's enforcement state + * @ctx: Supplies a pointer to the contexts whose state changed. + */ +void ipe_audit_enforce(const struct ipe_context *const ctx) +{ + struct audit_buffer *ab; + bool enforcing = false; + + ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS); + if (!ab) + return; + + rcu_read_lock(); + enforcing = READ_ONCE(ctx->enforce); + rcu_read_unlock(); + + audit_log_format(ab, "permissive=%d", !enforcing); + + audit_log_end(ab); +} + +/** + * emit_enforcement: Emit the enforcement state of IPE started with. + * + * Return: + * 0 - Always + */ +static int emit_enforcement(void) +{ + struct ipe_context *ctx = NULL; + + if (!ipe_enabled) + return -EOPNOTSUPP; + + ctx = ipe_current_ctx(); + ipe_audit_enforce(ctx); + ipe_put_ctx(ctx); + return 0; +} + +late_initcall(emit_enforcement); diff --git a/security/ipe/audit.h b/security/ipe/audit.h index bec03208042d..daff9c801a8e 100644 --- a/security/ipe/audit.h +++ b/security/ipe/audit.h @@ -15,6 +15,7 @@ void ipe_audit_match(const struct ipe_eval_ctx *const ctx, enum ipe_action act, const struct ipe_rule *const r); void ipe_audit_policy_load(const struct ipe_policy *const p); void ipe_audit_policy_activation(const struct ipe_policy *const p); +void ipe_audit_enforce(const struct ipe_context *const ctx); #else static inline void ipe_audit_match(const struct ipe_eval_ctx *const ctx, enum ipe_match match_type, @@ -29,6 +30,10 @@ static inline void ipe_audit_policy_load(const struct ipe_policy *const p) static inline void ipe_audit_policy_activation(const st
[RFC PATCH v8 17/17] documentation: add ipe documentation
Add IPE's admin and developer documentation to the kernel tree. Co-developed-by: Fan Wu Signed-off-by: Fan Wu Signed-off-by: Deven Bowers --- v2: + No Changes v3: + Add Acked-by + Fixup code block syntax + Fix a minor grammatical issue. v4: + Update documentation with the results of other code changes. v5: + No changes v6: + No changes v7: + Add additional developer-level documentation + Update admin-guide docs to reflect changes. + Drop Acked-by due to significant changes + Added section about audit events in admin-guide v8: + Correct terminology from "audit event" to "audit record" + Add associated documentation with the correct "audit event" terminology. + Add some context to the historical motivation for IPE and design philosophy. + Add some content about the securityfs layout in the policies directory. + Various spelling and grammatical corrections. --- Documentation/admin-guide/LSM/index.rst | 1 + Documentation/admin-guide/LSM/ipe.rst | 739 ++ .../admin-guide/kernel-parameters.txt | 12 + Documentation/security/index.rst | 1 + Documentation/security/ipe.rst| 559 + MAINTAINERS | 2 + 6 files changed, 1314 insertions(+) create mode 100644 Documentation/admin-guide/LSM/ipe.rst create mode 100644 Documentation/security/ipe.rst diff --git a/Documentation/admin-guide/LSM/index.rst b/Documentation/admin-guide/LSM/index.rst index a6ba95fbaa9f..ce63be6d64ad 100644 --- a/Documentation/admin-guide/LSM/index.rst +++ b/Documentation/admin-guide/LSM/index.rst @@ -47,3 +47,4 @@ subdirectories. tomoyo Yama SafeSetID + ipe diff --git a/Documentation/admin-guide/LSM/ipe.rst b/Documentation/admin-guide/LSM/ipe.rst new file mode 100644 index ..58335ce4f85b --- /dev/null +++ b/Documentation/admin-guide/LSM/ipe.rst @@ -0,0 +1,739 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Integrity Policy Enforcement (IPE) +== + +.. NOTE:: + + This is the documentation for admins, system builders, or individuals + attempting to use IPE. If you're looking for more developer-focused + documentation about IPE please see `Documentation/security/ipe.rst` + +Overview + + +IPE is a Linux Security Module which takes a complimentary approach to +access control. Whereas existing mandatory access control mechanisms +base their decisions on labels and paths, IPE instead determines +whether or not an operation should be allowed based on immutable +security properties of the system component the operation is being +performed on. + +IPE itself does not mandate how the security property should be +evaluated, but relies on an extensible set of external property providers +to evaluate the component. IPE makes its decision based on reference +values for the selected properties, specified in the IPE policy. + +The reference values represent the value that the policy writer and the +local system administrator (based on the policy signature) trust for the +system to accomplish the desired tasks. + +One such provider is for example dm-verity, which is able to represent +the integrity property of a partition (its immutable state) with a digest. + +IPE is compiled under ``CONFIG_SECURITY_IPE`` (Security -> Integrity Policy Enforcement (IPE)). + +Use Cases +- + +IPE works best in fixed-function devices: devices in which their purpose +is clearly defined and not supposed to be changed (e.g. network firewall +device in a data center, an IoT device, etcetera), where all software and +configuration is built and provisioned by the system owner. + +IPE is a long-way off for use in general-purpose computing: the Linux +community as a whole tends to follow a decentralized trust model, +known as the web of trust, which IPE has no support for as of yet. + +IPE, instead of supporting web of trust, supports PKI, which generally +designates a set of entities that provide a measure of absolute trust. + +Additionally, while most packages are signed today, the files inside +the packages (for instance, the executables), tend to be unsigned. This +makes it difficult to utilize IPE in systems where a package manager is +expected to be functional, without major changes to the package manager +and ecosystem behind it. + +DIGLIM [#diglim]_ is a system that when combined with IPE, could be used to +enable general purpose computing scenarios. + +Known Gaps +-- + +IPE cannot verify the integrity of anonymous executable memory, such as +the trampolines created by gcc closures and libffi (<3.4.2), or JIT'd code. +Unfortunately, as this is dynamically generated code, there is no way +for IPE to ensure the integrity of this code to form a trust basis. In all +cases, the return result for these operations will be whatever the admin +configures as the ``DEFAULT`` action for ``EXECUTE``. + +IPE cannot verify the integrity o
[RFC PATCH v8 00/17] Integrity Policy Enforcement LSM (IPE)
Overview: - IPE is a Linux Security Module which takes a complimentary approach to access control. Whereas existing mandatory access control mechanisms base their decisions on labels and paths, IPE instead determines whether or not an operation should be allowed based on immutable security properties of the system component the operation is being performed on. IPE itself does not mandate how the security property should be evaluated, but relies on an extensible set of external property providers to evaluate the component. IPE makes its decision based on reference values for the selected properties, specified in the IPE policy. The reference values represent the value that the policy writer and the local system administrator (based on the policy signature) trust for the system to accomplish the desired tasks. One such provider is for example dm-verity, which is able to represent the integrity property of a partition (its immutable state) with a digest. IPE is compiled under CONFIG_SECURITY_IPE. Use Cases - IPE works best in fixed-function devices: Devices in which their purpose is clearly defined and not supposed to be changed (e.g. network firewall device in a data center, an IoT device, etcetera), where all software and configuration is built and provisioned by the system owner. IPE is a long-way off for use in general-purpose computing: the Linux community as a whole tends to follow a decentralized trust model, known as the web of trust, which IPE has no support for as of yet. There are exceptions, to this general-purpose computing rule; however, such as the scenario, wherein Linux distribution vendors trust only their own keys - in this case, IPE can be used to enforce the trust reqiurement. IPE, instead of supporting web of trust, supports PKI, which generally designates a set of entities that provide a measure absolute trust. Commonly used in embedded systems, Additionally, while most packages are signed today, the files inside the packages (for instance, the executables), tend to be unsigned. This makes it difficult to utilize IPE in systems where a package manager is expected to be functional, without major changes to the package manager and ecosystem behind it. DIGLIM[1] is a system that when combined with IPE, could be used to enable general purpose computing scenarios. Policy: --- IPE policy is a plain-text policy composed of multiple statements over several lines. There is one required line, at the top of the policy, indicating the policy name, and the policy version, for instance: policy_name="Ex Policy" policy_version=0.0.0 The policy version indicates the current version of the policy (NOT the policy syntax version). This is used to prevent roll-back of policy to potentially insecure previous versions of the policy. The next portion of IPE policy, are rules. Rules are formed by key=value pairs, known as properties. IPE rules require two keys: "action", which determines what IPE does when it encounters a match against the policy and "op", which determines when that rule should be evaluated. Thus, a minimal rule is: op=EXECUTE action=ALLOW This example will allow any execution. Additional properties are used to restrict attributes about the files being evaluated. These properties are intended to be deterministic attributes that are resident in the kernel. Available properties for IPE described in the documentation patch of this series. A rule is required to have the "op" property as the first token of a rule, and the "action" as the last token of the rule. Rules are evaluated top-to-bottom. As a result, any revocation rules, or denies should be placed early in the file to ensure that these rules are evaluated before a rule with "action=ALLOW" is hit. Any unknown syntax in IPE policy will result in a fatal error to parse the policy. User mode can interrogate the kernel to understand what properties and the associated versions through the securityfs node, $securityfs/ipe/config, which will return a string of form: key1=version1 key2=version2 . . . keyN=versionN User-mode should correlate these versions with the supported values identified in the documentation to determine whether a policy should be accepted by the system without actually trying to deploy the policy. Additionally, a DEFAULT operation must be set for all understood operations within IPE. For policies to remain completely forwards compatible, it is recommended that users add a "DEFAULT action=ALLOW" and override the defaults on a per-operation basis. For more information about the policy syntax, see the kernel documentation page. Early Usermode Protection: -- IPE can be provided with a policy at startup to load and enforce. This is intended to be a minimal policy to get the system to a state where userland is setup and ready to receive commands, at which point a policy can be deployed via securityfs. This "boot policy" can be specified via the
[RFC PATCH v8 02/17] ipe: add policy parser
IPE's interpretation of the what the user trusts is accomplished through its policy. IPE's design is to not provide support for a single trust provider, but to support multiple providers to enable the end-user to choose the best one to seek their needs. This requires the policy to be rather flexible and modular so that integrity providers, like fs-verity, dm-verity, dm-integrity, or some other system, can plug into the policy with minimal code changes, and IPE can Signed-off-by: Deven Bowers --- v2: + Split evaluation loop, access control hooks, and evaluation loop from policy parser and userspace interface to pass mailing list character limit v3: + Move policy load and activation audit event to 03/12 + Fix a potential panic when a policy failed to load. + use pr_warn for a failure to parse instead of an audit record + Remove comments from headers + Add lockdep assertions to ipe_update_active_policy and ipe_activate_policy + Fix up warnings with checkpatch --strict + Use file_ns_capable for CAP_MAC_ADMIN for securityfs nodes. + Use memdup_user instead of kzalloc+simple_write_to_buffer. + Remove strict_parse command line parameter, as it is added by the sysctl command line. + Prefix extern variables with ipe_ v4: + Remove securityfs to reverse-dependency + Add SHA1 reverse dependency. + Add versioning scheme for IPE properties, and associated interface to query the versioning scheme. + Cause a parser to always return an error on unknown syntax. + Remove strict_parse option + Change active_policy interface from sysctl, to securityfs, and change scheme. v5: + Cause an error if a default action is not defined for each operaiton. + Minor function renames v6: + No changes v7: + Further split parser and userspace interface into two separate commits, for easier review. + Refactor policy parser to make code cleaner via introducing a more modular design, for easier extension of policy, and easier review. v8: + remove unnecessary pr_info emission on parser loading + add explicit newline to the pr_err emitted when a parser fails to load. --- include/asm-generic/vmlinux.lds.h| 16 + security/ipe/Makefile| 6 + security/ipe/ipe.c | 61 ++ security/ipe/ipe.h | 5 + security/ipe/ipe_parser.h| 59 ++ security/ipe/modules.c | 109 +++ security/ipe/modules.h | 17 + security/ipe/modules/ipe_module.h| 33 + security/ipe/parsers.c | 143 security/ipe/parsers/Makefile| 12 + security/ipe/parsers/default.c | 106 +++ security/ipe/parsers/policy_header.c | 126 security/ipe/policy.c| 946 +++ security/ipe/policy.h| 97 +++ 14 files changed, 1736 insertions(+) create mode 100644 security/ipe/ipe_parser.h create mode 100644 security/ipe/modules.c create mode 100644 security/ipe/modules.h create mode 100644 security/ipe/modules/ipe_module.h create mode 100644 security/ipe/parsers.c create mode 100644 security/ipe/parsers/Makefile create mode 100644 security/ipe/parsers/default.c create mode 100644 security/ipe/parsers/policy_header.c create mode 100644 security/ipe/policy.c create mode 100644 security/ipe/policy.h diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 7515a465ec03..8549b98d0cf6 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -284,6 +284,20 @@ #define EARLY_LSM_TABLE() #endif +#ifdef CONFIG_SECURITY_IPE +#define IPE_PARSER_TABLE() . = ALIGN(8); \ + __start_ipe_parsers = .;\ + KEEP(*(.ipe_parsers)) \ + __end_ipe_parsers = .; +#define IPE_MODULE_TABLE() . = ALIGN(8); \ + __start_ipe_modules = .;\ + KEEP(*(.ipe_modules)) \ + __end_ipe_modules = .; +#else +#define IPE_PARSER_TABLE() +#define IPE_MODULE_TABLE() +#endif + #define ___OF_TABLE(cfg, name) _OF_TABLE_##cfg(name) #define __OF_TABLE(cfg, name) ___OF_TABLE(cfg, name) #define OF_TABLE(cfg, name)__OF_TABLE(IS_ENABLED(cfg), name) @@ -436,6 +450,8 @@ KEEP(*(__tracepoints_ptrs)) /* Tracepoints: pointer array */ \ __stop___tracepoints_ptrs = .; \ *(__tracepoints_strings)/* Tracepoints: strings */ \ + IPE_PARSER_TABLE() \ + IPE_MODULE_TABLE() \ } \ \
[RFC PATCH v8 12/17] ipe: add support for dm-verity as a trust provider
Allows author of IPE policy to indicate trust for a singular dm-verity volume, identified by roothash, through "dmverity_roothash" and all signed dm-verity volumes, through "dmverity_signature". Signed-off-by: Deven Bowers --- v2: + No Changes v3: + No changes v4: + No changes v5: + No changes v6: + Fix an improper cleanup that can result in a leak v7: + Squash patch 08/12, 10/12 to [11/16] v8: + Undo squash of 08/12, 10/12 - separating drivers/md/ from security/ & block/ + Use common-audit function for dmverity_signature. + Change implementation for storing the dm-verity digest to use the newly introduced dm_verity_digest structure introduced in patch 14/20. --- security/ipe/eval.c | 5 + security/ipe/eval.h | 11 ++ security/ipe/hooks.c | 51 + security/ipe/hooks.h | 6 + security/ipe/ipe.c| 9 ++ security/ipe/ipe.h| 3 + security/ipe/modules.c| 133 ++ security/ipe/modules/Kconfig | 23 security/ipe/modules/Makefile | 2 + security/ipe/modules/dmverity_roothash.c | 31 + security/ipe/modules/dmverity_signature.c | 26 + security/ipe/modules/ipe_module.h | 5 + 12 files changed, 305 insertions(+) create mode 100644 security/ipe/modules/dmverity_roothash.c create mode 100644 security/ipe/modules/dmverity_signature.c diff --git a/security/ipe/eval.c b/security/ipe/eval.c index ccf9b843040b..9b29d83cd466 100644 --- a/security/ipe/eval.c +++ b/security/ipe/eval.c @@ -23,6 +23,7 @@ static struct super_block *pinned_sb; static DEFINE_SPINLOCK(pin_lock); #define FILE_SUPERBLOCK(f) ((f)->f_path.mnt->mnt_sb) +#define FILE_BLOCK_DEV(f) (FILE_SUPERBLOCK(f)->s_bdev) /** * pin_sb: pin the underlying superblock of @f, marking it as trusted @@ -93,6 +94,10 @@ static struct ipe_eval_ctx *build_ctx(const struct file *file, ctx->op = op; ctx->ci_ctx = ipe_current_ctx(); ctx->from_init_sb = from_pinned(file); + if (file) { + if (FILE_BLOCK_DEV(file)) + ctx->ipe_bdev = ipe_bdev(FILE_BLOCK_DEV(file)); + } return ctx; } diff --git a/security/ipe/eval.h b/security/ipe/eval.h index f195671eaa8f..57b7b2b424f8 100644 --- a/security/ipe/eval.h +++ b/security/ipe/eval.h @@ -8,17 +8,28 @@ #include #include +#include #include "ctx.h" #include "hooks.h" #include "policy.h" +struct ipe_bdev { + bool dm_verity_signed; + + const u8 *digest; + size_t digest_len; + const char *digest_algo; +}; + struct ipe_eval_ctx { enum ipe_operation op; const struct file *file; struct ipe_context *ci_ctx; + const struct ipe_bdev *ipe_bdev; + bool from_init_sb; }; diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c index 4dc7b0c0fd31..1072ee5bb8f6 100644 --- a/security/ipe/hooks.c +++ b/security/ipe/hooks.c @@ -13,8 +13,11 @@ #include #include #include +#include #include #include +#include +#include /** * ipe_task_alloc: Assign a new context for an associated task structure. @@ -216,3 +219,51 @@ void ipe_sb_free_security(struct super_block *mnt_sb) { ipe_invalidate_pinned_sb(mnt_sb); } + +/** + * ipe_bdev_free_security: free nested structures within IPE's LSM blob + *in block_devices + * @bdev: Supplies a pointer to a block_device that contains the structure + * to free. + */ +void ipe_bdev_free_security(struct block_device *bdev) +{ + struct ipe_bdev *blob = ipe_bdev(bdev); + + kfree(blob->digest); + kfree(blob->digest_algo); +} + +/** + * ipe_bdev_setsecurity: associate some data from the block device layer + * with IPE's LSM blob. + * @bdev: Supplies a pointer to a block_device that contains the LSM blob. + * @key: Supplies the string key that uniquely identifies the value. + * @value: Supplies the value to store. + * @len: The length of @value. + */ +int ipe_bdev_setsecurity(struct block_device *bdev, const char *key, +const void *value, size_t len) +{ + struct ipe_bdev *blob = ipe_bdev(bdev); + + if (!strcmp(key, DM_VERITY_ROOTHASH_SEC_NAME)) { + const struct dm_verity_digest *digest = value; + + blob->digest = kmemdup(digest->digest, digest->digest_len, GFP_KERNEL); + if (!blob->digest) + return -ENOMEM; + + blob->digest_algo = kstrdup_const(digest->algo, GFP_KERNEL); + if (!blob->digest_algo) + return -ENOMEM; + + blob->digest_len = digest->digest_len; + return 0; + } else if (!strcmp(key, DM_VERITY_SIGNATURE_SEC_NAME)) { + blob->dm_verity_signed = true; + return
[RFC PATCH v8 03/17] ipe: add evaluation loop
IPE must have a centralized function to evaluate incoming callers against IPE's policy. This iteration of the policy for against the rules for that specific caller is known as the evaluation loop. Signed-off-by: Deven Bowers --- v2: + Split evaluation loop, access control hooks, and evaluation loop from policy parser and userspace interface to pass mailing list character limit v3: + Move ipe_load_properties to patch 04. + Remove useless 0-initializations + Prefix extern variables with ipe_ + Remove kernel module parameters, as these are exposed through sysctls. + Add more prose to the IPE base config option help text. + Use GFP_KERNEL for audit_log_start. + Remove unnecessary caching system. + Remove comments from headers + Use rcu_access_pointer for rcu-pointer null check + Remove usage of reqprot; use prot only. + Move policy load and activation audit event to 03/12 v4: + Remove sysctls in favor of securityfs nodes + Re-add kernel module parameters, as these are now exposed through securityfs. + Refactor property audit loop to a separate function. v5: + fix minor grammatical errors + do not group rule by curly-brace in audit record, reconstruct the exact rule. v6: + No changes v7: + Further split lsm creation into a separate commit from the evaluation loop and audit system, for easier review. + Propogating changes to support the new ipe_context structure in the evaluation loop. Introduced in v8: + Remove ipe_hook enumeration; hooks can be correlated via syscall record. --- security/ipe/Makefile | 1 + security/ipe/ctx.c| 59 +++- security/ipe/ctx.h| 6 ++ security/ipe/eval.c | 144 ++ security/ipe/eval.h | 24 + security/ipe/modules/ipe_module.h | 3 + security/ipe/policy.c | 27 ++ security/ipe/policy.h | 4 + 8 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 security/ipe/eval.c create mode 100644 security/ipe/eval.h diff --git a/security/ipe/Makefile b/security/ipe/Makefile index 9a97efd8a190..0db69f13e82a 100644 --- a/security/ipe/Makefile +++ b/security/ipe/Makefile @@ -9,6 +9,7 @@ ccflags-y := -I$(srctree)/security/ipe/modules obj-$(CONFIG_SECURITY_IPE) += \ ctx.o \ + eval.o \ hooks.o \ ipe.o \ modules.o \ diff --git a/security/ipe/ctx.c b/security/ipe/ctx.c index d51fe2e13ad9..97305ddc2ff7 100644 --- a/security/ipe/ctx.c +++ b/security/ipe/ctx.c @@ -5,6 +5,7 @@ #include "ipe.h" #include "ctx.h" +#include "policy.h" #include #include @@ -60,10 +61,25 @@ struct ipe_context *ipe_get_ctx_rcu(struct ipe_context __rcu *ctx) */ static void free_ctx_work(struct work_struct *const work) { + struct ipe_policy *p = NULL; struct ipe_context *ctx = NULL; ctx = container_of(work, struct ipe_context, free_work); + /* Make p->ctx no longer have any references */ + spin_lock(&ctx->lock); + list_for_each_entry(p, &ctx->policies, next) + rcu_assign_pointer(p->ctx, NULL); + spin_unlock(&ctx->lock); + synchronize_rcu(); + + /* +* locking no longer necessary - nothing can get a reference to ctx, +* so list is guaranteed stable. +*/ + list_for_each_entry(p, &ctx->policies, next) + ipe_put_policy(p); + kfree(ctx); } @@ -88,6 +104,7 @@ static struct ipe_context *create_ctx(void) } INIT_WORK(&ctx->free_work, free_ctx_work); + INIT_LIST_HEAD(&ctx->policies); refcount_set(&ctx->refcount, 1); spin_lock_init(&ctx->lock); @@ -98,9 +115,49 @@ static struct ipe_context *create_ctx(void) return ERR_PTR(rc); } +/** + * remove_policy: Remove a policy from its context + * @p: Supplies a pointer to a policy that will be removed from its context + * + * Decrements @p's reference by 1. + */ +void ipe_remove_policy(struct ipe_policy *p) +{ + struct ipe_context *ctx; + + ctx = ipe_get_ctx_rcu(p->ctx); + if (!ctx) + return; + + spin_lock(&ctx->lock); + list_del_init(&p->next); + rcu_assign_pointer(p->ctx, NULL); + spin_unlock(&ctx->lock); + synchronize_rcu(); + + ipe_put_ctx(ctx); + /* drop the reference representing the list */ + ipe_put_policy(p); +} + +/** + * ipe_add_policy: Associate @p with @ctx + * @ctx: Supplies a pointer to the ipe_context structure to associate @p with. + * @p: Supplies a pointer to the ipe_policy structure to associate. + */ +void ipe_add_policy(struct ipe_context *ctx, struct ipe_policy *p) +{ + spin_lock(&ctx->lock); + rcu_assign_pointer(p->ctx, ctx); + list_add_tail(&p->next, &ctx->policies); + refcount_inc(&p->refcount); + spin_unlock(&ctx->lock); + synchronize_rcu(); +} + /** * ipe_put_ctx: Decremen
[RFC PATCH v8 13/17] fsverity: consume builtin signature via LSM hook
From: Fan Wu fsverity represents a mechanism to support both integrity and authenticity protection of a file, supporting both signed and unsigned digests. An LSM which controls access to a resource based on authenticity and integrity of said resource, can then use this data to make an informed decision on the authorization (provided by the LSM's policy) of said claim. This effectively allows the extension of a policy enforcement layer in LSM for fsverity, allowing for more granular control of how a particular authenticity claim can be used. For example, "all (built-in) signed fsverity files should be allowed to execute, but only these hashes are allowed to be loaded as kernel modules". This enforcement must be done in kernel space, as a userspace only solution would fail a simple litmus test: Download a self-contained malicious binary that never touches the userspace stack. This binary would still be able to execute. Signed-off-by: Fan Wu Signed-off-by: Deven Bowers --- v1-v6: + Not present v7: Introduced v8: + Split fs/verity/ changes and security/ changes into separate patches + Change signature of fsverity_create_info to accept non-const inode + Change signature of fsverity_verify_signature to accept non-const inode + Don't cast-away const from inode. + Digest functionality dropped in favor of: ("fs-verity: define a function to return the integrity protected file digest") + Reworded commit description and title to match changes. + Fix a bug wherein no LSM implements the particular fsverity @name (or LSM is disabled), and returns -EOPNOTSUPP, causing errors. --- fs/verity/fsverity_private.h | 2 +- fs/verity/open.c | 13 - fs/verity/signature.c| 1 + include/linux/fsverity.h | 2 ++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h index 629785c95007..e0d70235bbdc 100644 --- a/fs/verity/fsverity_private.h +++ b/fs/verity/fsverity_private.h @@ -114,7 +114,7 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, unsigned int log_blocksize, const u8 *salt, size_t salt_size); -struct fsverity_info *fsverity_create_info(const struct inode *inode, +struct fsverity_info *fsverity_create_info(struct inode *inode, struct fsverity_descriptor *desc); void fsverity_set_info(struct inode *inode, struct fsverity_info *vi); diff --git a/fs/verity/open.c b/fs/verity/open.c index 81ff94442f7b..7e6fa52c0e9c 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -7,7 +7,9 @@ #include "fsverity_private.h" +#include #include +#include static struct kmem_cache *fsverity_info_cachep; @@ -146,7 +148,7 @@ static int compute_file_digest(struct fsverity_hash_alg *hash_alg, * appended signature), and check the signature if present. The * fsverity_descriptor must have already undergone basic validation. */ -struct fsverity_info *fsverity_create_info(const struct inode *inode, +struct fsverity_info *fsverity_create_info(struct inode *inode, struct fsverity_descriptor *desc) { struct fsverity_info *vi; @@ -182,6 +184,15 @@ struct fsverity_info *fsverity_create_info(const struct inode *inode, err = fsverity_verify_signature(vi, desc->signature, le32_to_cpu(desc->sig_size)); + if (err) { + fsverity_err(inode, "Error %d verifying signature", err); + goto out; + } + + err = security_inode_setsecurity(inode, FS_VERITY_INODE_SEC_NAME, desc->signature, +le32_to_cpu(desc->sig_size), 0); + if (err == -EOPNOTSUPP) + err = 0; out: if (err) { fsverity_free_info(vi); diff --git a/fs/verity/signature.c b/fs/verity/signature.c index 143a530a8008..5d7b9496f9c4 100644 --- a/fs/verity/signature.c +++ b/fs/verity/signature.c @@ -9,6 +9,7 @@ #include #include +#include #include #include diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 7af030fa3c36..f37936b56150 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -251,4 +251,6 @@ static inline bool fsverity_active(const struct inode *inode) return fsverity_get_info(inode) != NULL; } +#define FS_VERITY_INODE_SEC_NAME "fsverity.inode-info" + #endif /* _LINUX_FSVERITY_H */ -- 2.25.1 -- Linux-audit mailing list Linux-audit@redhat.com https://listman.redhat.com/mailman/listinfo/linux-audit
[RFC PATCH v8 07/17] ipe: add auditing support
Users of IPE require a way to identify when and why an operation fails, allowing them to both respond to violations of policy and be notified of potentially malicious actions on their systens with respect to IPE itself. The new 1420 audit, AUDIT_IPE_ACCESS indicates the result of a policy evaulation of a resource. The other two events, AUDIT_MAC_POLICY_LOAD, and AUDIT_MAC_CONFIG_CHANGE represent a new policy was loaded into the kernel and the currently active policy changed, respectively. This patch also adds support for success auditing, allowing users to identify how a resource passed policy. It is recommended to use this option with caution, as it is quite noisy. Signed-off-by: Deven Bowers --- This patch adds the following audit records: type=1420 audit(1653364735.161:64): rule="DEFAULT op=EXECUTE action=DENY" type=1420 audit(1653364370.067:61): path="/root/fs/rw/plain/execve" dev="vdc1" ino=16 rule="DEFAULT op=EXECUTE action=DENY" type=1405 audit(1653425583.136:54): policy_name="dmverity_roothash" policy_version=0.0.0 sha256=A9C5803309F80D2B84D7C047534BE8B60EF121C8E1F351F2A8EFFA617B7F0686 type=1403 audit(1653425529.927:53): policy_name="dmverity_roothash" policy_version=0.0.0 sha256=A9C5803309F80D2B84D7C047534BE8B60EF121C8E1F351F2A8EFFA617B7F0686 This results in the following events (the audit records are always prior to a SYSCALL record): type=1420 audit(1653364735.161:64): rule="DEFAULT op=EXECUTE action=DENY" type=1300 audit(1653364735.161:64): arch=c03e syscall=9 success=no exit=-13 a0=0 a1=1000 a2=4 a3=20 items=0 ppid=455 pid=774 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=ttyS0 ses=3 comm="mmap" exe="/root/host/mmap" subj=kernel key=(null) audit: type=1327 audit(1653364735.161:64): proctitle=686F73742F6D6D617000410058 type=1420 audit(1653364370.067:61): path="/root/fs/rw/plain/execve" dev="vdc1" ino=16 rule="DEFAULT op=EXECUTE action=DENY" type=1300 audit(1653364370.067:61): arch=c03e syscall=10 success=no exit=-13 a0=7f0bf0644000 a1=4f80 a2=5 a3=7f0bf043d300 items=0 ppid=455 pid=737 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=ttyS0 ses=3 comm="mprotect" exe="/root/host/mprotect" subj=kernel key=(null) type=1327 audit(1653364370.067:61): proctitle=686F73742F6D70726F7465637400534800527C5700527C5800706C61696E2F657865637665 type=1403 audit(1653425529.927:53): policy_name="dmverity_roothash" policy_version=0.0.0 sha256=A9C5803309F80D2B84D7C047534BE8B60EF121C8E1F351F2A8EFFA617B7F0686 type=1300 audit(1653425529.927:53): arch=c03e syscall=1 success=yes exit=6215 a0=1 a1=7f07adfe4000 a2=1847 a3=22 items=0 ppid=441 pid=445 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=) type=1327 audit(1653425529.927:53): proctitle=63617400706F6C69636965732F646D7665726974795F726F6F74686173682E706F6C2E703762 type=1405 audit(1653425583.136:54): policy_name="dmverity_roothash" policy_version=0.0.0 sha256=A9C5803309F80D2B84D7C047534BE8B60EF121C8E1F351F2A8EFFA617B7F0686 type=1300 audit(1653425583.136:54): arch=c03e syscall=1 success=yes exit=2 a0=1 a1=55c1065e5c60 a2=2 a3=7fe683990020 items=0 ppid=405 pid=441 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 e) type=1327 audit(1653425583.136:54): proctitle="-bash" --- v2: + Split evaluation loop, access control hooks, and evaluation loop from policy parser and userspace interface to pass mailing list character limit v3: + Move ipe_load_properties to patch 04. + Remove useless 0-initializations + Prefix extern variables with ipe_ + Remove kernel module parameters, as these are exposed through sysctls. + Add more prose to the IPE base config option help text. + Use GFP_KERNEL for audit_log_start. + Remove unnecessary caching system. + Remove comments from headers + Use rcu_access_pointer for rcu-pointer null check + Remove usage of reqprot; use prot only. + Move policy load and activation audit event to 03/12 v4: + Remove sysctls in favor of securityfs nodes + Re-add kernel module parameters, as these are now exposed through securityfs. + Refactor property audit loop to a separate function. v5: + fix minor grammatical errors + do not group rule by curly-brace in audit record, reconstruct the exact rule. v6: + No changes v7: + Further split lsm creation, the audit system, the evaluation loop, and access control hooks into separate patches. + Further split audit system patch into two separate patches; one for include/uapi, and the usage of the new defines. + Split out the permissive functionality into another separate patch, for easier review. + Correct misuse of audit_log_n_untrusted string to audit_log_format + Use get_task_comm instead of comm directly. + Quote certain audit values + Remove unnecessary help text on choice options - these were previously idented at the wrong level + Corre
Re: [RFC PATCH v8 00/17] Integrity Policy Enforcement LSM (IPE)
On Wed, Jun 08, 2022 at 12:01:12PM -0700, Deven Bowers wrote: > IPE is a Linux Security Module which takes a complimentary approach to Hello, IPE. You're looking exceptionally attractive today. Have you been working out? (maybe you meant "complementary"? ;-) -- Linux-audit mailing list Linux-audit@redhat.com https://listman.redhat.com/mailman/listinfo/linux-audit
Re: [RFC PATCH v8 00/17] Integrity Policy Enforcement LSM (IPE)
On Wed, Jun 08, 2022 at 08:10:58PM +0100, Matthew Wilcox wrote: > On Wed, Jun 08, 2022 at 12:01:12PM -0700, Deven Bowers wrote: > > IPE is a Linux Security Module which takes a complimentary approach to > > Hello, IPE. You're looking exceptionally attractive today. Have you > been working out? Not nearly as often as I'd like to :) > > (maybe you meant "complementary"? ;-) Yes, thanks. Sorry for the misspelling. -- Linux-audit mailing list Linux-audit@redhat.com https://listman.redhat.com/mailman/listinfo/linux-audit
Re: [RFC PATCH v8 10/17] block|security: add LSM blob to block_device
On 6/8/2022 12:01 PM, Deven Bowers wrote: block_device structures can have valuable security properties, based on how they are created, and what subsystem manages them. By adding LSM storage to this structure, this data can be accessed at the LSM layer. Signed-off-by: Deven Bowers Reviewed-by: Casey Schaufler Not everyone is going to appreciate the infrastructure allocation of the block_device security blob, but I do. --- v2: + No Changes v3: + Minor style changes from checkpatch --strict v4: + No Changes v5: + Allow multiple callers to call security_bdev_setsecurity v6: + Simplify security_bdev_setsecurity break condition v7: + Squash all dm-verity related patches to two patches, the additions to dm-verity/fs, and the consumption of the additions. v8: + Split dm-verity related patches squashed in v7 to 3 commits based on topic: + New LSM hook + Consumption of hook outside LSM + Consumption of hook inside LSM. + change return of security_bdev_alloc / security_bdev_setsecurity to LSM_RET_DEFAULT instead of 0. + Change return code to -EOPNOTSUPP, bring inline with other setsecurity hooks. --- block/bdev.c | 7 include/linux/blk_types.h | 1 + include/linux/lsm_hook_defs.h | 5 +++ include/linux/lsm_hooks.h | 12 ++ include/linux/security.h | 22 +++ security/security.c | 70 +++ 6 files changed, 117 insertions(+) diff --git a/block/bdev.c b/block/bdev.c index 5fe06c1f2def..e7ef2c7a22c9 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "../fs/internal.h" @@ -397,6 +398,11 @@ static struct inode *bdev_alloc_inode(struct super_block *sb) if (!ei) return NULL; memset(&ei->bdev, 0, sizeof(ei->bdev)); + + if (unlikely(security_bdev_alloc(&ei->bdev))) { + kmem_cache_free(bdev_cachep, ei); + return NULL; + } return &ei->vfs_inode; } @@ -406,6 +412,7 @@ static void bdev_free_inode(struct inode *inode) free_percpu(bdev->bd_stats); kfree(bdev->bd_meta_info); + security_bdev_free(bdev); if (!bdev_is_partition(bdev)) { if (bdev->bd_disk && bdev->bd_disk->bdi) diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index a24d4078fb21..a014ffa14b2d 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -68,6 +68,7 @@ struct block_device { #ifdef CONFIG_FAIL_MAKE_REQUEST boolbd_make_it_fail; #endif + void*security; } __randomize_layout; #define bdev_whole(_bdev) \ diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index eafa1d2489fd..3449c004bd84 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -407,3 +407,8 @@ LSM_HOOK(int, 0, perf_event_write, struct perf_event *event) LSM_HOOK(int, 0, uring_override_creds, const struct cred *new) LSM_HOOK(int, 0, uring_sqpoll, void) #endif /* CONFIG_IO_URING */ + +LSM_HOOK(int, 0, bdev_alloc_security, struct block_device *bdev) +LSM_HOOK(void, LSM_RET_VOID, bdev_free_security, struct block_device *bdev) +LSM_HOOK(int, 0, bdev_setsecurity, struct block_device *bdev, const char *name, +const void *value, size_t size) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 91c8146649f5..9f011d705ea8 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1550,6 +1550,17 @@ * * @what: kernel feature being accessed * + * @bdev_alloc_security: + * Initialize the security field inside a block_device structure. + * + * @bdev_free_security: + * Cleanup the security information stored inside a block_device structure. + * + * @bdev_setsecurity: + * Set a security property associated with @name for @bdev with + * value @value. @size indicates the size of @value in bytes. + * If a @name is not implemented, return -EOPNOTSUPP. + * * Security hooks for perf events * * @perf_event_open: @@ -1610,6 +1621,7 @@ struct lsm_blob_sizes { int lbs_ipc; int lbs_msg_msg; int lbs_task; + int lbs_bdev; }; /* diff --git a/include/linux/security.h b/include/linux/security.h index 7fc4e9f49f54..30b663de301f 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -473,6 +473,11 @@ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen); int security_locked_down(enum lockdown_reason what); +int security_bdev_alloc(struct block_device *bdev); +void security_bdev_free(struct block_device *bdev); +int security_bdev_setsecurity(