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 case READING_MODULE_COMPRESSED: 149 op = IPE_OP_KERNEL_MODULE; 150 break; 151 case READING_KEXEC_INITRAMFS: 152 op = IPE_OP_KEXEC_INITRAMFS; 153 break; 154 case READING_KEXEC_IMAGE: 155 op = IPE_OP_KEXEC_IMAGE; 156 break; 157 case READING_POLICY: 158 op = IPE_OP_POLICY; 159 break; 160 case READING_X509_CERTIFICATE: 161 op = IPE_OP_X509; 162 break; 163 default: 164 op = IPE_OP_INVALID; 165 WARN(1, "no rule setup for kernel_read_file enum %d", id); 166 } 167 168 ipe_build_eval_ctx(&ctx, file, op, IPE_HOOK_KERNEL_READ); 169 return ipe_evaluate_event(&ctx); 170 } 171 172 /** 173 * ipe_kernel_load_data() - ipe security hook function for kernel load data. 174 * @id: Supplies the enumeration identifying the purpose of the load. 175 * @contents: Unused. 176 * 177 * This LSM hook is called when a data buffer provided by userspace is loading 178 * into the kernel. 179 * 180 * Return: 181 * * %0 - Success 182 * * %-EACCES - Did not pass IPE policy 183 */ 184 int ipe_kernel_load_data(enum kernel_load_data_id id, bool contents) 185 { 186 struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT; 187 enum ipe_op_type op; 188 189 switch (id) { 190 case LOADING_FIRMWARE: 191 op = IPE_OP_FIRMWARE; 192 break; 193 case LOADING_MODULE: 194 op = IPE_OP_KERNEL_MODULE; 195 break; 196 case LOADING_KEXEC_INITRAMFS: 197 op = IPE_OP_KEXEC_INITRAMFS; 198 break; 199 case LOADING_KEXEC_IMAGE: 200 op = IPE_OP_KEXEC_IMAGE; 201 break; 202 case LOADING_POLICY: 203 op = IPE_OP_POLICY; 204 break; 205 case LOADING_X509_CERTIFICATE: 206 op = IPE_OP_X509; 207 break; 208 default: 209 op = IPE_OP_INVALID; 210 WARN(1, "no rule setup for kernel_load_data enum %d", id); 211 } 212 213 ipe_build_eval_ctx(&ctx, NULL, op, IPE_HOOK_KERNEL_LOAD); 214 return ipe_evaluate_event(&ctx); 215 } 216 217 /** 218 * ipe_unpack_initramfs() - Mark the current rootfs as initramfs. 219 */ 220 void ipe_unpack_initramfs(void) 221 { 222 ipe_sb(current->fs->root.mnt->mnt_sb)->initramfs = true; 223 } 224 225 #ifdef CONFIG_IPE_PROP_DM_VERITY 226 /** 227 * ipe_bdev_free_security() - Free IPE's LSM blob of block_devices. 228 * @bdev: Supplies a pointer to a block_device that contains the structure 229 * to free. 230 */ 231 void ipe_bdev_free_security(struct block_device *bdev) 232 { 233 struct ipe_bdev *blob = ipe_bdev(bdev); 234 235 ipe_digest_free(blob->root_hash); 236 } 237 238 #ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE 239 static void ipe_set_dmverity_signature(struct ipe_bdev *blob, 240 const void *value, 241 size_t size) 242 { 243 blob->dm_verity_signed = size > 0 && value; 244 } 245 #else 246 static inline void ipe_set_dmverity_signature(struct ipe_bdev *blob, 247 const void *value, 248 size_t size) 249 { 250 } 251 #endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */ 252 253 /** 254 * ipe_bdev_setintegrity() - Save integrity data from a bdev to IPE's LSM blob. 255 * @bdev: Supplies a pointer to a block_device that contains the LSM blob. 256 * @type: Supplies the integrity type. 257 * @value: Supplies the value to store. 258 * @size: The size of @value. 259 * 260 * This hook is currently used to save dm-verity's root hash or the existence 261 * of a validated signed dm-verity root hash into LSM blob. 262 * 263 * Return: %0 on success. If an error occurs, the function will return the 264 * -errno. 265 */ 266 int ipe_bdev_setintegrity(struct block_device *bdev, enum lsm_integrity_type type, 267 const void *value, size_t size) 268 { 269 const struct dm_verity_digest *digest = NULL; 270 struct ipe_bdev *blob = ipe_bdev(bdev); 271 struct digest_info *info = NULL; 272 273 if (type == LSM_INT_DMVERITY_SIG_VALID) { 274 ipe_set_dmverity_signature(blob, value, size); 275 276 return 0; 277 } 278 279 if (type != LSM_INT_DMVERITY_ROOTHASH) 280 return -EINVAL; 281 282 if (!value) { 283 ipe_digest_free(blob->root_hash); 284 blob->root_hash = NULL; 285 286 return 0; 287 } 288 digest = value; 289 290 info = kzalloc(sizeof(*info), GFP_KERNEL); 291 if (!info) 292 return -ENOMEM; 293 294 info->digest = kmemdup(digest->digest, digest->digest_len, GFP_KERNEL); 295 if (!info->digest) 296 goto err; 297 298 info->alg = kstrdup(digest->alg, GFP_KERNEL); 299 if (!info->alg) 300 goto err; 301 302 info->digest_len = digest->digest_len; 303 304 ipe_digest_free(blob->root_hash); 305 blob->root_hash = info; 306 307 return 0; 308 err: 309 ipe_digest_free(info); 310 311 return -ENOMEM; 312 } 313 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 314 315 #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 316 /** 317 * ipe_inode_setintegrity() - save integrity data from a inode to IPE's LSM blob. 318 * @inode: The inode to source the security blob from. 319 * @type: Supplies the integrity type. 320 * @value: The value to be stored. 321 * @size: The size of @value. 322 * 323 * This hook is currently used to save the existence of a validated fs-verity 324 * builtin signature into LSM blob. 325 * 326 * Return: %0 on success. If an error occurs, the function will return the 327 * -errno. 328 */ 329 int ipe_inode_setintegrity(const struct inode *inode, 330 enum lsm_integrity_type type, 331 const void *value, size_t size) 332 { 333 struct ipe_inode *inode_sec = ipe_inode(inode); 334 335 if (type == LSM_INT_FSVERITY_BUILTINSIG_VALID) { 336 inode_sec->fs_verity_signed = size > 0 && value; 337 return 0; 338 } 339 340 return -EINVAL; 341 } 342 #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 343