Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ipe: enable support for fs-verity as a trust provider

Enable IPE policy authors to indicate trust for a singular fsverity
file, identified by the digest information, through "fsverity_digest"
and all files using valid fsverity 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: Deven Bowers <deven.desai@linux.microsoft.com>
Signed-off-by: Fan Wu <wufan@linux.microsoft.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>

authored by

Fan Wu and committed by
Paul Moore
31f8c868 7c373e4f

+237 -1
+26
security/ipe/Kconfig
··· 10 10 select SYSTEM_DATA_VERIFICATION 11 11 select IPE_PROP_DM_VERITY if DM_VERITY 12 12 select IPE_PROP_DM_VERITY_SIGNATURE if DM_VERITY && DM_VERITY_VERIFY_ROOTHASH_SIG 13 + select IPE_PROP_FS_VERITY if FS_VERITY 14 + select IPE_PROP_FS_VERITY_BUILTIN_SIG if FS_VERITY && FS_VERITY_BUILTIN_SIGNATURES 13 15 help 14 16 This option enables the Integrity Policy Enforcement LSM 15 17 allowing users to define a policy to enforce a trust-based access ··· 40 38 policies. The property evaluates to TRUE when a file from a dm-verity 41 39 volume, which has been mounted with a valid signed root hash, 42 40 is evaluated. 41 + 42 + If unsure, answer Y. 43 + 44 + config IPE_PROP_FS_VERITY 45 + bool "Enable support for fs-verity based on file digest" 46 + depends on FS_VERITY 47 + help 48 + This option enables the 'fsverity_digest' property within IPE 49 + policies. The property evaluates to TRUE when a file is fsverity 50 + enabled and its digest matches the supplied digest value in the 51 + policy. 52 + 53 + if unsure, answer Y. 54 + 55 + config IPE_PROP_FS_VERITY_BUILTIN_SIG 56 + bool "Enable support for fs-verity based on builtin signature" 57 + depends on FS_VERITY && FS_VERITY_BUILTIN_SIGNATURES 58 + help 59 + This option enables the 'fsverity_signature' property within IPE 60 + policies. The property evaluates to TRUE when a file is fsverity 61 + enabled and it has a valid builtin signature whose signing cert 62 + is in the .fs-verity keyring. 63 + 64 + if unsure, answer Y. 43 65 44 66 endmenu 45 67
+17
security/ipe/audit.c
··· 56 56 "dmverity_roothash=", 57 57 "dmverity_signature=FALSE", 58 58 "dmverity_signature=TRUE", 59 + "fsverity_digest=", 60 + "fsverity_signature=FALSE", 61 + "fsverity_signature=TRUE", 59 62 }; 60 63 61 64 /** ··· 70 67 { 71 68 audit_log_format(ab, "%s", audit_prop_names[IPE_PROP_DMV_ROOTHASH]); 72 69 ipe_digest_audit(ab, rh); 70 + } 71 + 72 + /** 73 + * audit_fsv_digest() - audit the digest of a fsverity_digest property. 74 + * @ab: Supplies a pointer to the audit_buffer to append to. 75 + * @d: Supplies a pointer to the digest structure. 76 + */ 77 + static void audit_fsv_digest(struct audit_buffer *ab, const void *d) 78 + { 79 + audit_log_format(ab, "%s", audit_prop_names[IPE_PROP_FSV_DIGEST]); 80 + ipe_digest_audit(ab, d); 73 81 } 74 82 75 83 /** ··· 98 84 switch (ptr->type) { 99 85 case IPE_PROP_DMV_ROOTHASH: 100 86 audit_dmv_roothash(ab, ptr->value); 87 + break; 88 + case IPE_PROP_FSV_DIGEST: 89 + audit_fsv_digest(ab, ptr->value); 101 90 break; 102 91 default: 103 92 audit_log_format(ab, "%s", audit_prop_names[ptr->type]);
+122 -1
security/ipe/eval.c
··· 10 10 #include <linux/sched.h> 11 11 #include <linux/rcupdate.h> 12 12 #include <linux/moduleparam.h> 13 + #include <linux/fsverity.h> 13 14 14 15 #include "ipe.h" 15 16 #include "eval.h" ··· 52 51 } 53 52 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 54 53 54 + #ifdef CONFIG_IPE_PROP_FS_VERITY 55 + #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 56 + static void build_ipe_inode_blob_ctx(struct ipe_eval_ctx *ctx, 57 + const struct inode *const ino) 58 + { 59 + ctx->ipe_inode = ipe_inode(ctx->ino); 60 + } 61 + #else 62 + static inline void build_ipe_inode_blob_ctx(struct ipe_eval_ctx *ctx, 63 + const struct inode *const ino) 64 + { 65 + } 66 + #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 67 + 68 + /** 69 + * build_ipe_inode_ctx() - Build inode fields of an evaluation context. 70 + * @ctx: Supplies a pointer to the context to be populated. 71 + * @ino: Supplies the inode struct of the file triggered IPE event. 72 + */ 73 + static void build_ipe_inode_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino) 74 + { 75 + ctx->ino = ino; 76 + build_ipe_inode_blob_ctx(ctx, ino); 77 + } 78 + #else 79 + static void build_ipe_inode_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino) 80 + { 81 + } 82 + #endif /* CONFIG_IPE_PROP_FS_VERITY */ 83 + 55 84 /** 56 85 * ipe_build_eval_ctx() - Build an ipe evaluation context. 57 86 * @ctx: Supplies a pointer to the context to be populated. ··· 94 63 enum ipe_op_type op, 95 64 enum ipe_hook_type hook) 96 65 { 66 + struct inode *ino; 67 + 97 68 ctx->file = file; 98 69 ctx->op = op; 99 70 ctx->hook = hook; 100 71 101 72 if (file) { 102 73 build_ipe_sb_ctx(ctx, file); 103 - build_ipe_bdev_ctx(ctx, d_real_inode(file->f_path.dentry)); 74 + ino = d_real_inode(file->f_path.dentry); 75 + build_ipe_bdev_ctx(ctx, ino); 76 + build_ipe_inode_ctx(ctx, ino); 104 77 } 105 78 } 106 79 ··· 185 150 } 186 151 #endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */ 187 152 153 + #ifdef CONFIG_IPE_PROP_FS_VERITY 154 + /** 155 + * evaluate_fsv_digest() - Evaluate @ctx against a fsv digest property. 156 + * @ctx: Supplies a pointer to the context being evaluated. 157 + * @p: Supplies a pointer to the property being evaluated. 158 + * 159 + * Return: 160 + * * %true - The current @ctx match the @p 161 + * * %false - The current @ctx doesn't match the @p 162 + */ 163 + static bool evaluate_fsv_digest(const struct ipe_eval_ctx *const ctx, 164 + struct ipe_prop *p) 165 + { 166 + enum hash_algo alg; 167 + u8 digest[FS_VERITY_MAX_DIGEST_SIZE]; 168 + struct digest_info info; 169 + 170 + if (!ctx->ino) 171 + return false; 172 + if (!fsverity_get_digest((struct inode *)ctx->ino, 173 + digest, 174 + NULL, 175 + &alg)) 176 + return false; 177 + 178 + info.alg = hash_algo_name[alg]; 179 + info.digest = digest; 180 + info.digest_len = hash_digest_size[alg]; 181 + 182 + return ipe_digest_eval(p->value, &info); 183 + } 184 + #else 185 + static bool evaluate_fsv_digest(const struct ipe_eval_ctx *const ctx, 186 + struct ipe_prop *p) 187 + { 188 + return false; 189 + } 190 + #endif /* CONFIG_IPE_PROP_FS_VERITY */ 191 + 192 + #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 193 + /** 194 + * evaluate_fsv_sig_false() - Evaluate @ctx against a fsv sig false property. 195 + * @ctx: Supplies a pointer to the context being evaluated. 196 + * 197 + * Return: 198 + * * %true - The current @ctx match the property 199 + * * %false - The current @ctx doesn't match the property 200 + */ 201 + static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx) 202 + { 203 + return !ctx->ino || 204 + !IS_VERITY(ctx->ino) || 205 + !ctx->ipe_inode || 206 + !ctx->ipe_inode->fs_verity_signed; 207 + } 208 + 209 + /** 210 + * evaluate_fsv_sig_true() - Evaluate @ctx against a fsv sig true property. 211 + * @ctx: Supplies a pointer to the context being evaluated. 212 + * 213 + * Return: 214 + * * %true - The current @ctx match the property 215 + * * %false - The current @ctx doesn't match the property 216 + */ 217 + static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx) 218 + { 219 + return !evaluate_fsv_sig_false(ctx); 220 + } 221 + #else 222 + static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx) 223 + { 224 + return false; 225 + } 226 + 227 + static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx) 228 + { 229 + return false; 230 + } 231 + #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 232 + 188 233 /** 189 234 * evaluate_property() - Analyze @ctx against a rule property. 190 235 * @ctx: Supplies a pointer to the context to be evaluated. ··· 291 176 return evaluate_dmv_sig_false(ctx); 292 177 case IPE_PROP_DMV_SIG_TRUE: 293 178 return evaluate_dmv_sig_true(ctx); 179 + case IPE_PROP_FSV_DIGEST: 180 + return evaluate_fsv_digest(ctx, p); 181 + case IPE_PROP_FSV_SIG_FALSE: 182 + return evaluate_fsv_sig_false(ctx); 183 + case IPE_PROP_FSV_SIG_TRUE: 184 + return evaluate_fsv_sig_true(ctx); 294 185 default: 295 186 return false; 296 187 }
+12
security/ipe/eval.h
··· 31 31 }; 32 32 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 33 33 34 + #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 35 + struct ipe_inode { 36 + bool fs_verity_signed; 37 + }; 38 + #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 39 + 34 40 struct ipe_eval_ctx { 35 41 enum ipe_op_type op; 36 42 enum ipe_hook_type hook; ··· 46 40 #ifdef CONFIG_IPE_PROP_DM_VERITY 47 41 const struct ipe_bdev *ipe_bdev; 48 42 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 43 + #ifdef CONFIG_IPE_PROP_FS_VERITY 44 + const struct inode *ino; 45 + #endif /* CONFIG_IPE_PROP_FS_VERITY */ 46 + #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 47 + const struct ipe_inode *ipe_inode; 48 + #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 49 49 }; 50 50 51 51 enum ipe_match {
+29
security/ipe/hooks.c
··· 283 283 return -ENOMEM; 284 284 } 285 285 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 286 + 287 + #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 288 + /** 289 + * ipe_inode_setintegrity() - save integrity data from a inode to IPE's LSM blob. 290 + * @inode: The inode to source the security blob from. 291 + * @type: Supplies the integrity type. 292 + * @value: The value to be stored. 293 + * @size: The size of @value. 294 + * 295 + * This hook is currently used to save the existence of a validated fs-verity 296 + * builtin signature into LSM blob. 297 + * 298 + * Return: %0 on success. If an error occurs, the function will return the 299 + * -errno. 300 + */ 301 + int ipe_inode_setintegrity(const struct inode *inode, 302 + enum lsm_integrity_type type, 303 + const void *value, size_t size) 304 + { 305 + struct ipe_inode *inode_sec = ipe_inode(inode); 306 + 307 + if (type == LSM_INT_FSVERITY_BUILTINSIG_VALID) { 308 + inode_sec->fs_verity_signed = size > 0 && value; 309 + return 0; 310 + } 311 + 312 + return -EINVAL; 313 + } 314 + #endif /* CONFIG_CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+6
security/ipe/hooks.h
··· 9 9 #include <linux/binfmts.h> 10 10 #include <linux/security.h> 11 11 #include <linux/blk_types.h> 12 + #include <linux/fsverity.h> 12 13 13 14 enum ipe_hook_type { 14 15 IPE_HOOK_BPRM_CHECK = 0, ··· 43 42 int ipe_bdev_setintegrity(struct block_device *bdev, enum lsm_integrity_type type, 44 43 const void *value, size_t len); 45 44 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 45 + 46 + #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 47 + int ipe_inode_setintegrity(const struct inode *inode, enum lsm_integrity_type type, 48 + const void *value, size_t size); 49 + #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 46 50 47 51 #endif /* _IPE_HOOKS_H */
+13
security/ipe/ipe.c
··· 16 16 #ifdef CONFIG_IPE_PROP_DM_VERITY 17 17 .lbs_bdev = sizeof(struct ipe_bdev), 18 18 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 19 + #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 20 + .lbs_inode = sizeof(struct ipe_inode), 21 + #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 19 22 }; 20 23 21 24 static const struct lsm_id ipe_lsmid = { ··· 38 35 } 39 36 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 40 37 38 + #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 39 + struct ipe_inode *ipe_inode(const struct inode *inode) 40 + { 41 + return inode->i_security + ipe_blobs.lbs_inode; 42 + } 43 + #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 44 + 41 45 static struct security_hook_list ipe_hooks[] __ro_after_init = { 42 46 LSM_HOOK_INIT(bprm_check_security, ipe_bprm_check_security), 43 47 LSM_HOOK_INIT(mmap_file, ipe_mmap_file), ··· 56 46 LSM_HOOK_INIT(bdev_free_security, ipe_bdev_free_security), 57 47 LSM_HOOK_INIT(bdev_setintegrity, ipe_bdev_setintegrity), 58 48 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 49 + #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 50 + LSM_HOOK_INIT(inode_setintegrity, ipe_inode_setintegrity), 51 + #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 59 52 }; 60 53 61 54 /**
+3
security/ipe/ipe.h
··· 19 19 #ifdef CONFIG_IPE_PROP_DM_VERITY 20 20 struct ipe_bdev *ipe_bdev(struct block_device *b); 21 21 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 22 + #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 23 + struct ipe_inode *ipe_inode(const struct inode *inode); 24 + #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 22 25 23 26 #endif /* _IPE_H */
+3
security/ipe/policy.h
··· 36 36 IPE_PROP_DMV_ROOTHASH, 37 37 IPE_PROP_DMV_SIG_FALSE, 38 38 IPE_PROP_DMV_SIG_TRUE, 39 + IPE_PROP_FSV_DIGEST, 40 + IPE_PROP_FSV_SIG_FALSE, 41 + IPE_PROP_FSV_SIG_TRUE, 39 42 __IPE_PROP_MAX 40 43 }; 41 44
+6
security/ipe/policy_parser.c
··· 278 278 {IPE_PROP_DMV_ROOTHASH, "dmverity_roothash=%s"}, 279 279 {IPE_PROP_DMV_SIG_FALSE, "dmverity_signature=FALSE"}, 280 280 {IPE_PROP_DMV_SIG_TRUE, "dmverity_signature=TRUE"}, 281 + {IPE_PROP_FSV_DIGEST, "fsverity_digest=%s"}, 282 + {IPE_PROP_FSV_SIG_FALSE, "fsverity_signature=FALSE"}, 283 + {IPE_PROP_FSV_SIG_TRUE, "fsverity_signature=TRUE"}, 281 284 {IPE_PROP_INVALID, NULL} 282 285 }; 283 286 ··· 313 310 314 311 switch (token) { 315 312 case IPE_PROP_DMV_ROOTHASH: 313 + case IPE_PROP_FSV_DIGEST: 316 314 dup = match_strdup(&args[0]); 317 315 if (!dup) { 318 316 rc = -ENOMEM; ··· 329 325 case IPE_PROP_BOOT_VERIFIED_TRUE: 330 326 case IPE_PROP_DMV_SIG_FALSE: 331 327 case IPE_PROP_DMV_SIG_TRUE: 328 + case IPE_PROP_FSV_SIG_FALSE: 329 + case IPE_PROP_FSV_SIG_TRUE: 332 330 p->type = token; 333 331 break; 334 332 default: