d_real() is about to be able to fail for D_REAL_DATA. So switch ipe_build_eval_ctx() from d_real_inode() to d_real_data_inode() and deal with the error. Currently, if overlayfs fails to resolve the data of a file it hands back the overlayfs inode and IPE evaluates the policy against that. The overlayfs inode has neither a block device nor any fs-verity state so none of the properties of the file hosting the data are visible. Remember the error in the evaluation context and if a policy is loaded refuse the operation with -EACCES without looking at the rules. That's what IPE returns for every denial and what IMA returns when it can't appraise a file. Permissive mode allows it like any other denial and without a policy IPE still allows everything. Note that the operation wouldn't necessarily fail on its own. overlayfs doesn't verify the data again on mmap() so a file whose data can't be resolved could otherwise be mapped executable. This is a no-op until d_real() can actually fail. Signed-off-by: Christian Brauner (Amutable) --- security/ipe/eval.c | 15 ++++++++++++++- security/ipe/eval.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/security/ipe/eval.c b/security/ipe/eval.c index 4a7be96c84f03..3751963509df4 100644 --- a/security/ipe/eval.c +++ b/security/ipe/eval.c @@ -102,7 +102,11 @@ void ipe_build_eval_ctx(struct ipe_eval_ctx *ctx, if (file) { build_ipe_sb_ctx(ctx, file); - ino = d_real_inode(file->f_path.dentry); + ino = d_real_data_inode(file->f_path.dentry); + if (IS_ERR(ino)) { + ctx->file_err = PTR_ERR(ino); + return; + } build_ipe_bdev_ctx(ctx, ino); build_ipe_inode_ctx(ctx, ino); } @@ -335,6 +339,15 @@ int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx) return 0; } + /* + * Without the inode hosting the data none of the properties of the + * file can be evaluated. Refuse it unless IPE is permissive. + */ + if (ctx->file_err) { + rcu_read_unlock(); + return READ_ONCE(enforce) ? -EACCES : 0; + } + if (ctx->op == IPE_OP_INVALID) { if (pol->parsed->global_default_action == IPE_ACTION_INVALID) { WARN(1, "no default rule set for unknown op, ALLOW it"); diff --git a/security/ipe/eval.h b/security/ipe/eval.h index b26d1147d0708..58ca50987b2b5 100644 --- a/security/ipe/eval.h +++ b/security/ipe/eval.h @@ -42,6 +42,7 @@ struct ipe_eval_ctx { enum ipe_hook_type hook; const struct file *file; + int file_err; bool initramfs; #ifdef CONFIG_IPE_PROP_DM_VERITY const struct ipe_bdev *ipe_bdev; -- 2.53.0