Message ID | 1687986571-16823-5-git-send-email-wufan@linux.microsoft.com (mailing list archive) |
---|---|
State | Not Applicable |
Headers | show |
Series | Integrity Policy Enforcement LSM (IPE) | expand |
On Jun 28, 2023 Fan Wu <wufan@linux.microsoft.com> wrote: > > 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 <deven.desai@linux.microsoft.com> > Signed-off-by: Fan Wu <wufan@linux.microsoft.com> > --- > security/ipe/eval.c | 14 ++++ > security/ipe/eval.h | 1 + > security/ipe/hooks.c | 182 +++++++++++++++++++++++++++++++++++++++++++ > security/ipe/hooks.h | 25 ++++++ > security/ipe/ipe.c | 6 ++ > 5 files changed, 228 insertions(+) > create mode 100644 security/ipe/hooks.c > create mode 100644 security/ipe/hooks.h Adding the 'hooks.h' header allows for much of code added in the previous patches to finally compile and there are a number of errors, too many to include here. Please fix those and ensure that each point in the patchset compiles cleanly. > diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c > new file mode 100644 > index 000000000000..d896a5a474bc > --- /dev/null > +++ b/security/ipe/hooks.c > @@ -0,0 +1,182 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) Microsoft Corporation. All rights reserved. > + */ > + > +#include <linux/fs.h> > +#include <linux/types.h> > +#include <linux/binfmts.h> > +#include <linux/mman.h> > + > +#include "ipe.h" > +#include "hooks.h" > +#include "eval.h" > + > +/** > + * ipe_bprm_check_security - ipe security hook function for bprm check. > + * @bprm: Supplies a pointer to a linux_binprm structure to source the file > + * being evaluated. > + * > + * This LSM hook is called when a binary is loaded through the exec > + * family of system calls. > + * Return: > + * *0 - OK > + * *!0 - Error > + */ > +int ipe_bprm_check_security(struct linux_binprm *bprm) > +{ > + struct ipe_eval_ctx ctx = { 0 }; It's up to you, but when you have a fequently used initializer like this it is often wrapped in a macro: #define IPE_EVAL_CTX_INIT ((struct ipe_eval_ctx){ 0 }) ... so that you can write the variable decalaration like this: struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT; It's not a requirement, it just tends to look a little cleaner and should you ever need to change the initializer it makes your life a lot easier. > + build_eval_ctx(&ctx, bprm->file, __IPE_OP_EXEC); > + return ipe_evaluate_event(&ctx); > +} > + > +/** > + * ipe_mmap_file - ipe security hook function for mmap check. > + * @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. > + * > + * This hook is called when a file is loaded through the mmap > + * family of system calls. > + * > + * Return: > + * * 0 - OK > + * * !0 - Error > + */ > +int ipe_mmap_file(struct file *f, unsigned long reqprot, unsigned long prot, > + unsigned long flags) Since @reqprot is always going to be unused in this function, you might want to mark it as such to help prevent compiler warnings/errors, for example: unsigned long reqprot __always_unused > +{ > + struct ipe_eval_ctx ctx = { 0 }; > + > + if (prot & PROT_EXEC) { > + build_eval_ctx(&ctx, f, __IPE_OP_EXEC); > + return ipe_evaluate_event(&ctx); > + } > + > + return 0; > +} > + > +/** > + * ipe_file_mprotect - ipe security hook function for mprotect check. > + * @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. > + * > + * This LSM hook is called when a mmap'd region of memory is changing > + * its protections via mprotect. > + * > + * Return: > + * * 0 - OK > + * * !0 - Error > + */ > +int ipe_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, See my comment above about @reqprot. > + unsigned long prot) > +{ > + struct ipe_eval_ctx ctx = { 0 }; > + > + /* Already Executable */ > + if (vma->vm_flags & VM_EXEC) > + return 0; > + > + if (prot & PROT_EXEC) { > + build_eval_ctx(&ctx, vma->vm_file, __IPE_OP_EXEC); > + return ipe_evaluate_event(&ctx); > + } > + > + return 0; > +} -- paul-moore.com
On Sat, Jul 08, 2023 at 12:23:02AM -0400, Paul Moore wrote: > On Jun 28, 2023 Fan Wu <wufan@linux.microsoft.com> wrote: > > > > 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 <deven.desai@linux.microsoft.com> > > Signed-off-by: Fan Wu <wufan@linux.microsoft.com> > > --- > > security/ipe/eval.c | 14 ++++ > > security/ipe/eval.h | 1 + > > security/ipe/hooks.c | 182 +++++++++++++++++++++++++++++++++++++++++++ > > security/ipe/hooks.h | 25 ++++++ > > security/ipe/ipe.c | 6 ++ > > 5 files changed, 228 insertions(+) > > create mode 100644 security/ipe/hooks.c > > create mode 100644 security/ipe/hooks.h > > Adding the 'hooks.h' header allows for much of code added in the > previous patches to finally compile and there are a number of errors, > too many to include here. Please fix those and ensure that each > point in the patchset compiles cleanly. > Sorry again for the mistake I made here. > > diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c > > new file mode 100644 > > index 000000000000..d896a5a474bc > > --- /dev/null > > +++ b/security/ipe/hooks.c > > @@ -0,0 +1,182 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (C) Microsoft Corporation. All rights reserved. > > + */ > > + > > +#include <linux/fs.h> > > +#include <linux/types.h> > > +#include <linux/binfmts.h> > > +#include <linux/mman.h> > > + > > +#include "ipe.h" > > +#include "hooks.h" > > +#include "eval.h" > > + > > +/** > > + * ipe_bprm_check_security - ipe security hook function for bprm check. > > + * @bprm: Supplies a pointer to a linux_binprm structure to source the file > > + * being evaluated. > > + * > > + * This LSM hook is called when a binary is loaded through the exec > > + * family of system calls. > > + * Return: > > + * *0 - OK > > + * *!0 - Error > > + */ > > +int ipe_bprm_check_security(struct linux_binprm *bprm) > > +{ > > + struct ipe_eval_ctx ctx = { 0 }; > > It's up to you, but when you have a fequently used initializer like > this it is often wrapped in a macro: > > #define IPE_EVAL_CTX_INIT ((struct ipe_eval_ctx){ 0 }) > > ... so that you can write the variable decalaration like this: > > struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT; > > It's not a requirement, it just tends to look a little cleaner and > should you ever need to change the initializer it makes your life > a lot easier. > Yes I agree this looks way better, I will update all the context init. > > + build_eval_ctx(&ctx, bprm->file, __IPE_OP_EXEC); > > + return ipe_evaluate_event(&ctx); > > +} > > + > > +/** > > + * ipe_mmap_file - ipe security hook function for mmap check. > > + * @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. > > + * > > + * This hook is called when a file is loaded through the mmap > > + * family of system calls. > > + * > > + * Return: > > + * * 0 - OK > > + * * !0 - Error > > + */ > > +int ipe_mmap_file(struct file *f, unsigned long reqprot, unsigned long prot, > > + unsigned long flags) > > Since @reqprot is always going to be unused in this function, you > might want to mark it as such to help prevent compiler > warnings/errors, for example: > > unsigned long reqprot __always_unused > Thanks for telling me this useful mark! I will add it. -Fan > > +{ > > + struct ipe_eval_ctx ctx = { 0 }; > > + > > + if (prot & PROT_EXEC) { > > + build_eval_ctx(&ctx, f, __IPE_OP_EXEC); > > + return ipe_evaluate_event(&ctx); > > + } > > + > > + return 0; > > +} > > + > > +/** > > + * ipe_file_mprotect - ipe security hook function for mprotect check. > > + * @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. > > + * > > + * This LSM hook is called when a mmap'd region of memory is changing > > + * its protections via mprotect. > > + * > > + * Return: > > + * * 0 - OK > > + * * !0 - Error > > + */ > > +int ipe_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, > > See my comment above about @reqprot. > > > + unsigned long prot) > > +{ > > + struct ipe_eval_ctx ctx = { 0 }; > > + > > + /* Already Executable */ > > + if (vma->vm_flags & VM_EXEC) > > + return 0; > > + > > + if (prot & PROT_EXEC) { > > + build_eval_ctx(&ctx, vma->vm_file, __IPE_OP_EXEC); > > + return ipe_evaluate_event(&ctx); > > + } > > + > > + return 0; > > +} > > -- > paul-moore.com
diff --git a/security/ipe/eval.c b/security/ipe/eval.c index 59144b2ecdda..8d0ec7c80f8f 100644 --- a/security/ipe/eval.c +++ b/security/ipe/eval.c @@ -17,6 +17,20 @@ struct ipe_policy __rcu *ipe_active_policy; +/** + * build_eval_ctx - Build an evaluation context. + * @ctx: Supplies a pointer to the context to be populdated. + * @file: Supplies a pointer to the file to associated with the evaluation. + * @op: Supplies the IPE policy operation associated with the evaluation. + */ +void build_eval_ctx(struct ipe_eval_ctx *ctx, + const struct file *file, + enum ipe_op_type op) +{ + ctx->file = file; + ctx->op = op; +} + /** * evaluate_property - Analyze @ctx against a property. * @ctx: Supplies a pointer to the context to be evaluated. diff --git a/security/ipe/eval.h b/security/ipe/eval.h index 972580dfec15..5abb845d5c4e 100644 --- a/security/ipe/eval.h +++ b/security/ipe/eval.h @@ -20,6 +20,7 @@ struct ipe_eval_ctx { const struct file *file; }; +void build_eval_ctx(struct ipe_eval_ctx *ctx, const struct file *file, enum ipe_op_type op); int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx); #endif /* _IPE_EVAL_H */ diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c new file mode 100644 index 000000000000..d896a5a474bc --- /dev/null +++ b/security/ipe/hooks.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Microsoft Corporation. All rights reserved. + */ + +#include <linux/fs.h> +#include <linux/types.h> +#include <linux/binfmts.h> +#include <linux/mman.h> + +#include "ipe.h" +#include "hooks.h" +#include "eval.h" + +/** + * ipe_bprm_check_security - ipe security hook function for bprm check. + * @bprm: Supplies a pointer to a linux_binprm structure to source the file + * being evaluated. + * + * This LSM hook is called when a binary is loaded through the exec + * family of system calls. + * Return: + * *0 - OK + * *!0 - Error + */ +int ipe_bprm_check_security(struct linux_binprm *bprm) +{ + struct ipe_eval_ctx ctx = { 0 }; + + build_eval_ctx(&ctx, bprm->file, __IPE_OP_EXEC); + return ipe_evaluate_event(&ctx); +} + +/** + * ipe_mmap_file - ipe security hook function for mmap check. + * @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. + * + * This hook is called when a file is loaded through the mmap + * family of system calls. + * + * Return: + * * 0 - OK + * * !0 - Error + */ +int ipe_mmap_file(struct file *f, unsigned long reqprot, unsigned long prot, + unsigned long flags) +{ + struct ipe_eval_ctx ctx = { 0 }; + + if (prot & PROT_EXEC) { + build_eval_ctx(&ctx, f, __IPE_OP_EXEC); + return ipe_evaluate_event(&ctx); + } + + return 0; +} + +/** + * ipe_file_mprotect - ipe security hook function for mprotect check. + * @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. + * + * This LSM hook is called when a mmap'd region of memory is changing + * its protections via mprotect. + * + * Return: + * * 0 - OK + * * !0 - Error + */ +int ipe_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, + unsigned long prot) +{ + struct ipe_eval_ctx ctx = { 0 }; + + /* Already Executable */ + if (vma->vm_flags & VM_EXEC) + return 0; + + if (prot & PROT_EXEC) { + build_eval_ctx(&ctx, vma->vm_file, __IPE_OP_EXEC); + return ipe_evaluate_event(&ctx); + } + + return 0; +} + +/** + * ipe_kernel_read_file - ipe security hook function for kernel read. + * @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. + * + * This LSM hook is called when a file is being read in from disk from + * the kernel. + * + * Return: + * 0 - OK + * !0 - Error + */ +int ipe_kernel_read_file(struct file *file, enum kernel_read_file_id id, + bool contents) +{ + enum ipe_op_type op; + struct ipe_eval_ctx ctx; + + switch (id) { + case READING_FIRMWARE: + op = __IPE_OP_FIRMWARE; + break; + case READING_MODULE: + op = __IPE_OP_KERNEL_MODULE; + break; + case READING_KEXEC_INITRAMFS: + op = __IPE_OP_KEXEC_INITRAMFS; + break; + case READING_KEXEC_IMAGE: + op = __IPE_OP_KEXEC_IMAGE; + break; + case READING_POLICY: + op = __IPE_OP_IMA_POLICY; + break; + case READING_X509_CERTIFICATE: + op = __IPE_OP_IMA_X509; + break; + default: + op = __IPE_OP_INVALID; + WARN(op == __IPE_OP_INVALID, "no rule setup for enum %d", id); + } + + build_eval_ctx(&ctx, file, op); + return ipe_evaluate_event(&ctx); +} + +/** + * ipe_kernel_load_data - ipe security hook function for kernel load data. + * @id: Supplies the enumeration identifying the purpose of the read. + * @contents: Unused. + * + * This LSM hook is called when a buffer is being read in from disk. + * + * Return: + * * 0 - OK + * * !0 - Error + */ +int ipe_kernel_load_data(enum kernel_load_data_id id, bool contents) +{ + enum ipe_op_type op; + struct ipe_eval_ctx ctx = { 0 }; + + switch (id) { + case LOADING_FIRMWARE: + op = __IPE_OP_FIRMWARE; + break; + case LOADING_MODULE: + op = __IPE_OP_KERNEL_MODULE; + break; + case LOADING_KEXEC_INITRAMFS: + op = __IPE_OP_KEXEC_INITRAMFS; + break; + case LOADING_KEXEC_IMAGE: + op = __IPE_OP_KEXEC_IMAGE; + break; + case LOADING_POLICY: + op = __IPE_OP_IMA_POLICY; + break; + case LOADING_X509_CERTIFICATE: + op = __IPE_OP_IMA_X509; + break; + default: + op = __IPE_OP_INVALID; + WARN(op == __IPE_OP_INVALID, "no rule setup for enum %d", id); + } + + build_eval_ctx(&ctx, NULL, op); + return ipe_evaluate_event(&ctx); +} diff --git a/security/ipe/hooks.h b/security/ipe/hooks.h new file mode 100644 index 000000000000..23205452f758 --- /dev/null +++ b/security/ipe/hooks.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Microsoft Corporation. All rights reserved. + */ +#ifndef _IPE_HOOKS_H +#define _IPE_HOOKS_H + +#include <linux/fs.h> +#include <linux/binfmts.h> +#include <linux/security.h> + +int ipe_bprm_check_security(struct linux_binprm *bprm); + +int ipe_mmap_file(struct file *f, unsigned long reqprot, unsigned long prot, + unsigned long flags); + +int ipe_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, + unsigned long prot); + +int ipe_kernel_read_file(struct file *file, enum kernel_read_file_id id, + bool contents); + +int ipe_kernel_load_data(enum kernel_load_data_id id, bool contents); + +#endif /* _IPE_HOOKS_H */ diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c index 2ee0f5de29d7..29bedc0b2ad6 100644 --- a/security/ipe/ipe.c +++ b/security/ipe/ipe.c @@ -4,11 +4,17 @@ */ #include "ipe.h" +#include "hooks.h" static struct lsm_blob_sizes ipe_blobs __ro_after_init = { }; static struct security_hook_list ipe_hooks[] __ro_after_init = { + LSM_HOOK_INIT(bprm_check_security, ipe_bprm_check_security), + LSM_HOOK_INIT(mmap_file, ipe_mmap_file), + LSM_HOOK_INIT(file_mprotect, ipe_file_mprotect), + LSM_HOOK_INIT(kernel_read_file, ipe_kernel_read_file), + LSM_HOOK_INIT(kernel_load_data, ipe_kernel_load_data), }; /**