From: Roberto Sassu <roberto.sassu@huawei.com>
In preparation to move IMA and EVM to the LSM infrastructure, introduce the
file_post_open hook. Also, export security_file_post_open() for NFS.
Based on policy, IMA calculates the digest of the file content, and decides
based on that digest whether the file should be made accessible to the
requesting process.
LSMs could similarly take action depending on the file content.
The new hook returns a value and can cause the open to be aborted.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
fs/namei.c | 2 ++
fs/nfsd/vfs.c | 6 ++++++
include/linux/lsm_hook_defs.h | 1 +
include/linux/security.h | 6 ++++++
security/security.c | 17 +++++++++++++++++
5 files changed, 32 insertions(+)
On Fri, 2023-10-27 at 10:35 +0200, Roberto Sassu wrote:
> diff --git a/security/security.c b/security/security.c
> index 2ee958afaf40..d24a8f92d641 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2947,6 +2947,23 @@ int security_file_open(struct file *file)
> return fsnotify_perm(file, MAY_OPEN);
> }
>
> +/**
> + * security_file_post_open() - Recheck access to a file after it has been opened
> + * @file: the file
> + * @mask: access mask
> + *
> + * Recheck access with mask after the file has been opened. The hook is useful
> + * for LSMs that require the file content to be available in order to make
> + * decisions.
> + *
The hook isn't limited to "Recheck access". It's used for measuring,
appraising, and auditing a file's integrity. Sorry for suggesting an
incomplete patch description. Please update the wording here and the
patch description accordingly.
> + * Return: Returns 0 if permission is granted.
> + */
> +int security_file_post_open(struct file *file, int mask)
> +{
> + return call_int_hook(file_post_open, 0, file, mask);
> +}
> +EXPORT_SYMBOL_GPL(security_file_post_open);
> +
> /**
> * security_file_truncate() - Check if truncating a file is allowed
> * @file: file
@@ -3637,6 +3637,8 @@ static int do_open(struct nameidata *nd,
error = may_open(idmap, &nd->path, acc_mode, open_flag);
if (!error && !(file->f_mode & FMODE_OPENED))
error = vfs_open(&nd->path, file);
+ if (!error)
+ error = security_file_post_open(file, op->acc_mode);
if (!error)
error = ima_file_check(file, op->acc_mode);
if (!error && do_truncate)
@@ -862,6 +862,12 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
goto out_nfserr;
}
+ host_err = security_file_post_open(file, may_flags);
+ if (host_err) {
+ fput(file);
+ goto out_nfserr;
+ }
+
host_err = ima_file_check(file, may_flags);
if (host_err) {
fput(file);
@@ -189,6 +189,7 @@ LSM_HOOK(int, 0, file_send_sigiotask, struct task_struct *tsk,
struct fown_struct *fown, int sig)
LSM_HOOK(int, 0, file_receive, struct file *file)
LSM_HOOK(int, 0, file_open, struct file *file)
+LSM_HOOK(int, 0, file_post_open, struct file *file, int mask)
LSM_HOOK(int, 0, file_truncate, struct file *file)
LSM_HOOK(int, 0, task_alloc, struct task_struct *task,
unsigned long clone_flags)
@@ -409,6 +409,7 @@ int security_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int sig);
int security_file_receive(struct file *file);
int security_file_open(struct file *file);
+int security_file_post_open(struct file *file, int mask);
int security_file_truncate(struct file *file);
int security_task_alloc(struct task_struct *task, unsigned long clone_flags);
void security_task_free(struct task_struct *task);
@@ -1065,6 +1066,11 @@ static inline int security_file_open(struct file *file)
return 0;
}
+static inline int security_file_post_open(struct file *file, int mask)
+{
+ return 0;
+}
+
static inline int security_file_truncate(struct file *file)
{
return 0;
@@ -2947,6 +2947,23 @@ int security_file_open(struct file *file)
return fsnotify_perm(file, MAY_OPEN);
}
+/**
+ * security_file_post_open() - Recheck access to a file after it has been opened
+ * @file: the file
+ * @mask: access mask
+ *
+ * Recheck access with mask after the file has been opened. The hook is useful
+ * for LSMs that require the file content to be available in order to make
+ * decisions.
+ *
+ * Return: Returns 0 if permission is granted.
+ */
+int security_file_post_open(struct file *file, int mask)
+{
+ return call_int_hook(file_post_open, 0, file, mask);
+}
+EXPORT_SYMBOL_GPL(security_file_post_open);
+
/**
* security_file_truncate() - Check if truncating a file is allowed
* @file: file