// SPDX-License-Identifier: GPL-2.01/*2* Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.3*/45#include <linux/fs.h>6#include <linux/fs_struct.h>7#include <linux/types.h>8#include <linux/binfmts.h>9#include <linux/mman.h>10#include <linux/blk_types.h>1112#include "ipe.h"13#include "hooks.h"14#include "eval.h"15#include "digest.h"1617/**18* ipe_bprm_check_security() - ipe security hook function for bprm check.19* @bprm: Supplies a pointer to a linux_binprm structure to source the file20* being evaluated.21*22* This LSM hook is called when a binary is loaded through the exec23* family of system calls.24*25* Return:26* * %0 - Success27* * %-EACCES - Did not pass IPE policy28*/29int ipe_bprm_check_security(struct linux_binprm *bprm)30{31struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;3233ipe_build_eval_ctx(&ctx, bprm->file, IPE_OP_EXEC, IPE_HOOK_BPRM_CHECK);34return ipe_evaluate_event(&ctx);35}3637/**38* ipe_bprm_creds_for_exec() - ipe security hook function for bprm creds check.39* @bprm: Supplies a pointer to a linux_binprm structure to source the file40* being evaluated.41*42* This LSM hook is called when userspace signals the kernel to check a file43* for execution through the execveat syscall with the AT_EXECVE_CHECK flag.44* The hook triggers IPE policy evaluation on the script file and returns45* the policy decision to userspace. The userspace program receives the46* return code and can decide whether to proceed with script execution.47*48* Return:49* * %0 - Success50* * %-EACCES - Did not pass IPE policy51*/52int ipe_bprm_creds_for_exec(struct linux_binprm *bprm)53{54struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;5556if (!bprm->is_check)57return 0;5859ipe_build_eval_ctx(&ctx, bprm->file, IPE_OP_EXEC,60IPE_HOOK_BPRM_CREDS_FOR_EXEC);61return ipe_evaluate_event(&ctx);62}6364/**65* ipe_mmap_file() - ipe security hook function for mmap check.66* @f: File being mmap'd. Can be NULL in the case of anonymous memory.67* @reqprot: The requested protection on the mmap, passed from usermode.68* @prot: The effective protection on the mmap, resolved from reqprot and69* system configuration.70* @flags: Unused.71*72* This hook is called when a file is loaded through the mmap73* family of system calls.74*75* Return:76* * %0 - Success77* * %-EACCES - Did not pass IPE policy78*/79int ipe_mmap_file(struct file *f, unsigned long reqprot __always_unused,80unsigned long prot, unsigned long flags)81{82struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;8384if (prot & PROT_EXEC) {85ipe_build_eval_ctx(&ctx, f, IPE_OP_EXEC, IPE_HOOK_MMAP);86return ipe_evaluate_event(&ctx);87}8889return 0;90}9192/**93* ipe_file_mprotect() - ipe security hook function for mprotect check.94* @vma: Existing virtual memory area created by mmap or similar.95* @reqprot: The requested protection on the mmap, passed from usermode.96* @prot: The effective protection on the mmap, resolved from reqprot and97* system configuration.98*99* This LSM hook is called when a mmap'd region of memory is changing100* its protections via mprotect.101*102* Return:103* * %0 - Success104* * %-EACCES - Did not pass IPE policy105*/106int ipe_file_mprotect(struct vm_area_struct *vma,107unsigned long reqprot __always_unused,108unsigned long prot)109{110struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;111112/* Already Executable */113if (vma->vm_flags & VM_EXEC)114return 0;115116if (prot & PROT_EXEC) {117ipe_build_eval_ctx(&ctx, vma->vm_file, IPE_OP_EXEC, IPE_HOOK_MPROTECT);118return ipe_evaluate_event(&ctx);119}120121return 0;122}123124/**125* ipe_kernel_read_file() - ipe security hook function for kernel read.126* @file: Supplies a pointer to the file structure being read in from disk.127* @id: Supplies the enumeration identifying the purpose of the read.128* @contents: Unused.129*130* This LSM hook is called when a file is read from disk in the kernel.131*132* Return:133* * %0 - Success134* * %-EACCES - Did not pass IPE policy135*/136int ipe_kernel_read_file(struct file *file, enum kernel_read_file_id id,137bool contents)138{139struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;140enum ipe_op_type op;141142switch (id) {143case READING_FIRMWARE:144op = IPE_OP_FIRMWARE;145break;146case READING_MODULE:147case READING_MODULE_COMPRESSED:148op = IPE_OP_KERNEL_MODULE;149break;150case READING_KEXEC_INITRAMFS:151op = IPE_OP_KEXEC_INITRAMFS;152break;153case READING_KEXEC_IMAGE:154op = IPE_OP_KEXEC_IMAGE;155break;156case READING_POLICY:157op = IPE_OP_POLICY;158break;159case READING_X509_CERTIFICATE:160op = IPE_OP_X509;161break;162default:163op = IPE_OP_INVALID;164WARN(1, "no rule setup for kernel_read_file enum %d", id);165}166167ipe_build_eval_ctx(&ctx, file, op, IPE_HOOK_KERNEL_READ);168return ipe_evaluate_event(&ctx);169}170171/**172* ipe_kernel_load_data() - ipe security hook function for kernel load data.173* @id: Supplies the enumeration identifying the purpose of the load.174* @contents: Unused.175*176* This LSM hook is called when a data buffer provided by userspace is loading177* into the kernel.178*179* Return:180* * %0 - Success181* * %-EACCES - Did not pass IPE policy182*/183int ipe_kernel_load_data(enum kernel_load_data_id id, bool contents)184{185struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;186enum ipe_op_type op;187188switch (id) {189case LOADING_FIRMWARE:190op = IPE_OP_FIRMWARE;191break;192case LOADING_MODULE:193op = IPE_OP_KERNEL_MODULE;194break;195case LOADING_KEXEC_INITRAMFS:196op = IPE_OP_KEXEC_INITRAMFS;197break;198case LOADING_KEXEC_IMAGE:199op = IPE_OP_KEXEC_IMAGE;200break;201case LOADING_POLICY:202op = IPE_OP_POLICY;203break;204case LOADING_X509_CERTIFICATE:205op = IPE_OP_X509;206break;207default:208op = IPE_OP_INVALID;209WARN(1, "no rule setup for kernel_load_data enum %d", id);210}211212ipe_build_eval_ctx(&ctx, NULL, op, IPE_HOOK_KERNEL_LOAD);213return ipe_evaluate_event(&ctx);214}215216/**217* ipe_unpack_initramfs() - Mark the current rootfs as initramfs.218*/219void ipe_unpack_initramfs(void)220{221ipe_sb(current->fs->root.mnt->mnt_sb)->initramfs = true;222}223224#ifdef CONFIG_IPE_PROP_DM_VERITY225/**226* ipe_bdev_free_security() - Free IPE's LSM blob of block_devices.227* @bdev: Supplies a pointer to a block_device that contains the structure228* to free.229*/230void ipe_bdev_free_security(struct block_device *bdev)231{232struct ipe_bdev *blob = ipe_bdev(bdev);233234ipe_digest_free(blob->root_hash);235}236237#ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE238static void ipe_set_dmverity_signature(struct ipe_bdev *blob,239const void *value,240size_t size)241{242blob->dm_verity_signed = size > 0 && value;243}244#else245static inline void ipe_set_dmverity_signature(struct ipe_bdev *blob,246const void *value,247size_t size)248{249}250#endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */251252/**253* ipe_bdev_setintegrity() - Save integrity data from a bdev to IPE's LSM blob.254* @bdev: Supplies a pointer to a block_device that contains the LSM blob.255* @type: Supplies the integrity type.256* @value: Supplies the value to store.257* @size: The size of @value.258*259* This hook is currently used to save dm-verity's root hash or the existence260* of a validated signed dm-verity root hash into LSM blob.261*262* Return: %0 on success. If an error occurs, the function will return the263* -errno.264*/265int ipe_bdev_setintegrity(struct block_device *bdev, enum lsm_integrity_type type,266const void *value, size_t size)267{268const struct dm_verity_digest *digest = NULL;269struct ipe_bdev *blob = ipe_bdev(bdev);270struct digest_info *info = NULL;271272if (type == LSM_INT_DMVERITY_SIG_VALID) {273ipe_set_dmverity_signature(blob, value, size);274275return 0;276}277278if (type != LSM_INT_DMVERITY_ROOTHASH)279return -EINVAL;280281if (!value) {282ipe_digest_free(blob->root_hash);283blob->root_hash = NULL;284285return 0;286}287digest = value;288289info = kzalloc(sizeof(*info), GFP_KERNEL);290if (!info)291return -ENOMEM;292293info->digest = kmemdup(digest->digest, digest->digest_len, GFP_KERNEL);294if (!info->digest)295goto err;296297info->alg = kstrdup(digest->alg, GFP_KERNEL);298if (!info->alg)299goto err;300301info->digest_len = digest->digest_len;302303ipe_digest_free(blob->root_hash);304blob->root_hash = info;305306return 0;307err:308ipe_digest_free(info);309310return -ENOMEM;311}312#endif /* CONFIG_IPE_PROP_DM_VERITY */313314#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG315/**316* ipe_inode_setintegrity() - save integrity data from a inode to IPE's LSM blob.317* @inode: The inode to source the security blob from.318* @type: Supplies the integrity type.319* @value: The value to be stored.320* @size: The size of @value.321*322* This hook is currently used to save the existence of a validated fs-verity323* builtin signature into LSM blob.324*325* Return: %0 on success. If an error occurs, the function will return the326* -errno.327*/328int ipe_inode_setintegrity(const struct inode *inode,329enum lsm_integrity_type type,330const void *value, size_t size)331{332struct ipe_inode *inode_sec = ipe_inode(inode);333334if (type == LSM_INT_FSVERITY_BUILTINSIG_VALID) {335inode_sec->fs_verity_signed = size > 0 && value;336return 0;337}338339return -EINVAL;340}341#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */342343344