1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved. 4 */ 5 6 #include <linux/fs.h> 7 #include <linux/fs_struct.h> 8 #include <linux/types.h> 9 #include <linux/binfmts.h> 10 #include <linux/mman.h> 11 #include <linux/blk_types.h> 12 13 #include "ipe.h" 14 #include "hooks.h" 15 #include "eval.h" 16 #include "digest.h" 17 18 /** 19 * ipe_bprm_check_security() - ipe security hook function for bprm check. 20 * @bprm: Supplies a pointer to a linux_binprm structure to source the file 21 * being evaluated. 22 * 23 * This LSM hook is called when a binary is loaded through the exec 24 * family of system calls. 25 * 26 * Return: 27 * * %0 - Success 28 * * %-EACCES - Did not pass IPE policy 29 */ 30 int ipe_bprm_check_security(struct linux_binprm *bprm) 31 { 32 struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT; 33 34 ipe_build_eval_ctx(&ctx, bprm->file, IPE_OP_EXEC, IPE_HOOK_BPRM_CHECK); 35 return ipe_evaluate_event(&ctx); 36 } 37 38 /** 39 * ipe_bprm_creds_for_exec() - ipe security hook function for bprm creds check. 40 * @bprm: Supplies a pointer to a linux_binprm structure to source the file 41 * being evaluated. 42 * 43 * This LSM hook is called when userspace signals the kernel to check a file 44 * for execution through the execveat syscall with the AT_EXECVE_CHECK flag. 45 * The hook triggers IPE policy evaluation on the script file and returns 46 * the policy decision to userspace. The userspace program receives the 47 * return code and can decide whether to proceed with script execution. 48 * 49 * Return: 50 * * %0 - Success 51 * * %-EACCES - Did not pass IPE policy 52 */ 53 int ipe_bprm_creds_for_exec(struct linux_binprm *bprm) 54 { 55 struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT; 56 57 if (!bprm->is_check) 58 return 0; 59 60 ipe_build_eval_ctx(&ctx, bprm->file, IPE_OP_EXEC, 61 IPE_HOOK_BPRM_CREDS_FOR_EXEC); 62 return ipe_evaluate_event(&ctx); 63 } 64 65 /** 66 * ipe_mmap_file() - ipe security hook function for mmap check. 67 * @f: File being mmap'd. Can be NULL in the case of anonymous memory. 68 * @reqprot: The requested protection on the mmap, passed from usermode. 69 * @prot: The effective protection on the mmap, resolved from reqprot and 70 * system configuration. 71 * @flags: Unused. 72 * 73 * This hook is called when a file is loaded through the mmap 74 * family of system calls. 75 * 76 * Return: 77 * * %0 - Success 78 * * %-EACCES - Did not pass IPE policy 79 */ 80 int ipe_mmap_file(struct file *f, unsigned long reqprot __always_unused, 81 unsigned long prot, unsigned long flags) 82 { 83 struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT; 84 85 if (prot & PROT_EXEC) { 86 ipe_build_eval_ctx(&ctx, f, IPE_OP_EXEC, IPE_HOOK_MMAP); 87 return ipe_evaluate_event(&ctx); 88 } 89 90 return 0; 91 } 92 93 /** 94 * ipe_file_mprotect() - ipe security hook function for mprotect check. 95 * @vma: Existing virtual memory area created by mmap or similar. 96 * @reqprot: The requested protection on the mmap, passed from usermode. 97 * @prot: The effective protection on the mmap, resolved from reqprot and 98 * system configuration. 99 * 100 * This LSM hook is called when a mmap'd region of memory is changing 101 * its protections via mprotect. 102 * 103 * Return: 104 * * %0 - Success 105 * * %-EACCES - Did not pass IPE policy 106 */ 107 int ipe_file_mprotect(struct vm_area_struct *vma, 108 unsigned long reqprot __always_unused, 109 unsigned long prot) 110 { 111 struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT; 112 113 /* Already Executable */ 114 if (vma->vm_flags & VM_EXEC) 115 return 0; 116 117 if (prot & PROT_EXEC) { 118 ipe_build_eval_ctx(&ctx, vma->vm_file, IPE_OP_EXEC, IPE_HOOK_MPROTECT); 119 return ipe_evaluate_event(&ctx); 120 } 121 122 return 0; 123 } 124 125 /** 126 * ipe_kernel_read_file() - ipe security hook function for kernel read. 127 * @file: Supplies a pointer to the file structure being read in from disk. 128 * @id: Supplies the enumeration identifying the purpose of the read. 129 * @contents: Unused. 130 * 131 * This LSM hook is called when a file is read from disk in the kernel. 132 * 133 * Return: 134 * * %0 - Success 135 * * %-EACCES - Did not pass IPE policy 136 */ 137 int ipe_kernel_read_file(struct file *file, enum kernel_read_file_id id, 138 bool contents) 139 { 140 struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT; 141 enum ipe_op_type op; 142 143 switch (id) { 144 case READING_FIRMWARE: 145 op = IPE_OP_FIRMWARE; 146 break; 147 case READING_MODULE: 148 op = IPE_OP_KERNEL_MODULE; 149 break; 150 case READING_KEXEC_INITRAMFS: 151 op = IPE_OP_KEXEC_INITRAMFS; 152 break; 153 case READING_KEXEC_IMAGE: 154 op = IPE_OP_KEXEC_IMAGE; 155 break; 156 case READING_POLICY: 157 op = IPE_OP_POLICY; 158 break; 159 case READING_X509_CERTIFICATE: 160 op = IPE_OP_X509; 161 break; 162 default: 163 op = IPE_OP_INVALID; 164 WARN(1, "no rule setup for kernel_read_file enum %d", id); 165 } 166 167 ipe_build_eval_ctx(&ctx, file, op, IPE_HOOK_KERNEL_READ); 168 return ipe_evaluate_event(&ctx); 169 } 170 171 /** 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 loading 177 * into the kernel. 178 * 179 * Return: 180 * * %0 - Success 181 * * %-EACCES - Did not pass IPE policy 182 */ 183 int ipe_kernel_load_data(enum kernel_load_data_id id, bool contents) 184 { 185 struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT; 186 enum ipe_op_type op; 187 188 switch (id) { 189 case LOADING_FIRMWARE: 190 op = IPE_OP_FIRMWARE; 191 break; 192 case LOADING_MODULE: 193 op = IPE_OP_KERNEL_MODULE; 194 break; 195 case LOADING_KEXEC_INITRAMFS: 196 op = IPE_OP_KEXEC_INITRAMFS; 197 break; 198 case LOADING_KEXEC_IMAGE: 199 op = IPE_OP_KEXEC_IMAGE; 200 break; 201 case LOADING_POLICY: 202 op = IPE_OP_POLICY; 203 break; 204 case LOADING_X509_CERTIFICATE: 205 op = IPE_OP_X509; 206 break; 207 default: 208 op = IPE_OP_INVALID; 209 WARN(1, "no rule setup for kernel_load_data enum %d", id); 210 } 211 212 ipe_build_eval_ctx(&ctx, NULL, op, IPE_HOOK_KERNEL_LOAD); 213 return ipe_evaluate_event(&ctx); 214 } 215 216 /** 217 * ipe_unpack_initramfs() - Mark the current rootfs as initramfs. 218 */ 219 void ipe_unpack_initramfs(void) 220 { 221 ipe_sb(current->fs->root.mnt->mnt_sb)->initramfs = true; 222 } 223 224 #ifdef CONFIG_IPE_PROP_DM_VERITY 225 /** 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 structure 228 * to free. 229 */ 230 void ipe_bdev_free_security(struct block_device *bdev) 231 { 232 struct ipe_bdev *blob = ipe_bdev(bdev); 233 234 ipe_digest_free(blob->root_hash); 235 } 236 237 #ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE 238 static void ipe_set_dmverity_signature(struct ipe_bdev *blob, 239 const void *value, 240 size_t size) 241 { 242 blob->dm_verity_signed = size > 0 && value; 243 } 244 #else 245 static inline void ipe_set_dmverity_signature(struct ipe_bdev *blob, 246 const void *value, 247 size_t size) 248 { 249 } 250 #endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */ 251 252 /** 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 existence 260 * 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 the 263 * -errno. 264 */ 265 int ipe_bdev_setintegrity(struct block_device *bdev, enum lsm_integrity_type type, 266 const void *value, size_t size) 267 { 268 const struct dm_verity_digest *digest = NULL; 269 struct ipe_bdev *blob = ipe_bdev(bdev); 270 struct digest_info *info = NULL; 271 272 if (type == LSM_INT_DMVERITY_SIG_VALID) { 273 ipe_set_dmverity_signature(blob, value, size); 274 275 return 0; 276 } 277 278 if (type != LSM_INT_DMVERITY_ROOTHASH) 279 return -EINVAL; 280 281 if (!value) { 282 ipe_digest_free(blob->root_hash); 283 blob->root_hash = NULL; 284 285 return 0; 286 } 287 digest = value; 288 289 info = kzalloc(sizeof(*info), GFP_KERNEL); 290 if (!info) 291 return -ENOMEM; 292 293 info->digest = kmemdup(digest->digest, digest->digest_len, GFP_KERNEL); 294 if (!info->digest) 295 goto err; 296 297 info->alg = kstrdup(digest->alg, GFP_KERNEL); 298 if (!info->alg) 299 goto err; 300 301 info->digest_len = digest->digest_len; 302 303 ipe_digest_free(blob->root_hash); 304 blob->root_hash = info; 305 306 return 0; 307 err: 308 ipe_digest_free(info); 309 310 return -ENOMEM; 311 } 312 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 313 314 #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 315 /** 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-verity 323 * builtin signature into LSM blob. 324 * 325 * Return: %0 on success. If an error occurs, the function will return the 326 * -errno. 327 */ 328 int ipe_inode_setintegrity(const struct inode *inode, 329 enum lsm_integrity_type type, 330 const void *value, size_t size) 331 { 332 struct ipe_inode *inode_sec = ipe_inode(inode); 333 334 if (type == LSM_INT_FSVERITY_BUILTINSIG_VALID) { 335 inode_sec->fs_verity_signed = size > 0 && value; 336 return 0; 337 } 338 339 return -EINVAL; 340 } 341 #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 342