Re: [PATCH 6/9] fs: Introduce file_to_perms() helper

From: Casey Schaufler
Date: Thu Oct 20 2022 - 13:29:23 EST


On 10/13/2022 3:36 PM, Kees Cook wrote:
> Extract the logic used by LSM file hooks to be able to reconstruct the
> access mode permissions from an open.
>
> Cc: John Johansen <john.johansen@xxxxxxxxxxxxx>
> Cc: Paul Moore <paul@xxxxxxxxxxxxxx>
> Cc: James Morris <jmorris@xxxxxxxxx>
> Cc: "Serge E. Hallyn" <serge@xxxxxxxxxx>
> Cc: linux-security-module@xxxxxxxxxxxxxxx
> Signed-off-by: Kees Cook <keescook@xxxxxxxxxxxx>
> ---
> include/linux/fs.h | 22 ++++++++++++++++++++++
> security/apparmor/include/file.h | 18 ++++--------------
> 2 files changed, 26 insertions(+), 14 deletions(-)

Smack uses its own definitions for MAY_SOMETHING. Making
AppArmor's values global is going to clash. If you want to
do this there needs to be a grand consolidation. It could
go in security/lsm_hooks.h. I can't see anyone other than
Smack wanting MAY_LOCK, so I can't say the concept really
makes much sense.

>
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 9eced4cc286e..814f10d4132e 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -993,6 +993,28 @@ static inline struct file *get_file(struct file *f)
> #define get_file_rcu(x) atomic_long_inc_not_zero(&(x)->f_count)
> #define file_count(x) atomic_long_read(&(x)->f_count)
>
> +/* Calculate the basic MAY_* flags needed for a given file. */
> +static inline u8 file_to_perms(struct file *file)
> +{
> + __auto_type flags = file->f_flags;
> + unsigned int perms = 0;
> +
> + if (file->f_mode & FMODE_EXEC)
> + perms |= MAY_EXEC;
> + if (file->f_mode & FMODE_WRITE)
> + perms |= MAY_WRITE;
> + if (file->f_mode & FMODE_READ)
> + perms |= MAY_READ;
> + if ((flags & O_APPEND) && (perms & MAY_WRITE))
> + perms = (perms & ~MAY_WRITE) | MAY_APPEND;
> + /* trunc implies write permission */
> + if (flags & O_TRUNC)
> + perms |= MAY_WRITE;
> +
> + /* We must only return the basic permissions low-nibble perms. */
> + return (perms | (MAY_EXEC | MAY_WRITE | MAY_READ | MAY_APPEND));
> +}
> +
> #define MAX_NON_LFS ((1UL<<31) - 1)
>
> /* Page cache limit. The filesystems should put that into their s_maxbytes
> diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
> index 029cb20e322d..505d6da02af3 100644
> --- a/security/apparmor/include/file.h
> +++ b/security/apparmor/include/file.h
> @@ -218,20 +218,10 @@ static inline void aa_free_file_rules(struct aa_file_rules *rules)
> */
> static inline u32 aa_map_file_to_perms(struct file *file)
> {
> - int flags = file->f_flags;
> - u32 perms = 0;
> -
> - if (file->f_mode & FMODE_WRITE)
> - perms |= MAY_WRITE;
> - if (file->f_mode & FMODE_READ)
> - perms |= MAY_READ;
> -
> - if ((flags & O_APPEND) && (perms & MAY_WRITE))
> - perms = (perms & ~MAY_WRITE) | MAY_APPEND;
> - /* trunc implies write permission */
> - if (flags & O_TRUNC)
> - perms |= MAY_WRITE;
> - if (flags & O_CREAT)
> + u32 perms = file_to_perms(file);
> +
> + /* Also want to check O_CREAT */
> + if (file->f_flags & O_CREAT)
> perms |= AA_MAY_CREATE;
>
> return perms;