--- v7
+++ v6
@@ -2,8 +2,7 @@
additional restrictions depending on a security policy managed by the
kernel through a sysctl or implemented by an LSM thanks to the
inode_permission hook. This new flag is ignored by open(2) and
-openat(2) because of their unspecified flags handling. When used with
-openat2(2), the default behavior is only to forbid to open a directory.
+openat(2) because of their unspecified flags handling.
The underlying idea is to be able to restrict scripts interpretation
according to a policy defined by the system administrator. For this to
@@ -33,14 +32,16 @@
The implementation of O_MAYEXEC almost duplicates what execve(2) and
uselib(2) are already doing: setting MAY_OPENEXEC in acc_mode (which can
-then be checked as MAY_EXEC, if enforced).
+then be checked as MAY_EXEC, if enforced), and propagating FMODE_EXEC to
+_fmode via __FMODE_EXEC flag (which can then trigger a
+fanotify/FAN_OPEN_EXEC event).
This is an updated subset of the patch initially written by Vincent
Strubel for CLIP OS 4:
https://github.com/clipos-archive/src_platform_clip-patches/blob/f5cb330d6b684752e403b4e41b39f7004d88e561/1901_open_mayexec.patch
This patch has been used for more than 12 years with customized script
-interpreters. Some examples (with the original O_MAYEXEC) can be found
-here:
+interpreters. Some examples (with the original name O_MAYEXEC) can be
+found here:
https://github.com/clipos-archive/clipos4_portage-overlay/search?q=O_MAYEXEC
Co-developed-by: Vincent Strubel <vincent.strubel@ssi.gouv.fr>
@@ -48,18 +49,11 @@
Co-developed-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr>
Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr>
Signed-off-by: Mickaël Salaün <mic@digikod.net>
+Reviewed-by: Deven Bowers <deven.desai@linux.microsoft.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
Cc: Aleksa Sarai <cyphar@cyphar.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
-Cc: Deven Bowers <deven.desai@linux.microsoft.com>
-Cc: Kees Cook <keescook@chromium.org>
---
-
-Changes since v6:
-* Do not set __FMODE_EXEC for now because of inconsistent behavior:
- https://lore.kernel.org/lkml/202007160822.CCDB5478@keescook/
-* Returns EISDIR when opening a directory with O_MAYEXEC.
-* Removed Deven Bowers and Kees Cook Reviewed-by tags because of the
- current update.
Changes since v5:
* Update commit message.
@@ -88,12 +82,11 @@
https://lore.kernel.org/lkml/20181213094658.GA996@lithium.mbobrowski.org/
---
fs/fcntl.c | 2 +-
- fs/namei.c | 4 ++--
- fs/open.c | 6 ++++++
+ fs/open.c | 8 ++++++++
include/linux/fcntl.h | 2 +-
include/linux/fs.h | 2 ++
include/uapi/asm-generic/fcntl.h | 7 +++++++
- 6 files changed, 19 insertions(+), 4 deletions(-)
+ 5 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 2e4c0fa2074b..0357ad667563 100644
@@ -108,30 +101,8 @@
HWEIGHT32(
(VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) |
__FMODE_EXEC | __FMODE_NONOTIFY));
-diff --git a/fs/namei.c b/fs/namei.c
-index ddc9b25540fe..3f074ec77390 100644
---- a/fs/namei.c
-+++ b/fs/namei.c
-@@ -428,7 +428,7 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
- /**
- * inode_permission - Check for access rights to a given inode
- * @inode: Inode to check permission on
-- * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
-+ * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, %MAY_OPENEXEC)
- *
- * Check for read/write/execute permissions on an inode. We use fs[ug]id for
- * this, letting us set arbitrary permissions for filesystem access without
-@@ -2849,7 +2849,7 @@ static int may_open(const struct path *path, int acc_mode, int flag)
- case S_IFLNK:
- return -ELOOP;
- case S_IFDIR:
-- if (acc_mode & (MAY_WRITE | MAY_EXEC))
-+ if (acc_mode & (MAY_WRITE | MAY_EXEC | MAY_OPENEXEC))
- return -EISDIR;
- break;
- case S_IFBLK:
diff --git a/fs/open.c b/fs/open.c
-index 623b7506a6db..21c2c1020574 100644
+index 623b7506a6db..38e434bdbbb6 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -987,6 +987,8 @@ inline struct open_how build_open_how(int flags, umode_t mode)
@@ -143,13 +114,15 @@
/* O_PATH beats everything else. */
if (how.flags & O_PATH)
how.flags &= O_PATH_FLAGS;
-@@ -1054,6 +1056,10 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op)
+@@ -1054,6 +1056,12 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op)
if (flags & __O_SYNC)
flags |= O_DSYNC;
+ /* Checks execution permissions on open. */
-+ if (flags & O_MAYEXEC)
++ if (flags & O_MAYEXEC) {
+ acc_mode |= MAY_OPENEXEC;
++ flags |= __FMODE_EXEC;
++ }
+
op->open_flag = flags;