2023-12-14 17:13:53

by Roberto Sassu

[permalink] [raw]
Subject: [PATCH v8 13/24] security: Introduce file_release hook

From: Roberto Sassu <[email protected]>

In preparation for moving IMA and EVM to the LSM infrastructure, introduce
the file_release hook.

IMA calculates at file close the new digest of the file content and writes
it to security.ima, so that appraisal at next file access succeeds.

LSMs could also take some action before the last reference of a file is
released.

The new hook cannot return an error and cannot cause the operation to be
reverted.

Signed-off-by: Roberto Sassu <[email protected]>
---
fs/file_table.c | 1 +
include/linux/lsm_hook_defs.h | 1 +
include/linux/security.h | 4 ++++
security/security.c | 11 +++++++++++
4 files changed, 17 insertions(+)

diff --git a/fs/file_table.c b/fs/file_table.c
index de4a2915bfd4..c72dc75f2bd3 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -385,6 +385,7 @@ static void __fput(struct file *file)
eventpoll_release(file);
locks_remove_file(file);

+ security_file_release(file);
ima_file_free(file);
if (unlikely(file->f_flags & FASYNC)) {
if (file->f_op->fasync)
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index e2b45fee94e2..175ca00a6b1d 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -173,6 +173,7 @@ LSM_HOOK(int, 0, kernfs_init_security, struct kernfs_node *kn_dir,
struct kernfs_node *kn)
LSM_HOOK(int, 0, file_permission, struct file *file, int mask)
LSM_HOOK(int, 0, file_alloc_security, struct file *file)
+LSM_HOOK(void, LSM_RET_VOID, file_release, struct file *file)
LSM_HOOK(void, LSM_RET_VOID, file_free_security, struct file *file)
LSM_HOOK(int, 0, file_ioctl, struct file *file, unsigned int cmd,
unsigned long arg)
diff --git a/include/linux/security.h b/include/linux/security.h
index c360458920b1..4c3585e3dcb4 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -395,6 +395,7 @@ int security_kernfs_init_security(struct kernfs_node *kn_dir,
struct kernfs_node *kn);
int security_file_permission(struct file *file, int mask);
int security_file_alloc(struct file *file);
+void security_file_release(struct file *file);
void security_file_free(struct file *file);
int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
int security_mmap_file(struct file *file, unsigned long prot,
@@ -1006,6 +1007,9 @@ static inline int security_file_alloc(struct file *file)
return 0;
}

+static inline void security_file_release(struct file *file)
+{ }
+
static inline void security_file_free(struct file *file)
{ }

diff --git a/security/security.c b/security/security.c
index fe6a160afc35..9aa072ca5a19 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2724,6 +2724,17 @@ int security_file_alloc(struct file *file)
return rc;
}

+/**
+ * security_file_release() - Perform actions before releasing the file ref
+ * @file: the file
+ *
+ * Perform actions before releasing the last reference to a file.
+ */
+void security_file_release(struct file *file)
+{
+ call_void_hook(file_release, file);
+}
+
/**
* security_file_free() - Free a file's LSM blob
* @file: the file
--
2.34.1


2023-12-15 21:41:36

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v8 13/24] security: Introduce file_release hook

On 12/14/2023 9:08 AM, Roberto Sassu wrote:
> From: Roberto Sassu <[email protected]>
>
> In preparation for moving IMA and EVM to the LSM infrastructure, introduce
> the file_release hook.
>
> IMA calculates at file close the new digest of the file content and writes
> it to security.ima, so that appraisal at next file access succeeds.
>
> LSMs could also take some action before the last reference of a file is
> released.

You could make this more convincing with an example. Perhaps:

An LSM could implement an exclusive access scheme for files,
only allowing access to files that have no references.


>
> The new hook cannot return an error and cannot cause the operation to be
> reverted.
>
> Signed-off-by: Roberto Sassu <[email protected]>
> ---
> fs/file_table.c | 1 +
> include/linux/lsm_hook_defs.h | 1 +
> include/linux/security.h | 4 ++++
> security/security.c | 11 +++++++++++
> 4 files changed, 17 insertions(+)
>
> diff --git a/fs/file_table.c b/fs/file_table.c
> index de4a2915bfd4..c72dc75f2bd3 100644
> --- a/fs/file_table.c
> +++ b/fs/file_table.c
> @@ -385,6 +385,7 @@ static void __fput(struct file *file)
> eventpoll_release(file);
> locks_remove_file(file);
>
> + security_file_release(file);
> ima_file_free(file);
> if (unlikely(file->f_flags & FASYNC)) {
> if (file->f_op->fasync)
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index e2b45fee94e2..175ca00a6b1d 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -173,6 +173,7 @@ LSM_HOOK(int, 0, kernfs_init_security, struct kernfs_node *kn_dir,
> struct kernfs_node *kn)
> LSM_HOOK(int, 0, file_permission, struct file *file, int mask)
> LSM_HOOK(int, 0, file_alloc_security, struct file *file)
> +LSM_HOOK(void, LSM_RET_VOID, file_release, struct file *file)
> LSM_HOOK(void, LSM_RET_VOID, file_free_security, struct file *file)
> LSM_HOOK(int, 0, file_ioctl, struct file *file, unsigned int cmd,
> unsigned long arg)
> diff --git a/include/linux/security.h b/include/linux/security.h
> index c360458920b1..4c3585e3dcb4 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -395,6 +395,7 @@ int security_kernfs_init_security(struct kernfs_node *kn_dir,
> struct kernfs_node *kn);
> int security_file_permission(struct file *file, int mask);
> int security_file_alloc(struct file *file);
> +void security_file_release(struct file *file);
> void security_file_free(struct file *file);
> int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
> int security_mmap_file(struct file *file, unsigned long prot,
> @@ -1006,6 +1007,9 @@ static inline int security_file_alloc(struct file *file)
> return 0;
> }
>
> +static inline void security_file_release(struct file *file)
> +{ }
> +
> static inline void security_file_free(struct file *file)
> { }
>
> diff --git a/security/security.c b/security/security.c
> index fe6a160afc35..9aa072ca5a19 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2724,6 +2724,17 @@ int security_file_alloc(struct file *file)
> return rc;
> }
>
> +/**
> + * security_file_release() - Perform actions before releasing the file ref
> + * @file: the file
> + *
> + * Perform actions before releasing the last reference to a file.
> + */
> +void security_file_release(struct file *file)
> +{
> + call_void_hook(file_release, file);
> +}
> +
> /**
> * security_file_free() - Free a file's LSM blob
> * @file: the file