Message ID | 20231107134012.682009-13-roberto.sassu@huaweicloud.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | security: Move IMA and EVM to the LSM infrastructure | expand |
On 11/7/2023 5:40 AM, Roberto Sassu wrote: > 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 > extends the TPM with the digest, verifies the file's integrity based on > the digest, and/or includes the file digest in the audit log. > > LSMs could similarly take action depending on the file content and the > access mask requested with open(). > > 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> Acked-by: Casey Schaufler <casey@schaufler-ca.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(+) > > diff --git a/fs/namei.c b/fs/namei.c > index 71c13b2990b4..fb93d3e13df6 100644 > --- a/fs/namei.c > +++ b/fs/namei.c > @@ -3620,6 +3620,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) > diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c > index fbbea7498f02..b0c3f07a8bba 100644 > --- a/fs/nfsd/vfs.c > +++ b/fs/nfsd/vfs.c > @@ -877,6 +877,12 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, > goto out; > } > > + host_err = security_file_post_open(file, may_flags); > + if (host_err) { > + fput(file); > + goto out; > + } > + > host_err = ima_file_check(file, may_flags); > if (host_err) { > fput(file); > diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h > index 88452e45025c..4f6861fecacd 100644 > --- a/include/linux/lsm_hook_defs.h > +++ b/include/linux/lsm_hook_defs.h > @@ -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) > diff --git a/include/linux/security.h b/include/linux/security.h > index 922ea7709bae..c360458920b1 100644 > --- a/include/linux/security.h > +++ b/include/linux/security.h > @@ -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; > diff --git a/security/security.c b/security/security.c > index 8aa6e9f316dd..fe6a160afc35 100644 > --- a/security/security.c > +++ b/security/security.c > @@ -2954,6 +2954,23 @@ int security_file_open(struct file *file) > return fsnotify_perm(file, MAY_OPEN); > } > > +/** > + * security_file_post_open() - Evaluate a file after it has been opened > + * @file: the file > + * @mask: access mask > + * > + * Evaluate an opened file and the access mask requested with open(). 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
diff --git a/fs/namei.c b/fs/namei.c index 71c13b2990b4..fb93d3e13df6 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3620,6 +3620,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) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index fbbea7498f02..b0c3f07a8bba 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -877,6 +877,12 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, goto out; } + host_err = security_file_post_open(file, may_flags); + if (host_err) { + fput(file); + goto out; + } + host_err = ima_file_check(file, may_flags); if (host_err) { fput(file); diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 88452e45025c..4f6861fecacd 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -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) diff --git a/include/linux/security.h b/include/linux/security.h index 922ea7709bae..c360458920b1 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -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; diff --git a/security/security.c b/security/security.c index 8aa6e9f316dd..fe6a160afc35 100644 --- a/security/security.c +++ b/security/security.c @@ -2954,6 +2954,23 @@ int security_file_open(struct file *file) return fsnotify_perm(file, MAY_OPEN); } +/** + * security_file_post_open() - Evaluate a file after it has been opened + * @file: the file + * @mask: access mask + * + * Evaluate an opened file and the access mask requested with open(). 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