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

From: Kees Cook
Date: Thu Oct 13 2022 - 18:37:46 EST


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(-)

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;
--
2.34.1