linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC
@ 2020-04-28 17:51 Mickaël Salaün
  2020-04-28 17:51 ` [PATCH v3 1/5] fs: Add support for a RESOLVE_MAYEXEC flag on openat2(2) Mickaël Salaün
                   ` (7 more replies)
  0 siblings, 8 replies; 23+ messages in thread
From: Mickaël Salaün @ 2020-04-28 17:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mickaël Salaün, Aleksa Sarai, Alexei Starovoitov,
	Al Viro, Andy Lutomirski, Christian Heimes, Daniel Borkmann,
	Deven Bowers, Eric Chiang, Florian Weimer, James Morris,
	Jan Kara, Jann Horn, Jonathan Corbet, Kees Cook, Matthew Garrett,
	Matthew Wilcox, Michael Kerrisk, Mickaël Salaün,
	Mimi Zohar, Philippe Trébuchet, Scott Shell,
	Sean Christopherson, Shuah Khan, Steve Dower, Steve Grubb,
	Thibaut Sautereau, Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel

Hi,

The goal of this patch series is to enable to control script execution
with interpreters help.  A new RESOLVE_MAYEXEC flag, usable through
openat2(2), is added to enable userspace script interpreter to delegate
to the kernel (and thus the system security policy) the permission to
interpret/execute scripts or other files containing what can be seen as
commands.

This third patch series mainly differ from the previous one by relying
on the new openat2(2) system call to get rid of the undefined behavior
of the open(2) flags.  Thus, the previous O_MAYEXEC flag is now replaced
with the new RESOLVE_MAYEXEC flag and benefits from the openat2(2)
strict check of this kind of flags.

A simple system-wide security policy can be enforced by the system
administrator through a sysctl configuration consistent with the mount
points or the file access rights.  The documentation patch explains the
prerequisites.

Furthermore, the security policy can also be delegated to an LSM, either
a MAC system or an integrity system.  For instance, the new kernel
MAY_OPENEXEC flag closes a major IMA measurement/appraisal interpreter
integrity gap by bringing the ability to check the use of scripts [1].
Other uses are expected, such as for openat2(2) [2], SGX integration
[3], bpffs [4] or IPE [5].

Userspace needs to adapt to take advantage of this new feature.  For
example, the PEP 578 [6] (Runtime Audit Hooks) enables Python 3.8 to be
extended with policy enforcement points related to code interpretation,
which can be used to align with the PowerShell audit features.
Additional Python security improvements (e.g. a limited interpreter
withou -c, stdin piping of code) are on their way.

The initial idea come from CLIP OS 4 and the original implementation has
been used for more than 11 years:
https://github.com/clipos-archive/clipos4_doc

An introduction to O_MAYEXEC (original name of RESOLVE_MAYEXEC) was
given at the Linux Security Summit Europe 2018 - Linux Kernel Security
Contributions by ANSSI:
https://www.youtube.com/watch?v=chNjCRtPKQY&t=17m15s
The "write xor execute" principle was explained at Kernel Recipes 2018 -
CLIP OS: a defense-in-depth OS:
https://www.youtube.com/watch?v=PjRE0uBtkHU&t=11m14s

This patch series can be applied on top of v5.7-rc3.  This can be tested
with CONFIG_SYSCTL.  I would really appreciate constructive comments on
this patch series.

Previous version:
https://lore.kernel.org/lkml/20190906152455.22757-1-mic@digikod.net/


[1] https://lore.kernel.org/lkml/1544647356.4028.105.camel@linux.ibm.com/
[2] https://lore.kernel.org/lkml/20190904201933.10736-6-cyphar@cyphar.com/
[3] https://lore.kernel.org/lkml/CALCETrVovr8XNZSroey7pHF46O=kj_c5D9K8h=z2T_cNrpvMig@mail.gmail.com/
[4] https://lore.kernel.org/lkml/CALCETrVeZ0eufFXwfhtaG_j+AdvbzEWE0M3wjXMWVEO7pj+xkw@mail.gmail.com/
[5] https://lore.kernel.org/lkml/20200406221439.1469862-12-deven.desai@linux.microsoft.com/
[6] https://www.python.org/dev/peps/pep-0578/

Regards,

Mickaël Salaün (5):
  fs: Add support for a RESOLVE_MAYEXEC flag on openat2(2)
  fs: Add a MAY_EXECMOUNT flag to infer the noexec mount property
  fs: Enable to enforce noexec mounts or file exec through
    RESOLVE_MAYEXEC
  selftest/openat2: Add tests for RESOLVE_MAYEXEC enforcing
  doc: Add documentation for the fs.open_mayexec_enforce sysctl

 Documentation/admin-guide/sysctl/fs.rst       |  43 +++
 fs/namei.c                                    |  74 +++-
 fs/open.c                                     |   6 +
 include/linux/fcntl.h                         |   2 +-
 include/linux/fs.h                            |   7 +
 include/uapi/linux/openat2.h                  |   6 +
 kernel/sysctl.c                               |   7 +
 tools/testing/selftests/kselftest_harness.h   |   3 +
 tools/testing/selftests/openat2/Makefile      |   3 +-
 tools/testing/selftests/openat2/config        |   1 +
 tools/testing/selftests/openat2/helpers.h     |   3 +
 .../testing/selftests/openat2/omayexec_test.c | 315 ++++++++++++++++++
 12 files changed, 467 insertions(+), 3 deletions(-)
 create mode 100644 tools/testing/selftests/openat2/config
 create mode 100644 tools/testing/selftests/openat2/omayexec_test.c

-- 
2.26.2


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v3 1/5] fs: Add support for a RESOLVE_MAYEXEC flag on openat2(2)
  2020-04-28 17:51 [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC Mickaël Salaün
@ 2020-04-28 17:51 ` Mickaël Salaün
  2020-05-01  4:04   ` James Morris
  2020-04-28 17:51 ` [PATCH v3 2/5] fs: Add a MAY_EXECMOUNT flag to infer the noexec mount property Mickaël Salaün
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 23+ messages in thread
From: Mickaël Salaün @ 2020-04-28 17:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mickaël Salaün, Aleksa Sarai, Alexei Starovoitov,
	Al Viro, Andy Lutomirski, Christian Heimes, Daniel Borkmann,
	Deven Bowers, Eric Chiang, Florian Weimer, James Morris,
	Jan Kara, Jann Horn, Jonathan Corbet, Kees Cook, Matthew Garrett,
	Matthew Wilcox, Michael Kerrisk, Mickaël Salaün,
	Mimi Zohar, Philippe Trébuchet, Scott Shell,
	Sean Christopherson, Shuah Khan, Steve Dower, Steve Grubb,
	Thibaut Sautereau, Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel

When the RESOLVE_MAYEXEC flag is passed, openat2(2) may be subject to
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.

The underlying idea is to be able to restrict scripts interpretation
according to a policy defined by the system administrator.  For this to
be possible, script interpreters must use the RESOLVE_MAYEXEC flag
appropriately.  To be fully effective, these interpreters also need to
handle the other ways to execute code: command line parameters (e.g.,
option -e for Perl), module loading (e.g., option -m for Python), stdin,
file sourcing, environment variables, configuration files...  According
to the threat model, it may be acceptable to allow some script
interpreters (e.g. Bash) to interpret commands from stdin, may it be a
TTY or a pipe, because it may not be enough to (directly) perform
syscalls.  Further documentation can be found in a following patch.

A simple security policy implementation, configured through a dedicated
sysctl, is available in a following patch.

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 11 years with customized script
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

Signed-off-by: Mickaël Salaün <mic@digikod.net>
Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr>
Signed-off-by: Vincent Strubel <vincent.strubel@ssi.gouv.fr>
Cc: Aleksa Sarai <cyphar@cyphar.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Kees Cook <keescook@chromium.org>
---

Changes since v2:
* Replace O_MAYEXEC with RESOLVE_MAYEXEC from openat2(2).  This change
  enables to not break existing application using bogus O_* flags that
  may be ignored by current kernels by using a new dedicated flag, only
  usable through openat2(2) (suggested by Jeff Layton).  Using this flag
  will results in an error if the running kernel does not support it.
  User space needs to manage this case, as with other RESOLVE_* flags.
  The best effort approach to security (for most common distros) will
  simply consists of ignoring such an error and retry without
  RESOLVE_MAYEXEC.  However, a fully controlled system may which to
  error out if such an inconsistency is detected.

Changes since v1:
* Set __FMODE_EXEC when using O_MAYEXEC to make this information
  available through the new fanotify/FAN_OPEN_EXEC event (suggested by
  Jan Kara and Matthew Bobrowski).
---
 fs/open.c                    | 6 ++++++
 include/linux/fcntl.h        | 2 +-
 include/linux/fs.h           | 2 ++
 include/uapi/linux/openat2.h | 6 ++++++
 4 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/fs/open.c b/fs/open.c
index 719b320ede52..ca5a145761a2 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1029,6 +1029,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 (how->resolve & RESOLVE_MAYEXEC) {
+		acc_mode |= MAY_OPENEXEC;
+		flags |= __FMODE_EXEC;
+	}
+
 	op->open_flag = flags;
 
 	/* O_TRUNC implies we need access checks for write permissions */
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index 7bcdcf4f6ab2..a37e213220ad 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -19,7 +19,7 @@
 /* List of all valid flags for the how->resolve argument: */
 #define VALID_RESOLVE_FLAGS \
 	(RESOLVE_NO_XDEV | RESOLVE_NO_MAGICLINKS | RESOLVE_NO_SYMLINKS | \
-	 RESOLVE_BENEATH | RESOLVE_IN_ROOT)
+	 RESOLVE_BENEATH | RESOLVE_IN_ROOT | RESOLVE_MAYEXEC)
 
 /* List of all open_how "versions". */
 #define OPEN_HOW_SIZE_VER0	24 /* sizeof first published struct */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4f6f59b4f22a..f5be4be7c01d 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -101,6 +101,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 #define MAY_CHDIR		0x00000040
 /* called from RCU mode, don't block */
 #define MAY_NOT_BLOCK		0x00000080
+/* the inode is opened with RESOLVE_MAYEXEC */
+#define MAY_OPENEXEC		0x00000100
 
 /*
  * flags in file.f_mode.  Note that FMODE_READ and FMODE_WRITE must correspond
diff --git a/include/uapi/linux/openat2.h b/include/uapi/linux/openat2.h
index 58b1eb711360..86ed0a2321c3 100644
--- a/include/uapi/linux/openat2.h
+++ b/include/uapi/linux/openat2.h
@@ -35,5 +35,11 @@ struct open_how {
 #define RESOLVE_IN_ROOT		0x10 /* Make all jumps to "/" and ".."
 					be scoped inside the dirfd
 					(similar to chroot(2)). */
+#define RESOLVE_MAYEXEC		0x20 /* Code execution from the target file is
+					intended, checks such permission.  A
+					simple policy can be enforced
+					system-wide as explained in
+					Documentation/admin-guide/sysctl/fs.rst
+					*/
 
 #endif /* _UAPI_LINUX_OPENAT2_H */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 2/5] fs: Add a MAY_EXECMOUNT flag to infer the noexec mount property
  2020-04-28 17:51 [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC Mickaël Salaün
  2020-04-28 17:51 ` [PATCH v3 1/5] fs: Add support for a RESOLVE_MAYEXEC flag on openat2(2) Mickaël Salaün
@ 2020-04-28 17:51 ` Mickaël Salaün
  2020-05-01  4:02   ` James Morris
  2020-04-28 17:51 ` [PATCH v3 3/5] fs: Enable to enforce noexec mounts or file exec through RESOLVE_MAYEXEC Mickaël Salaün
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 23+ messages in thread
From: Mickaël Salaün @ 2020-04-28 17:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mickaël Salaün, Aleksa Sarai, Alexei Starovoitov,
	Al Viro, Andy Lutomirski, Christian Heimes, Daniel Borkmann,
	Deven Bowers, Eric Chiang, Florian Weimer, James Morris,
	Jan Kara, Jann Horn, Jonathan Corbet, Kees Cook, Matthew Garrett,
	Matthew Wilcox, Michael Kerrisk, Mickaël Salaün,
	Mimi Zohar, Philippe Trébuchet, Scott Shell,
	Sean Christopherson, Shuah Khan, Steve Dower, Steve Grubb,
	Thibaut Sautereau, Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel

An LSM doesn't get path information related to an access request to open
an inode.  This new (internal) MAY_EXECMOUNT flag enables an LSM to
check if the underlying mount point of an inode is marked as executable.
This is useful to implement a security policy taking advantage of the
noexec mount option.

This flag is set according to path_noexec(), which checks if a mount
point is mounted with MNT_NOEXEC or if the underlying superblock is
SB_I_NOEXEC.

Signed-off-by: Mickaël Salaün <mic@digikod.net>
Reviewed-by: Philippe Trébuchet <philippe.trebuchet@ssi.gouv.fr>
Reviewed-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr>
Cc: Aleksa Sarai <cyphar@cyphar.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Kees Cook <keescook@chromium.org>
---
 fs/namei.c         | 2 ++
 include/linux/fs.h | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/fs/namei.c b/fs/namei.c
index a320371899cf..33b6d372e74a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2849,6 +2849,8 @@ static int may_open(const struct path *path, int acc_mode, int flag)
 		break;
 	}
 
+	/* Pass the mount point executability. */
+	acc_mode |= path_noexec(path) ? 0 : MAY_EXECMOUNT;
 	error = inode_permission(inode, MAY_OPEN | acc_mode);
 	if (error)
 		return error;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f5be4be7c01d..9213147d8636 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -103,6 +103,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 #define MAY_NOT_BLOCK		0x00000080
 /* the inode is opened with RESOLVE_MAYEXEC */
 #define MAY_OPENEXEC		0x00000100
+/* the mount point is marked as executable */
+#define MAY_EXECMOUNT		0x00000200
 
 /*
  * flags in file.f_mode.  Note that FMODE_READ and FMODE_WRITE must correspond
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 3/5] fs: Enable to enforce noexec mounts or file exec through RESOLVE_MAYEXEC
  2020-04-28 17:51 [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC Mickaël Salaün
  2020-04-28 17:51 ` [PATCH v3 1/5] fs: Add support for a RESOLVE_MAYEXEC flag on openat2(2) Mickaël Salaün
  2020-04-28 17:51 ` [PATCH v3 2/5] fs: Add a MAY_EXECMOUNT flag to infer the noexec mount property Mickaël Salaün
@ 2020-04-28 17:51 ` Mickaël Salaün
  2020-05-01  4:22   ` James Morris
  2020-04-28 17:51 ` [PATCH v3 4/5] selftest/openat2: Add tests for RESOLVE_MAYEXEC enforcing Mickaël Salaün
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 23+ messages in thread
From: Mickaël Salaün @ 2020-04-28 17:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mickaël Salaün, Aleksa Sarai, Alexei Starovoitov,
	Al Viro, Andy Lutomirski, Christian Heimes, Daniel Borkmann,
	Deven Bowers, Eric Chiang, Florian Weimer, James Morris,
	Jan Kara, Jann Horn, Jonathan Corbet, Kees Cook, Matthew Garrett,
	Matthew Wilcox, Michael Kerrisk, Mickaël Salaün,
	Mimi Zohar, Philippe Trébuchet, Scott Shell,
	Sean Christopherson, Shuah Khan, Steve Dower, Steve Grubb,
	Thibaut Sautereau, Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel

Enable to either propagate the mount options from the underlying VFS
mount to prevent execution, or to propagate the file execute permission.
This may allow a script interpreter to check execution permissions
before reading commands from a file.

The main goal is to be able to protect the kernel by restricting
arbitrary syscalls that an attacker could perform with a crafted binary
or certain script languages.  It also improves multilevel isolation
by reducing the ability of an attacker to use side channels with
specific code.  These restrictions can natively be enforced for ELF
binaries (with the noexec mount option) but require this kernel
extension to properly handle scripts (e.g., Python, Perl).

Add a new sysctl fs.open_mayexec_enforce to control this behavior.
Indeed, because of compatibility with installed systems, only the system
administrator is able to check that this new enforcement is in line with
the system mount points and file permissions.  A following patch adds
documentation.

Signed-off-by: Mickaël Salaün <mic@digikod.net>
Reviewed-by: Philippe Trébuchet <philippe.trebuchet@ssi.gouv.fr>
Reviewed-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr>
Cc: Aleksa Sarai <cyphar@cyphar.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Kees Cook <keescook@chromium.org>
---

Changes since v2:
* Cosmetic changes.

Changes since v1:
* Move code from Yama to the FS subsystem (suggested by Kees Cook).
* Make omayexec_inode_permission() static (suggested by Jann Horn).
* Use mode 0600 for the sysctl.
* Only match regular files (not directories nor other types), which
  follows the same semantic as commit 73601ea5b7b1 ("fs/open.c: allow
  opening only regular files during execve()").
---
 fs/namei.c         | 72 +++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/fs.h |  3 ++
 kernel/sysctl.c    |  7 +++++
 3 files changed, 81 insertions(+), 1 deletion(-)

diff --git a/fs/namei.c b/fs/namei.c
index 33b6d372e74a..dbf56de1fbe8 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -39,6 +39,7 @@
 #include <linux/bitops.h>
 #include <linux/init_task.h>
 #include <linux/uaccess.h>
+#include <linux/sysctl.h>
 
 #include "internal.h"
 #include "mount.h"
@@ -411,10 +412,40 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
 	return 0;
 }
 
+#define OMAYEXEC_ENFORCE_NONE	0
+#define OMAYEXEC_ENFORCE_MOUNT	(1 << 0)
+#define OMAYEXEC_ENFORCE_FILE	(1 << 1)
+#define _OMAYEXEC_LAST		OMAYEXEC_ENFORCE_FILE
+#define _OMAYEXEC_MASK		((_OMAYEXEC_LAST << 1) - 1)
+
+/**
+ * omayexec_inode_permission - Check RESOLVE_MAYEXEC before accessing an inode
+ *
+ * @inode: Inode to check permission on
+ * @mask: Right to check for (%MAY_OPENEXEC, %MAY_EXECMOUNT, %MAY_EXEC)
+ *
+ * Returns 0 if access is permitted, -EACCES otherwise.
+ */
+static inline int omayexec_inode_permission(struct inode *inode, int mask)
+{
+	if (!(mask & MAY_OPENEXEC))
+		return 0;
+
+	if ((sysctl_omayexec_enforce & OMAYEXEC_ENFORCE_MOUNT) &&
+			!(mask & MAY_EXECMOUNT))
+		return -EACCES;
+
+	if (sysctl_omayexec_enforce & OMAYEXEC_ENFORCE_FILE)
+		return generic_permission(inode, MAY_EXEC);
+
+	return 0;
+}
+
 /**
  * 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,
+ *        %MAY_EXECMOUNT)
  *
  * 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
@@ -454,10 +485,48 @@ int inode_permission(struct inode *inode, int mask)
 	if (retval)
 		return retval;
 
+	retval = omayexec_inode_permission(inode, mask);
+	if (retval)
+		return retval;
+
 	return security_inode_permission(inode, mask);
 }
 EXPORT_SYMBOL(inode_permission);
 
+/*
+ * Handle open_mayexec_enforce sysctl
+ */
+#ifdef CONFIG_SYSCTL
+int proc_omayexec(struct ctl_table *table, int write, void __user *buffer,
+		size_t *lenp, loff_t *ppos)
+{
+	int error;
+
+	if (write) {
+		struct ctl_table table_copy;
+		int tmp_mayexec_enforce;
+
+		if (!capable(CAP_MAC_ADMIN))
+			return -EPERM;
+		tmp_mayexec_enforce = *((int *)table->data);
+		table_copy = *table;
+		/* Do not erase sysctl_omayexec_enforce. */
+		table_copy.data = &tmp_mayexec_enforce;
+		error = proc_dointvec(&table_copy, write, buffer, lenp, ppos);
+		if (error)
+			return error;
+		if ((tmp_mayexec_enforce | _OMAYEXEC_MASK) != _OMAYEXEC_MASK)
+			return -EINVAL;
+		*((int *)table->data) = tmp_mayexec_enforce;
+	} else {
+		error = proc_dointvec(table, write, buffer, lenp, ppos);
+		if (error)
+			return error;
+	}
+	return 0;
+}
+#endif
+
 /**
  * path_get - get a reference to a path
  * @path: path to get the reference to
@@ -922,6 +991,7 @@ int sysctl_protected_symlinks __read_mostly = 0;
 int sysctl_protected_hardlinks __read_mostly = 0;
 int sysctl_protected_fifos __read_mostly;
 int sysctl_protected_regular __read_mostly;
+int sysctl_omayexec_enforce __read_mostly = OMAYEXEC_ENFORCE_NONE;
 
 /**
  * may_follow_link - Check symlink following for unsafe situations
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 9213147d8636..850c98276b6e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -83,6 +83,7 @@ extern int sysctl_protected_symlinks;
 extern int sysctl_protected_hardlinks;
 extern int sysctl_protected_fifos;
 extern int sysctl_protected_regular;
+extern int sysctl_omayexec_enforce;
 
 typedef __kernel_rwf_t rwf_t;
 
@@ -3545,6 +3546,8 @@ int proc_nr_dentry(struct ctl_table *table, int write,
 		  void __user *buffer, size_t *lenp, loff_t *ppos);
 int proc_nr_inodes(struct ctl_table *table, int write,
 		   void __user *buffer, size_t *lenp, loff_t *ppos);
+int proc_omayexec(struct ctl_table *table, int write, void __user *buffer,
+		size_t *lenp, loff_t *ppos);
 int __init get_filesystem_list(char *buf);
 
 #define __FMODE_EXEC		((__force int) FMODE_EXEC)
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 8a176d8727a3..911afa69f84c 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1892,6 +1892,13 @@ static struct ctl_table fs_table[] = {
 		.extra1		= SYSCTL_ZERO,
 		.extra2		= &two,
 	},
+	{
+		.procname       = "open_mayexec_enforce",
+		.data           = &sysctl_omayexec_enforce,
+		.maxlen         = sizeof(int),
+		.mode           = 0600,
+		.proc_handler   = proc_omayexec,
+	},
 #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE)
 	{
 		.procname	= "binfmt_misc",
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 4/5] selftest/openat2: Add tests for RESOLVE_MAYEXEC enforcing
  2020-04-28 17:51 [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC Mickaël Salaün
                   ` (2 preceding siblings ...)
  2020-04-28 17:51 ` [PATCH v3 3/5] fs: Enable to enforce noexec mounts or file exec through RESOLVE_MAYEXEC Mickaël Salaün
@ 2020-04-28 17:51 ` Mickaël Salaün
  2020-04-28 17:51 ` [PATCH v3 5/5] doc: Add documentation for the fs.open_mayexec_enforce sysctl Mickaël Salaün
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 23+ messages in thread
From: Mickaël Salaün @ 2020-04-28 17:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mickaël Salaün, Aleksa Sarai, Alexei Starovoitov,
	Al Viro, Andy Lutomirski, Christian Heimes, Daniel Borkmann,
	Deven Bowers, Eric Chiang, Florian Weimer, James Morris,
	Jan Kara, Jann Horn, Jonathan Corbet, Kees Cook, Matthew Garrett,
	Matthew Wilcox, Michael Kerrisk, Mickaël Salaün,
	Mimi Zohar, Philippe Trébuchet, Scott Shell,
	Sean Christopherson, Shuah Khan, Steve Dower, Steve Grubb,
	Thibaut Sautereau, Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel

Test propagation of noexec mount points or file executability through
files open with or without RESOLVE_MAYEXEC.

Signed-off-by: Mickaël Salaün <mic@digikod.net>
Reviewed-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr>
Cc: Aleksa Sarai <cyphar@cyphar.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Kees Cook <keescook@chromium.org>
Cc: Shuah Khan <shuah@kernel.org>
---

Changes since v2:
* Move tests from exec/ to openat2/ .
* Replace O_MAYEXEC with RESOLVE_MAYEXEC from openat2(2).
* Cleanup tests.

Changes since v1:
* Move tests from yama/ to exec/ .
* Fix _GNU_SOURCE in kselftest_harness.h .
* Add a new test sysctl_access_write to check if CAP_MAC_ADMIN is taken
  into account.
* Test directory execution which is always forbidden since commit
  73601ea5b7b1 ("fs/open.c: allow opening only regular files during
  execve()"), and also check that even the root user can not bypass file
  execution checks.
* Make sure delete_workspace() always as enough right to succeed.
* Cosmetic cleanup.
---
 tools/testing/selftests/kselftest_harness.h   |   3 +
 tools/testing/selftests/openat2/Makefile      |   3 +-
 tools/testing/selftests/openat2/config        |   1 +
 tools/testing/selftests/openat2/helpers.h     |   3 +
 .../testing/selftests/openat2/omayexec_test.c | 315 ++++++++++++++++++
 5 files changed, 324 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/openat2/config
 create mode 100644 tools/testing/selftests/openat2/omayexec_test.c

diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h
index 2bb8c81fc0b4..f6e056ba4a13 100644
--- a/tools/testing/selftests/kselftest_harness.h
+++ b/tools/testing/selftests/kselftest_harness.h
@@ -50,7 +50,10 @@
 #ifndef __KSELFTEST_HARNESS_H
 #define __KSELFTEST_HARNESS_H
 
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
+
 #include <asm/types.h>
 #include <errno.h>
 #include <stdbool.h>
diff --git a/tools/testing/selftests/openat2/Makefile b/tools/testing/selftests/openat2/Makefile
index 4b93b1417b86..cb98bdb4d5b1 100644
--- a/tools/testing/selftests/openat2/Makefile
+++ b/tools/testing/selftests/openat2/Makefile
@@ -1,7 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 
 CFLAGS += -Wall -O2 -g -fsanitize=address -fsanitize=undefined
-TEST_GEN_PROGS := openat2_test resolve_test rename_attack_test
+LDLIBS += -lcap
+TEST_GEN_PROGS := openat2_test resolve_test rename_attack_test omayexec_test
 
 include ../lib.mk
 
diff --git a/tools/testing/selftests/openat2/config b/tools/testing/selftests/openat2/config
new file mode 100644
index 000000000000..dd53c266bf52
--- /dev/null
+++ b/tools/testing/selftests/openat2/config
@@ -0,0 +1 @@
+CONFIG_SYSCTL=y
diff --git a/tools/testing/selftests/openat2/helpers.h b/tools/testing/selftests/openat2/helpers.h
index a6ea27344db2..2a46d5446110 100644
--- a/tools/testing/selftests/openat2/helpers.h
+++ b/tools/testing/selftests/openat2/helpers.h
@@ -9,6 +9,7 @@
 
 #define _GNU_SOURCE
 #include <stdint.h>
+#include <stdbool.h>
 #include <errno.h>
 #include <linux/types.h>
 #include "../kselftest.h"
@@ -60,6 +61,8 @@ bool needs_openat2(const struct open_how *how);
 #define RESOLVE_IN_ROOT		0x10 /* Make all jumps to "/" and ".."
 					be scoped inside the dirfd
 					(similar to chroot(2)). */
+#define RESOLVE_MAYEXEC		0x20 /* Command execution from file is
+					intended, checks exec permissions. */
 #endif /* RESOLVE_IN_ROOT */
 
 #define E_func(func, ...)						\
diff --git a/tools/testing/selftests/openat2/omayexec_test.c b/tools/testing/selftests/openat2/omayexec_test.c
new file mode 100644
index 000000000000..5298cbd5b7e9
--- /dev/null
+++ b/tools/testing/selftests/openat2/omayexec_test.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test openat2(2) with RESOLVE_MAYEXEC
+ *
+ * Copyright © 2018-2020 ANSSI
+ *
+ * Author: Mickaël Salaün <mic@digikod.net>
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "helpers.h"
+#include "../kselftest_harness.h"
+
+#define SYSCTL_MAYEXEC	"/proc/sys/fs/open_mayexec_enforce"
+
+#define BIN_DIR		"./test-mount"
+#define BIN_PATH	BIN_DIR "/file"
+#define DIR_PATH	BIN_DIR "/directory"
+
+#define ALLOWED		1
+#define DENIED		0
+
+static void ignore_dac(struct __test_metadata *_metadata, int override)
+{
+	cap_t caps;
+	const cap_value_t cap_val[2] = {
+		CAP_DAC_OVERRIDE,
+		CAP_DAC_READ_SEARCH,
+	};
+
+	caps = cap_get_proc();
+	ASSERT_NE(NULL, caps);
+	ASSERT_EQ(0, cap_set_flag(caps, CAP_EFFECTIVE, 2, cap_val,
+				override ? CAP_SET : CAP_CLEAR));
+	ASSERT_EQ(0, cap_set_proc(caps));
+	EXPECT_EQ(0, cap_free(caps));
+}
+
+static void ignore_mac(struct __test_metadata *_metadata, int override)
+{
+	cap_t caps;
+	const cap_value_t cap_val[1] = {
+		CAP_MAC_ADMIN,
+	};
+
+	caps = cap_get_proc();
+	ASSERT_NE(NULL, caps);
+	ASSERT_EQ(0, cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_val,
+				override ? CAP_SET : CAP_CLEAR));
+	ASSERT_EQ(0, cap_set_proc(caps));
+	EXPECT_EQ(0, cap_free(caps));
+}
+
+static void test_omx(struct __test_metadata *_metadata,
+		const char *const path, const int exec_allowed)
+{
+	struct open_how how = {
+		.flags = O_RDONLY | O_CLOEXEC,
+	};
+	int fd;
+
+	/* Opens without MAYEXEC. */
+	fd = sys_openat2(AT_FDCWD, path, &how);
+	ASSERT_LE(0, fd);
+	EXPECT_EQ(0, close(fd));
+
+	/* Opens with MAYEXEC. */
+	how.resolve = RESOLVE_MAYEXEC;
+	fd = sys_openat2(AT_FDCWD, path, &how);
+	if (exec_allowed) {
+		ASSERT_LE(0, fd);
+		EXPECT_EQ(0, close(fd));
+	} else {
+		ASSERT_EQ(-EACCES, fd);
+	}
+}
+
+static void test_omx_dir_file(struct __test_metadata *_metadata,
+		const char *const dir_path, const char *const file_path,
+		const int exec_allowed)
+{
+	/*
+	 * Directory execution is always denied since commit 73601ea5b7b1
+	 * ("fs/open.c: allow opening only regular files during execve()").
+	 */
+	test_omx(_metadata, dir_path, DENIED);
+	test_omx(_metadata, file_path, exec_allowed);
+}
+
+static void test_dir_file(struct __test_metadata *_metadata,
+		const char *const dir_path, const char *const file_path,
+		const int exec_allowed)
+{
+	/* Tests as root. */
+	ignore_dac(_metadata, 1);
+	test_omx_dir_file(_metadata, dir_path, file_path, exec_allowed);
+
+	/* Tests without bypass. */
+	ignore_dac(_metadata, 0);
+	test_omx_dir_file(_metadata, dir_path, file_path, exec_allowed);
+}
+
+static void sysctl_write(struct __test_metadata *_metadata,
+		const char *path, const char *value)
+{
+	int fd;
+	size_t len_value;
+	ssize_t len_wrote;
+
+	fd = open(path, O_WRONLY | O_CLOEXEC);
+	ASSERT_LE(0, fd);
+	len_value = strlen(value);
+	len_wrote = write(fd, value, len_value);
+	ASSERT_EQ(len_wrote, len_value);
+	EXPECT_EQ(0, close(fd));
+}
+
+static void create_workspace(struct __test_metadata *_metadata,
+		int mount_exec, int file_exec)
+{
+	int fd;
+
+	/*
+	 * Cleans previous workspace if any error previously happened (don't
+	 * check errors).
+	 */
+	umount(BIN_DIR);
+	rmdir(BIN_DIR);
+
+	/* Creates a clean mount point. */
+	ASSERT_EQ(0, mkdir(BIN_DIR, 00700));
+	ASSERT_EQ(0, mount("test", BIN_DIR, "tmpfs",
+				MS_MGC_VAL | (mount_exec ? 0 : MS_NOEXEC),
+				"mode=0700,size=4k"));
+
+	/* Creates a test file. */
+	fd = open(BIN_PATH, O_CREAT | O_RDONLY | O_CLOEXEC,
+			file_exec ? 00500 : 00400);
+	ASSERT_LE(0, fd);
+	EXPECT_EQ(0, close(fd));
+
+	/* Creates a test directory. */
+	ASSERT_EQ(0, mkdir(DIR_PATH, file_exec ? 00500 : 00400));
+}
+
+static void delete_workspace(struct __test_metadata *_metadata)
+{
+	ignore_mac(_metadata, 1);
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "0");
+
+	/* There is no need to unlink BIN_PATH nor DIR_PATH. */
+	ASSERT_EQ(0, umount(BIN_DIR));
+	ASSERT_EQ(0, rmdir(BIN_DIR));
+}
+
+FIXTURE_DATA(mount_exec_file_exec) { };
+
+FIXTURE_SETUP(mount_exec_file_exec)
+{
+	create_workspace(_metadata, 1, 1);
+}
+
+FIXTURE_TEARDOWN(mount_exec_file_exec)
+{
+	delete_workspace(_metadata);
+}
+
+TEST_F(mount_exec_file_exec, mount)
+{
+	/* Enforces mount exec check. */
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "1");
+	test_dir_file(_metadata, DIR_PATH, BIN_PATH, ALLOWED);
+}
+
+TEST_F(mount_exec_file_exec, file)
+{
+	/* Enforces file exec check. */
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "2");
+	test_dir_file(_metadata, DIR_PATH, BIN_PATH, ALLOWED);
+}
+
+TEST_F(mount_exec_file_exec, mount_file)
+{
+	/* Enforces mount and file exec check. */
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "3");
+	test_dir_file(_metadata, DIR_PATH, BIN_PATH, ALLOWED);
+}
+
+FIXTURE_DATA(mount_exec_file_noexec) { };
+
+FIXTURE_SETUP(mount_exec_file_noexec)
+{
+	create_workspace(_metadata, 1, 0);
+}
+
+FIXTURE_TEARDOWN(mount_exec_file_noexec)
+{
+	delete_workspace(_metadata);
+}
+
+TEST_F(mount_exec_file_noexec, mount)
+{
+	/* Enforces mount exec check. */
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "1");
+	test_dir_file(_metadata, DIR_PATH, BIN_PATH, ALLOWED);
+}
+
+TEST_F(mount_exec_file_noexec, file)
+{
+	/* Enforces file exec check. */
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "2");
+	test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED);
+}
+
+TEST_F(mount_exec_file_noexec, mount_file)
+{
+	/* Enforces mount and file exec check. */
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "3");
+	test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED);
+}
+
+FIXTURE_DATA(mount_noexec_file_exec) { };
+
+FIXTURE_SETUP(mount_noexec_file_exec)
+{
+	create_workspace(_metadata, 0, 1);
+}
+
+FIXTURE_TEARDOWN(mount_noexec_file_exec)
+{
+	delete_workspace(_metadata);
+}
+
+TEST_F(mount_noexec_file_exec, mount)
+{
+	/* Enforces mount exec check. */
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "1");
+	test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED);
+}
+
+TEST_F(mount_noexec_file_exec, file)
+{
+	/* Enforces file exec check. */
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "2");
+	test_dir_file(_metadata, DIR_PATH, BIN_PATH, ALLOWED);
+}
+
+TEST_F(mount_noexec_file_exec, mount_file)
+{
+	/* Enforces mount and file exec check. */
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "3");
+	test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED);
+}
+
+FIXTURE_DATA(mount_noexec_file_noexec) { };
+
+FIXTURE_SETUP(mount_noexec_file_noexec)
+{
+	create_workspace(_metadata, 0, 0);
+}
+
+FIXTURE_TEARDOWN(mount_noexec_file_noexec)
+{
+	delete_workspace(_metadata);
+}
+
+TEST_F(mount_noexec_file_noexec, mount)
+{
+	/* Enforces mount exec check. */
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "1");
+	test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED);
+}
+
+TEST_F(mount_noexec_file_noexec, file)
+{
+	/* Enforces file exec check. */
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "2");
+	test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED);
+}
+
+TEST_F(mount_noexec_file_noexec, mount_file)
+{
+	/* Enforces mount and file exec check. */
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "3");
+	test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED);
+}
+
+TEST(sysctl_access_write)
+{
+	int fd;
+	ssize_t len_wrote;
+
+	ignore_mac(_metadata, 1);
+	sysctl_write(_metadata, SYSCTL_MAYEXEC, "0");
+
+	ignore_mac(_metadata, 0);
+	fd = open(SYSCTL_MAYEXEC, O_WRONLY | O_CLOEXEC);
+	ASSERT_LE(0, fd);
+	len_wrote = write(fd, "0", 1);
+	ASSERT_EQ(len_wrote, -1);
+	EXPECT_EQ(0, close(fd));
+
+	ignore_mac(_metadata, 1);
+}
+
+TEST_HARNESS_MAIN
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 5/5] doc: Add documentation for the fs.open_mayexec_enforce sysctl
  2020-04-28 17:51 [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC Mickaël Salaün
                   ` (3 preceding siblings ...)
  2020-04-28 17:51 ` [PATCH v3 4/5] selftest/openat2: Add tests for RESOLVE_MAYEXEC enforcing Mickaël Salaün
@ 2020-04-28 17:51 ` Mickaël Salaün
  2020-04-28 19:21 ` [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC Jann Horn
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 23+ messages in thread
From: Mickaël Salaün @ 2020-04-28 17:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mickaël Salaün, Aleksa Sarai, Alexei Starovoitov,
	Al Viro, Andy Lutomirski, Christian Heimes, Daniel Borkmann,
	Deven Bowers, Eric Chiang, Florian Weimer, James Morris,
	Jan Kara, Jann Horn, Jonathan Corbet, Kees Cook, Matthew Garrett,
	Matthew Wilcox, Michael Kerrisk, Mickaël Salaün,
	Mimi Zohar, Philippe Trébuchet, Scott Shell,
	Sean Christopherson, Shuah Khan, Steve Dower, Steve Grubb,
	Thibaut Sautereau, Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel

Signed-off-by: Mickaël Salaün <mic@digikod.net>
Reviewed-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr>
Cc: Aleksa Sarai <cyphar@cyphar.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Kees Cook <keescook@chromium.org>
---

Changes since v2:
* Update documentation with the new RESOLVE_MAYEXEC.
* Improve explanations, including concerns about LD_PRELOAD.

Changes since v1:
* Move from LSM/Yama to sysctl/fs .
---
 Documentation/admin-guide/sysctl/fs.rst | 43 +++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/Documentation/admin-guide/sysctl/fs.rst b/Documentation/admin-guide/sysctl/fs.rst
index 2a45119e3331..1ed65a38d5fb 100644
--- a/Documentation/admin-guide/sysctl/fs.rst
+++ b/Documentation/admin-guide/sysctl/fs.rst
@@ -37,6 +37,7 @@ Currently, these files are in /proc/sys/fs:
 - inode-nr
 - inode-state
 - nr_open
+- open_mayexec_enforce
 - overflowuid
 - overflowgid
 - pipe-user-pages-hard
@@ -165,6 +166,48 @@ system needs to prune the inode list instead of allocating
 more.
 
 
+open_mayexec_enforce
+--------------------
+
+The ``RESOLVE_MAYEXEC`` flag can be passed to :manpage:`openat2(2)` to only
+open regular files that are expected to be executable.  If the file is not
+identified as executable, then the syscall returns -EACCES.  This may allow a
+script interpreter to check executable permission before reading commands from
+a file.  One interesting use case is to enforce a "write xor execute" policy
+through interpreters.
+
+The ability to restrict code execution must be thought as a system-wide policy,
+which first starts by restricting mount points with the ``noexec`` option.
+This option is also automatically applied to special filesystems such as /proc
+.  This prevents files on such mount points to be directly executed by the
+kernel or mapped as executable memory (e.g. libraries).  With script
+interpreters using the ``RESOLVE_MAYEXEC`` flag, the executable permission can
+then be checked before reading commands from files. This makes it possible to
+enforce the ``noexec`` at the interpreter level, and thus propagates this
+security policy to scripts.  To be fully effective, these interpreters also
+need to handle the other ways to execute code: command line parameters (e.g.,
+option ``-e`` for Perl), module loading (e.g., option ``-m`` for Python),
+stdin, file sourcing, environment variables, configuration files, etc.
+According to the threat model, it may be acceptable to allow some script
+interpreters (e.g. Bash) to interpret commands from stdin, may it be a TTY or a
+pipe, because it may not be enough to (directly) perform syscalls.
+
+There are two complementary security policies: enforce the ``noexec`` mount
+option, and enforce executable file permission.  These policies are handled by
+the ``fs.open_mayexec_enforce`` sysctl (writable only with ``CAP_MAC_ADMIN``)
+as a bitmask:
+
+1 - Mount restriction: checks that the mount options for the underlying VFS
+    mount do not prevent execution.
+
+2 - File permission restriction: checks that the to-be-opened file is marked as
+    executable for the current process (e.g., POSIX permissions).
+
+Code samples can be found in tools/testing/selftests/openat2/omayexec_test.c
+and (with the original ``O_MAYEXEC``) at
+https://github.com/clipos-archive/clipos4_portage-overlay/search?q=O_MAYEXEC .
+
+
 overflowgid & overflowuid
 -------------------------
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC
  2020-04-28 17:51 [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC Mickaël Salaün
                   ` (4 preceding siblings ...)
  2020-04-28 17:51 ` [PATCH v3 5/5] doc: Add documentation for the fs.open_mayexec_enforce sysctl Mickaël Salaün
@ 2020-04-28 19:21 ` Jann Horn
  2020-04-28 21:20   ` Florian Weimer
  2020-04-30  1:54 ` Aleksa Sarai
  2020-05-01  3:53 ` James Morris
  7 siblings, 1 reply; 23+ messages in thread
From: Jann Horn @ 2020-04-28 19:21 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: kernel list, Aleksa Sarai, Alexei Starovoitov, Al Viro,
	Andy Lutomirski, Christian Heimes, Daniel Borkmann, Deven Bowers,
	Eric Chiang, Florian Weimer, James Morris, Jan Kara,
	Jonathan Corbet, Kees Cook, Matthew Garrett, Matthew Wilcox,
	Michael Kerrisk, Mickaël Salaün, Mimi Zohar,
	Philippe Trébuchet, Scott Shell, Sean Christopherson,
	Shuah Khan, Steve Dower, Steve Grubb, Thibaut Sautereau,
	Vincent Strubel, Kernel Hardening, Linux API,
	linux-security-module, linux-fsdevel

On Tue, Apr 28, 2020 at 7:51 PM Mickaël Salaün <mic@digikod.net> wrote:
> The goal of this patch series is to enable to control script execution
> with interpreters help.  A new RESOLVE_MAYEXEC flag, usable through
> openat2(2), is added to enable userspace script interpreter to delegate
> to the kernel (and thus the system security policy) the permission to
> interpret/execute scripts or other files containing what can be seen as
> commands.
>
> This third patch series mainly differ from the previous one by relying
> on the new openat2(2) system call to get rid of the undefined behavior
> of the open(2) flags.  Thus, the previous O_MAYEXEC flag is now replaced
> with the new RESOLVE_MAYEXEC flag and benefits from the openat2(2)
> strict check of this kind of flags.
>
> A simple system-wide security policy can be enforced by the system
> administrator through a sysctl configuration consistent with the mount
> points or the file access rights.  The documentation patch explains the
> prerequisites.
>
> Furthermore, the security policy can also be delegated to an LSM, either
> a MAC system or an integrity system.  For instance, the new kernel
> MAY_OPENEXEC flag closes a major IMA measurement/appraisal interpreter
> integrity gap by bringing the ability to check the use of scripts [1].
> Other uses are expected, such as for openat2(2) [2], SGX integration
> [3], bpffs [4] or IPE [5].
>
> Userspace needs to adapt to take advantage of this new feature.  For
> example, the PEP 578 [6] (Runtime Audit Hooks) enables Python 3.8 to be
> extended with policy enforcement points related to code interpretation,
> which can be used to align with the PowerShell audit features.
> Additional Python security improvements (e.g. a limited interpreter
> withou -c, stdin piping of code) are on their way.
>
> The initial idea come from CLIP OS 4 and the original implementation has
> been used for more than 11 years:
> https://github.com/clipos-archive/clipos4_doc
>
> An introduction to O_MAYEXEC (original name of RESOLVE_MAYEXEC) was
> given at the Linux Security Summit Europe 2018 - Linux Kernel Security
> Contributions by ANSSI:
> https://www.youtube.com/watch?v=chNjCRtPKQY&t=17m15s
> The "write xor execute" principle was explained at Kernel Recipes 2018 -
> CLIP OS: a defense-in-depth OS:
> https://www.youtube.com/watch?v=PjRE0uBtkHU&t=11m14s
>
> This patch series can be applied on top of v5.7-rc3.  This can be tested
> with CONFIG_SYSCTL.  I would really appreciate constructive comments on
> this patch series.

Just as a comment: You'd probably also have to use RESOLVE_MAYEXEC in
the dynamic linker. A while back, I wrote a proof-of-concept ELF
library that can execute arbitrary code without triggering IMA because
it has no executable segments - instead it uses init_array to directly
trigger code execution at a JOP gadget in libc that then uses
mprotect() to make the code executable. I tested this on Debian
Stretch back in 2018.

=============================
user@debian:~/ima_stuff$ cat make_segments_rw.c
#include <stdlib.h>
#include <fcntl.h>
#include <err.h>
#include <elf.h>
#include <sys/mman.h>
#include <sys/stat.h>

int main(int argc, char **argv) {
        int fd = open(argv[1], O_RDWR);
        if (fd == -1) err(1, "open");
        struct stat st;
        if (fstat(fd, &st)) err(1, "stat");
        unsigned char *mapping = mmap(NULL, st.st_size,
PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        if (mapping == MAP_FAILED) err(1, "mmap");
        Elf64_Ehdr *ehdr = (void*)mapping;
        Elf64_Phdr *phdrs = (void*)(mapping + ehdr->e_phoff);

        for (int i=0; i<ehdr->e_phnum; i++) {
                phdrs[i].p_flags &= ~PF_X;
                phdrs[i].p_flags |= PF_W;
        }

        return 0;
}
user@debian:~/ima_stuff$ cat test.s
        .text
        .section        .text.startup,"aw",@progbits
        .globl  foobar
        .align 4096
foobar:
        /* alignment for xmm stuff in libc */
        sub     $8, %rsp
        call    getpid
        mov     %rax, %rsi
        leaq    message(%rip), %rdi
        call    printf
        movq    stdout_indir(%rip), %rdi
        movq    (%rdi), %rdi
        call fflush
        xor     %edi, %edi
        call    _exit

        .section        .init_array,"aw"
        .align 8
        .quad   rmdir+0x774

        .section        .fini_array,"aw"
        .quad   0xdeadbeef
        .quad   0xdeadbeef
        .quad   0xdeadbeef
        .quad   ucontext_data /* goes into rdi */
        .quad   0xdeadbeef
        .quad   0xdeadbeef
        .quad   0xdeadbeef
        .quad   0xdeadbeef
        .quad   setcontext+0x35 /* call target */

        .data
ucontext_data:
        /* 0x00 */
        .quad 0xdeadbeefdeadbeef, 0xdeadbeefdeadbeef
        .quad 0xdeadbeefdeadbeef, 0xdeadbeefdeadbeef
        .quad 0xdeadbeefdeadbeef, 0xdeadbeefdeadbeef
        .quad 0xdeadbeefdeadbeef, 0xdeadbeefdeadbeef
        /* 0x40 */
        .quad 0xdeadbeefdeadbeef, 0xdeadbeefdeadbeef
        .quad 0xdeadbeefdeadbeef, 0xdeadbeefdeadbeef
        .quad 0xdeadbeefdeadbeef, foobar
        .quad             0x1000, 0xdeadbeefdeadbeef
        /* 0x80 */
        .quad 0xdeadbeefdeadbeef, 0x7
        .quad 0xdeadbeefdeadbeef, 0xdeadbeefdeadbeef
        .quad stack_end, mprotect

        /* my stack */
        .fill 0x10000, 1, 0x42
stack_end:
        .quad foobar
message:
        .string "hello world from PID %d\n"
stdout_indir:
        .quad stdout
user@debian:~/ima_stuff$ gcc -o make_segments_rw make_segments_rw.c
user@debian:~/ima_stuff$ as -o test.o test.s
test.s: Assembler messages:
test.s:2: Warning: setting incorrect section attributes for .text.startup
user@debian:~/ima_stuff$ ld -shared -znorelro -o test.so test.o
user@debian:~/ima_stuff$ ./make_segments_rw test.so
user@debian:~/ima_stuff$ LD_PRELOAD=./test.so /bin/echo
hello world from PID 1053
user@debian:~/ima_stuff$ sudo tail
/sys/kernel/security/ima/runtime_measurements_count
1182
user@debian:~/ima_stuff$ sudo tail /sys/kernel/security/ima/runtime_measurements
tail: cannot open '/sys/kernel/security/ima/runtime_measurements' for
reading: No such file or directory
user@debian:~/ima_stuff$ sudo tail
/sys/kernel/security/ima/ascii_runtime_measurements
10 2435d24127ce5bcfbe776589ac86bc85530da07d ima-ng
sha256:ae35ddf5dbbef6ea31e8b87326001d12a6b4ec479bb8195b874d733d69ed1a4d
/usr/bin/x86_64-linux-gnu-gcc-6
10 f3ed20073a77fbc020d2807ce12ffc4cdbced976 ima-ng
sha256:65af5a9ea7ce00be9b921d4b13f5224c2369451eb918d4fa7721442283545957
/usr/bin/x86_64-linux-gnu-g++-6
10 25f0128e89a730a6f1cdd42d8de71d3db2625c9e ima-ng
sha256:d5d7e609b95939d0ae9f75a953d5cda4f1d8b9e4c1db98aeee7f792028bf026e
/usr/bin/x86_64-linux-gnu-as
10 51cf269a0008ab8173c7a696bee11be86a0bbd45 ima-ng
sha256:2d10a4e221ef8454b635f1ec646e6f4ff7f3db8e2e59b489c642758b2624a659
/usr/lib/x86_64-linux-gnu/libopcodes-2.28-system.so
10 b5c1db60c50722e1af84b83b34c0adb04b98d040 ima-ng
sha256:d3eef29b5b5bfc12999c5dbcc91029302477b70c7599aeb6b564140a336ab00b
/usr/lib/x86_64-linux-gnu/libbfd-2.28-system.so
10 6364d50cdac1733b7fd5dcfd9df124d1e4362a12 ima-ng
sha256:30c26e4b3cbd0677b2a23d09a72989002af138be57d301ed529c91b88427098f
/usr/lib/gcc/x86_64-linux-gnu/6/collect2
10 2a8c7ddacee57967e8a00ee1a522b552e29f559f ima-ng
sha256:a7b6287a8095701713e9ee7a886cae1f1ceefd0ce9c45dcc38719af563200964
/usr/bin/x86_64-linux-gnu-ld.bfd
10 e55a9c15349e2271cbdfe2f4fe36cd5b4070d3d0 ima-ng
sha256:b31674ad141a40eb2603f20400cc0dea4ee32ecf87771df3d039f16aae60ee26
/usr/lib/gcc/x86_64-linux-gnu/6/liblto_plugin.so.0.0.0
10 617aab630be74cd5bb7d830a727fd29cda361743 ima-ng
sha256:40fbf6acd3182d7a1ad158cd4de48da704bfe84f468d7b58dd557db93fe8a34c
/usr/bin/vim.basic
10 2c1fe398ecc0a8db6651621715d60a7e1b1958dc ima-ng
sha256:8523b422a01af773eff76b981c763cf0c739ea3030e592bb4d4f7854e295c418
/home/user/ima_stuff/make_segments_rw
user@debian:~/ima_stuff$
=============================

When looking at the syscalls the process is making, you can see that
it indeed never calls mmap() with PROT_EXEC on the library (I use
mprotect() to make my code executable, but IMA doesn't use the
mprotect security hook):

=============================
user@debian:~/ima_stuff$ strace -E LD_PRELOAD=./test.so /bin/echo
execve("/bin/echo", ["/bin/echo"], [/* 44 vars */]) = 0
brk(NULL)                               = 0x5642c52bc000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0x7fb83e817000
open("./test.so", O_RDONLY|O_CLOEXEC)   = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\20\0\0\0\0\0\0"...,
832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=72232, ...}) = 0
getcwd("/home/user/ima_stuff", 128)     = 21
mmap(NULL, 2167449, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_DENYWRITE,
3, 0) = 0x7fb83e3e5000
mprotect(0x7fb83e3e7000, 2093056, PROT_NONE) = 0
mmap(0x7fb83e5e6000, 69632, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1000) = 0x7fb83e5e6000
mprotect(0x7ffea1b1f000, 4096,
PROT_READ|PROT_WRITE|PROT_EXEC|PROT_GROWSDOWN) = 0
close(3)                                = 0
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=103509, ...}) = 0
mmap(NULL, 103509, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fb83e7fd000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\3\2\0\0\0\0\0"...,
832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1689360, ...}) = 0
mmap(NULL, 3795360, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3,
0) = 0x7fb83e046000
mprotect(0x7fb83e1db000, 2097152, PROT_NONE) = 0
mmap(0x7fb83e3db000, 24576, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x195000) = 0x7fb83e3db000
mmap(0x7fb83e3e1000, 14752, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb83e3e1000
close(3)                                = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0x7fb83e7fb000
arch_prctl(ARCH_SET_FS, 0x7fb83e7fb700) = 0
mprotect(0x7fb83e3db000, 16384, PROT_READ) = 0
mprotect(0x5642c3eed000, 4096, PROT_READ) = 0
mprotect(0x7fb83e81a000, 4096, PROT_READ) = 0
munmap(0x7fb83e7fd000, 103509)          = 0
mprotect(0x7fb83e3e6000, 4096, PROT_READ|PROT_WRITE|PROT_EXEC) = 0
getpid()                                = 1084
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
brk(NULL)                               = 0x5642c52bc000
brk(0x5642c52dd000)                     = 0x5642c52dd000
write(1, "hello world from PID 1084\n", 26hello world from PID 1084
) = 26
exit_group(0)                           = ?
+++ exited with 0 +++
=============================

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC
  2020-04-28 19:21 ` [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC Jann Horn
@ 2020-04-28 21:20   ` Florian Weimer
  2020-04-28 22:01     ` Jann Horn
  0 siblings, 1 reply; 23+ messages in thread
From: Florian Weimer @ 2020-04-28 21:20 UTC (permalink / raw)
  To: Jann Horn
  Cc: Mickaël Salaün, kernel list, Aleksa Sarai,
	Alexei Starovoitov, Al Viro, Andy Lutomirski, Christian Heimes,
	Daniel Borkmann, Deven Bowers, Eric Chiang, James Morris,
	Jan Kara, Jonathan Corbet, Kees Cook, Matthew Garrett,
	Matthew Wilcox, Michael Kerrisk, Mickaël Salaün,
	Mimi Zohar, Philippe Trébuchet, Scott Shell,
	Sean Christopherson, Shuah Khan, Steve Dower, Steve Grubb,
	Thibaut Sautereau, Vincent Strubel, Kernel Hardening, Linux API,
	linux-security-module, linux-fsdevel

* Jann Horn:

> Just as a comment: You'd probably also have to use RESOLVE_MAYEXEC in
> the dynamic linker.

Absolutely.  In typical configurations, the kernel does not enforce
that executable mappings must be backed by files which are executable.
It's most obvious with using an explicit loader invocation to run
executables on noexec mounts.  RESOLVE_MAYEXEC is much more useful
than trying to reimplement the kernel permission checks (or what some
believe they should be) in userspace.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC
  2020-04-28 21:20   ` Florian Weimer
@ 2020-04-28 22:01     ` Jann Horn
  2020-04-29  8:50       ` Mickaël Salaün
  2020-05-01 11:47       ` Christian Heimes
  0 siblings, 2 replies; 23+ messages in thread
From: Jann Horn @ 2020-04-28 22:01 UTC (permalink / raw)
  To: Florian Weimer
  Cc: Mickaël Salaün, kernel list, Aleksa Sarai,
	Alexei Starovoitov, Al Viro, Andy Lutomirski, Christian Heimes,
	Daniel Borkmann, Deven Bowers, Eric Chiang, James Morris,
	Jan Kara, Jonathan Corbet, Kees Cook, Matthew Garrett,
	Matthew Wilcox, Michael Kerrisk, Mickaël Salaün,
	Mimi Zohar, Philippe Trébuchet, Scott Shell,
	Sean Christopherson, Shuah Khan, Steve Dower, Steve Grubb,
	Thibaut Sautereau, Vincent Strubel, Kernel Hardening, Linux API,
	linux-security-module, linux-fsdevel

On Tue, Apr 28, 2020 at 11:21 PM Florian Weimer <fw@deneb.enyo.de> wrote:
> * Jann Horn:
>
> > Just as a comment: You'd probably also have to use RESOLVE_MAYEXEC in
> > the dynamic linker.
>
> Absolutely.  In typical configurations, the kernel does not enforce
> that executable mappings must be backed by files which are executable.
> It's most obvious with using an explicit loader invocation to run
> executables on noexec mounts.  RESOLVE_MAYEXEC is much more useful
> than trying to reimplement the kernel permission checks (or what some
> believe they should be) in userspace.

Oh, good point.

That actually seems like something Mickaël could add to his series? If
someone turns on that knob for "When an interpreter wants to execute
something, enforce that we have execute access to it", they probably
also don't want it to be possible to just map files as executable? So
perhaps when that flag is on, the kernel should either refuse to map
anything as executable if it wasn't opened with RESOLVE_MAYEXEC or
(less strict) if RESOLVE_MAYEXEC wasn't used, print a warning, then
check whether the file is executable and bail out if not?

A configuration where interpreters verify that scripts are executable,
but other things can just mmap executable pages, seems kinda
inconsistent...

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC
  2020-04-28 22:01     ` Jann Horn
@ 2020-04-29  8:50       ` Mickaël Salaün
  2020-05-01 11:47       ` Christian Heimes
  1 sibling, 0 replies; 23+ messages in thread
From: Mickaël Salaün @ 2020-04-29  8:50 UTC (permalink / raw)
  To: Jann Horn, Florian Weimer
  Cc: kernel list, Aleksa Sarai, Alexei Starovoitov, Al Viro,
	Andy Lutomirski, Christian Heimes, Daniel Borkmann, Deven Bowers,
	Eric Chiang, James Morris, Jan Kara, Jonathan Corbet, Kees Cook,
	Matthew Garrett, Matthew Wilcox, Michael Kerrisk,
	Mickaël Salaün, Mimi Zohar, Philippe Trébuchet,
	Scott Shell, Sean Christopherson, Shuah Khan, Steve Dower,
	Steve Grubb, Thibaut Sautereau, Vincent Strubel,
	Kernel Hardening, Linux API, linux-security-module,
	linux-fsdevel



On 29/04/2020 00:01, Jann Horn wrote:
> On Tue, Apr 28, 2020 at 11:21 PM Florian Weimer <fw@deneb.enyo.de> wrote:
>> * Jann Horn:
>>
>>> Just as a comment: You'd probably also have to use RESOLVE_MAYEXEC in
>>> the dynamic linker.
>>
>> Absolutely.  In typical configurations, the kernel does not enforce
>> that executable mappings must be backed by files which are executable.
>> It's most obvious with using an explicit loader invocation to run
>> executables on noexec mounts.  RESOLVE_MAYEXEC is much more useful
>> than trying to reimplement the kernel permission checks (or what some
>> believe they should be) in userspace.

Indeed it makes sense to use RESOLVE_MAYEXEC for the dynamic linker too.
Only the noexec mount option is taken into account for mmap(2) with
PROT_EXEC, and if you can trick the dynamic linker with JOP as Jann
explained, it may enable to execute new code. However, a kernel which
forbids remapping memory with PROT_EXEC still enables to implement a W^X
policy. Any JOP/ROP still enables unexpected code execution though.

> 
> Oh, good point.
> 
> That actually seems like something Mickaël could add to his series? If
> someone turns on that knob for "When an interpreter wants to execute
> something, enforce that we have execute access to it", they probably
> also don't want it to be possible to just map files as executable? So
> perhaps when that flag is on, the kernel should either refuse to map
> anything as executable if it wasn't opened with RESOLVE_MAYEXEC or
> (less strict) if RESOLVE_MAYEXEC wasn't used, print a warning, then
> check whether the file is executable and bail out if not?
> 
> A configuration where interpreters verify that scripts are executable,
> but other things can just mmap executable pages, seems kinda
> inconsistent...

As it is written in the documentation patch, this RESOLVE_MAYEXEC
feature is an important missing piece, but to implement a consistent
security policy we need to enable other restrictions starting with a
noexec mount point policy. The purpose of this patch series is not to
bring a full-feature LSM with process states handling, but it brings
what is needed for LSMs such as SELinux, IMA or IPE to extend their
capabilities to reach what you would expect.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC
  2020-04-28 17:51 [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC Mickaël Salaün
                   ` (5 preceding siblings ...)
  2020-04-28 19:21 ` [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC Jann Horn
@ 2020-04-30  1:54 ` Aleksa Sarai
  2020-04-30  8:07   ` Christian Brauner
  2020-05-01  3:53 ` James Morris
  7 siblings, 1 reply; 23+ messages in thread
From: Aleksa Sarai @ 2020-04-30  1:54 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: linux-kernel, Alexei Starovoitov, Al Viro, Andy Lutomirski,
	Christian Heimes, Daniel Borkmann, Deven Bowers, Eric Chiang,
	Florian Weimer, James Morris, Jan Kara, Jann Horn,
	Jonathan Corbet, Kees Cook, Matthew Garrett, Matthew Wilcox,
	Michael Kerrisk, Mickaël Salaün, Mimi Zohar,
	Philippe Trébuchet, Scott Shell, Sean Christopherson,
	Shuah Khan, Steve Dower, Steve Grubb, Thibaut Sautereau,
	Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel

[-- Attachment #1: Type: text/plain, Size: 1380 bytes --]

On 2020-04-28, Mickaël Salaün <mic@digikod.net> wrote:
> The goal of this patch series is to enable to control script execution
> with interpreters help.  A new RESOLVE_MAYEXEC flag, usable through
> openat2(2), is added to enable userspace script interpreter to delegate
> to the kernel (and thus the system security policy) the permission to
> interpret/execute scripts or other files containing what can be seen as
> commands.
> 
> This third patch series mainly differ from the previous one by relying
> on the new openat2(2) system call to get rid of the undefined behavior
> of the open(2) flags.  Thus, the previous O_MAYEXEC flag is now replaced
> with the new RESOLVE_MAYEXEC flag and benefits from the openat2(2)
> strict check of this kind of flags.

My only strong upfront objection is with this being a RESOLVE_ flag.

RESOLVE_ flags have a specific meaning (they generally apply to all
components, and affect the rules of path resolution). RESOLVE_MAYEXEC
does neither of these things and so seems out of place among the other
RESOLVE_ flags.

I would argue this should be an O_ flag, but not supported for the
old-style open(2). This is what the O_SPECIFIC_FD patchset does[1] and I
think it's a reasonable way of solving such problems.

-- 
Aleksa Sarai
Senior Software Engineer (Containers)
SUSE Linux GmbH
<https://www.cyphar.com/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC
  2020-04-30  1:54 ` Aleksa Sarai
@ 2020-04-30  8:07   ` Christian Brauner
  2020-04-30 10:45     ` Mickaël Salaün
  0 siblings, 1 reply; 23+ messages in thread
From: Christian Brauner @ 2020-04-30  8:07 UTC (permalink / raw)
  To: Aleksa Sarai
  Cc: Mickaël Salaün, linux-kernel, Alexei Starovoitov,
	Al Viro, Andy Lutomirski, Christian Heimes, Daniel Borkmann,
	Deven Bowers, Eric Chiang, Florian Weimer, James Morris,
	Jan Kara, Jann Horn, Jonathan Corbet, Kees Cook, Matthew Garrett,
	Matthew Wilcox, Michael Kerrisk, Mickaël Salaün,
	Mimi Zohar, Philippe Trébuchet, Scott Shell,
	Sean Christopherson, Shuah Khan, Steve Dower, Steve Grubb,
	Thibaut Sautereau, Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel

On Thu, Apr 30, 2020 at 11:54:29AM +1000, Aleksa Sarai wrote:
> On 2020-04-28, Mickaël Salaün <mic@digikod.net> wrote:
> > The goal of this patch series is to enable to control script execution
> > with interpreters help.  A new RESOLVE_MAYEXEC flag, usable through
> > openat2(2), is added to enable userspace script interpreter to delegate
> > to the kernel (and thus the system security policy) the permission to
> > interpret/execute scripts or other files containing what can be seen as
> > commands.
> > 
> > This third patch series mainly differ from the previous one by relying
> > on the new openat2(2) system call to get rid of the undefined behavior
> > of the open(2) flags.  Thus, the previous O_MAYEXEC flag is now replaced
> > with the new RESOLVE_MAYEXEC flag and benefits from the openat2(2)
> > strict check of this kind of flags.
> 
> My only strong upfront objection is with this being a RESOLVE_ flag.
> 
> RESOLVE_ flags have a specific meaning (they generally apply to all
> components, and affect the rules of path resolution). RESOLVE_MAYEXEC
> does neither of these things and so seems out of place among the other
> RESOLVE_ flags.
> 
> I would argue this should be an O_ flag, but not supported for the

I agree.

Christian

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC
  2020-04-30  8:07   ` Christian Brauner
@ 2020-04-30 10:45     ` Mickaël Salaün
  0 siblings, 0 replies; 23+ messages in thread
From: Mickaël Salaün @ 2020-04-30 10:45 UTC (permalink / raw)
  To: Christian Brauner, Aleksa Sarai
  Cc: linux-kernel, Alexei Starovoitov, Al Viro, Andy Lutomirski,
	Christian Heimes, Daniel Borkmann, Deven Bowers, Eric Chiang,
	Florian Weimer, James Morris, Jan Kara, Jann Horn,
	Jonathan Corbet, Kees Cook, Matthew Garrett, Matthew Wilcox,
	Michael Kerrisk, Mickaël Salaün, Mimi Zohar,
	Philippe Trébuchet, Scott Shell, Sean Christopherson,
	Shuah Khan, Steve Dower, Steve Grubb, Thibaut Sautereau,
	Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel


On 30/04/2020 10:07, Christian Brauner wrote:
> On Thu, Apr 30, 2020 at 11:54:29AM +1000, Aleksa Sarai wrote:
>> On 2020-04-28, Mickaël Salaün <mic@digikod.net> wrote:
>>> The goal of this patch series is to enable to control script execution
>>> with interpreters help.  A new RESOLVE_MAYEXEC flag, usable through
>>> openat2(2), is added to enable userspace script interpreter to delegate
>>> to the kernel (and thus the system security policy) the permission to
>>> interpret/execute scripts or other files containing what can be seen as
>>> commands.
>>>
>>> This third patch series mainly differ from the previous one by relying
>>> on the new openat2(2) system call to get rid of the undefined behavior
>>> of the open(2) flags.  Thus, the previous O_MAYEXEC flag is now replaced
>>> with the new RESOLVE_MAYEXEC flag and benefits from the openat2(2)
>>> strict check of this kind of flags.
>>
>> My only strong upfront objection is with this being a RESOLVE_ flag.
>>
>> RESOLVE_ flags have a specific meaning (they generally apply to all
>> components, and affect the rules of path resolution). RESOLVE_MAYEXEC
>> does neither of these things and so seems out of place among the other
>> RESOLVE_ flags.
>>
>> I would argue this should be an O_ flag, but not supported for the
> 
> I agree.

OK, I'll switch back to O_MAYEXEC.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC
  2020-04-28 17:51 [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC Mickaël Salaün
                   ` (6 preceding siblings ...)
  2020-04-30  1:54 ` Aleksa Sarai
@ 2020-05-01  3:53 ` James Morris
  7 siblings, 0 replies; 23+ messages in thread
From: James Morris @ 2020-05-01  3:53 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
	Andy Lutomirski, Christian Heimes, Daniel Borkmann, Deven Bowers,
	Eric Chiang, Florian Weimer, Jan Kara, Jann Horn,
	Jonathan Corbet, Kees Cook, Matthew Garrett, Matthew Wilcox,
	Michael Kerrisk, Mickaël Salaün, Mimi Zohar,
	Philippe Trébuchet, Scott Shell, Sean Christopherson,
	Shuah Khan, Steve Dower, Steve Grubb, Thibaut Sautereau,
	Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel

[-- Attachment #1: Type: text/plain, Size: 553 bytes --]

On Tue, 28 Apr 2020, Mickaël Salaün wrote:

> Furthermore, the security policy can also be delegated to an LSM, either
> a MAC system or an integrity system.  For instance, the new kernel
> MAY_OPENEXEC flag closes a major IMA measurement/appraisal interpreter
> integrity gap by bringing the ability to check the use of scripts [1].
> Other uses are expected, such as for openat2(2) [2], SGX integration
> [3], bpffs [4] or IPE [5].

Confirming that this is a highly desirable feature for the proposed IPE 
LSM.

-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 2/5] fs: Add a MAY_EXECMOUNT flag to infer the noexec mount property
  2020-04-28 17:51 ` [PATCH v3 2/5] fs: Add a MAY_EXECMOUNT flag to infer the noexec mount property Mickaël Salaün
@ 2020-05-01  4:02   ` James Morris
  2020-05-01 14:17     ` Mickaël Salaün
  0 siblings, 1 reply; 23+ messages in thread
From: James Morris @ 2020-05-01  4:02 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
	Andy Lutomirski, Christian Heimes, Daniel Borkmann, Deven Bowers,
	Eric Chiang, Florian Weimer, Jan Kara, Jann Horn,
	Jonathan Corbet, Kees Cook, Matthew Garrett, Matthew Wilcox,
	Michael Kerrisk, Mickaël Salaün, Mimi Zohar,
	Philippe Trébuchet, Scott Shell, Sean Christopherson,
	Shuah Khan, Steve Dower, Steve Grubb, Thibaut Sautereau,
	Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel

[-- Attachment #1: Type: text/plain, Size: 919 bytes --]

On Tue, 28 Apr 2020, Mickaël Salaün wrote:

> An LSM doesn't get path information related to an access request to open
> an inode.  This new (internal) MAY_EXECMOUNT flag enables an LSM to
> check if the underlying mount point of an inode is marked as executable.
> This is useful to implement a security policy taking advantage of the
> noexec mount option.
> 
> This flag is set according to path_noexec(), which checks if a mount
> point is mounted with MNT_NOEXEC or if the underlying superblock is
> SB_I_NOEXEC.
> 
> Signed-off-by: Mickaël Salaün <mic@digikod.net>
> Reviewed-by: Philippe Trébuchet <philippe.trebuchet@ssi.gouv.fr>
> Reviewed-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr>
> Cc: Aleksa Sarai <cyphar@cyphar.com>
> Cc: Al Viro <viro@zeniv.linux.org.uk>
> Cc: Kees Cook <keescook@chromium.org>

Are there any existing LSMs which plan to use this aspect?

-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 1/5] fs: Add support for a RESOLVE_MAYEXEC flag on openat2(2)
  2020-04-28 17:51 ` [PATCH v3 1/5] fs: Add support for a RESOLVE_MAYEXEC flag on openat2(2) Mickaël Salaün
@ 2020-05-01  4:04   ` James Morris
  2020-05-01 14:14     ` Mickaël Salaün
  0 siblings, 1 reply; 23+ messages in thread
From: James Morris @ 2020-05-01  4:04 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
	Andy Lutomirski, Christian Heimes, Daniel Borkmann, Deven Bowers,
	Eric Chiang, Florian Weimer, Jan Kara, Jann Horn,
	Jonathan Corbet, Kees Cook, Matthew Garrett, Matthew Wilcox,
	Michael Kerrisk, Mickaël Salaün, Mimi Zohar,
	Philippe Trébuchet, Scott Shell, Sean Christopherson,
	Shuah Khan, Steve Dower, Steve Grubb, Thibaut Sautereau,
	Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel

[-- Attachment #1: Type: text/plain, Size: 378 bytes --]

On Tue, 28 Apr 2020, Mickaël Salaün wrote:

> When the RESOLVE_MAYEXEC flag is passed, openat2(2) may be subject to
> 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.


Reviewed-by: James Morris <jamorris@linux.microsoft.com>


-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 3/5] fs: Enable to enforce noexec mounts or file exec through RESOLVE_MAYEXEC
  2020-04-28 17:51 ` [PATCH v3 3/5] fs: Enable to enforce noexec mounts or file exec through RESOLVE_MAYEXEC Mickaël Salaün
@ 2020-05-01  4:22   ` James Morris
  2020-05-01 14:32     ` Mickaël Salaün
  0 siblings, 1 reply; 23+ messages in thread
From: James Morris @ 2020-05-01  4:22 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
	Andy Lutomirski, Christian Heimes, Daniel Borkmann, Deven Bowers,
	Eric Chiang, Florian Weimer, Jan Kara, Jann Horn,
	Jonathan Corbet, Kees Cook, Matthew Garrett, Matthew Wilcox,
	Michael Kerrisk, Mickaël Salaün, Mimi Zohar,
	Philippe Trébuchet, Scott Shell, Sean Christopherson,
	Shuah Khan, Steve Dower, Steve Grubb, Thibaut Sautereau,
	Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel

[-- Attachment #1: Type: text/plain, Size: 1861 bytes --]

On Tue, 28 Apr 2020, Mickaël Salaün wrote:

> Enable to either propagate the mount options from the underlying VFS
> mount to prevent execution, or to propagate the file execute permission.
> This may allow a script interpreter to check execution permissions
> before reading commands from a file.

I'm finding the description of this patch difficult to understand.

In the first case, this seems to mean: if you open a file with 
RESOLVE_MAYEXEC from a noexec mount, then it will fail. Correct?

In the second case, do you mean a RESOLVE_MAYEXEC open will fail if the 
file does not have +x set for the user?


> The main goal is to be able to protect the kernel by restricting
> arbitrary syscalls that an attacker could perform with a crafted binary
> or certain script languages.

This sounds like the job of seccomp. Why is this part of MAYEXEC?

>  It also improves multilevel isolation
> by reducing the ability of an attacker to use side channels with
> specific code.  These restrictions can natively be enforced for ELF
> binaries (with the noexec mount option) but require this kernel
> extension to properly handle scripts (e.g., Python, Perl).

Again, not sure why you're talking about side channels and MAYEXEC and 
mount options. Are you more generally talking about being able to prevent 
execution of arbitrary script files included by an interpreter?

> Add a new sysctl fs.open_mayexec_enforce to control this behavior.
> Indeed, because of compatibility with installed systems, only the system
> administrator is able to check that this new enforcement is in line with
> the system mount points and file permissions.  A following patch adds
> documentation.

I don't like the idea of any of this feature set being configurable. 
RESOLVE_MAYEXEC as a new flag should have well-defined, stable semantics.


-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC
  2020-04-28 22:01     ` Jann Horn
  2020-04-29  8:50       ` Mickaël Salaün
@ 2020-05-01 11:47       ` Christian Heimes
  2020-05-05 14:57         ` Mickaël Salaün
  1 sibling, 1 reply; 23+ messages in thread
From: Christian Heimes @ 2020-05-01 11:47 UTC (permalink / raw)
  To: Jann Horn, Florian Weimer
  Cc: Mickaël Salaün, kernel list, Aleksa Sarai,
	Alexei Starovoitov, Al Viro, Andy Lutomirski, Daniel Borkmann,
	Deven Bowers, Eric Chiang, James Morris, Jan Kara,
	Jonathan Corbet, Kees Cook, Matthew Garrett, Matthew Wilcox,
	Michael Kerrisk, Mickaël Salaün, Mimi Zohar,
	Philippe Trébuchet, Scott Shell, Sean Christopherson,
	Shuah Khan, Steve Dower, Steve Grubb, Thibaut Sautereau,
	Vincent Strubel, Kernel Hardening, Linux API,
	linux-security-module, linux-fsdevel

On 29/04/2020 00.01, Jann Horn wrote:
> On Tue, Apr 28, 2020 at 11:21 PM Florian Weimer <fw@deneb.enyo.de> wrote:
>> * Jann Horn:
>>
>>> Just as a comment: You'd probably also have to use RESOLVE_MAYEXEC in
>>> the dynamic linker.
>>
>> Absolutely.  In typical configurations, the kernel does not enforce
>> that executable mappings must be backed by files which are executable.
>> It's most obvious with using an explicit loader invocation to run
>> executables on noexec mounts.  RESOLVE_MAYEXEC is much more useful
>> than trying to reimplement the kernel permission checks (or what some
>> believe they should be) in userspace.
> 
> Oh, good point.
> 
> That actually seems like something Mickaël could add to his series? If
> someone turns on that knob for "When an interpreter wants to execute
> something, enforce that we have execute access to it", they probably
> also don't want it to be possible to just map files as executable? So
> perhaps when that flag is on, the kernel should either refuse to map
> anything as executable if it wasn't opened with RESOLVE_MAYEXEC or
> (less strict) if RESOLVE_MAYEXEC wasn't used, print a warning, then
> check whether the file is executable and bail out if not?
> 
> A configuration where interpreters verify that scripts are executable,
> but other things can just mmap executable pages, seems kinda
> inconsistent...

+1

I worked with Steve Downer on Python PEP 578 [1] that added audit hooks
and PyFile_OpenCode() to CPython. A PyFile_OpenCode() implementation
with RESOLVE_MAYEXEC will hep to secure loading of Python code. But
Python also includes a wrapper of libffi. ctypes or cffi can load native
code from either shared libraries with dlopen() or execute native code
from mmap() regions. For example SnakeEater [2] is a clever attack that
abused memfd_create syscall and proc filesystem to execute code.

A consistent security policy must also ensure that mmap() PROT_EXEC
enforces the same restrictions as RESOLVE_MAYEXEC. The restriction
doesn't have be part of this patch, though.

Christian

[1] https://www.python.org/dev/peps/pep-0578/
[2] https://github.com/nullbites/SnakeEater/blob/master/SnakeEater2.py

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 1/5] fs: Add support for a RESOLVE_MAYEXEC flag on openat2(2)
  2020-05-01  4:04   ` James Morris
@ 2020-05-01 14:14     ` Mickaël Salaün
  0 siblings, 0 replies; 23+ messages in thread
From: Mickaël Salaün @ 2020-05-01 14:14 UTC (permalink / raw)
  To: James Morris
  Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
	Andy Lutomirski, Christian Heimes, Daniel Borkmann, Deven Bowers,
	Eric Chiang, Florian Weimer, Jan Kara, Jann Horn,
	Jonathan Corbet, Kees Cook, Matthew Garrett, Matthew Wilcox,
	Michael Kerrisk, Mickaël Salaün, Mimi Zohar,
	Philippe Trébuchet, Scott Shell, Sean Christopherson,
	Shuah Khan, Steve Dower, Steve Grubb, Thibaut Sautereau,
	Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel


On 01/05/2020 06:04, James Morris wrote:
> On Tue, 28 Apr 2020, Mickaël Salaün wrote:
> 
>> When the RESOLVE_MAYEXEC flag is passed, openat2(2) may be subject to
>> 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.
> 
> 
> Reviewed-by: James Morris <jamorris@linux.microsoft.com>

As requested, I switched back to O_MAYEXEC yesterday with the v4:
https://lore.kernel.org/lkml/20200430132320.699508-2-mic@digikod.net/

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 2/5] fs: Add a MAY_EXECMOUNT flag to infer the noexec mount property
  2020-05-01  4:02   ` James Morris
@ 2020-05-01 14:17     ` Mickaël Salaün
  0 siblings, 0 replies; 23+ messages in thread
From: Mickaël Salaün @ 2020-05-01 14:17 UTC (permalink / raw)
  To: James Morris
  Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
	Andy Lutomirski, Christian Heimes, Daniel Borkmann, Deven Bowers,
	Eric Chiang, Florian Weimer, Jan Kara, Jann Horn,
	Jonathan Corbet, Kees Cook, Matthew Garrett, Matthew Wilcox,
	Michael Kerrisk, Mickaël Salaün, Mimi Zohar,
	Philippe Trébuchet, Scott Shell, Sean Christopherson,
	Shuah Khan, Steve Dower, Steve Grubb, Thibaut Sautereau,
	Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel


On 01/05/2020 06:02, James Morris wrote:
> On Tue, 28 Apr 2020, Mickaël Salaün wrote:
> 
>> An LSM doesn't get path information related to an access request to open
>> an inode.  This new (internal) MAY_EXECMOUNT flag enables an LSM to
>> check if the underlying mount point of an inode is marked as executable.
>> This is useful to implement a security policy taking advantage of the
>> noexec mount option.
>>
>> This flag is set according to path_noexec(), which checks if a mount
>> point is mounted with MNT_NOEXEC or if the underlying superblock is
>> SB_I_NOEXEC.
>>
>> Signed-off-by: Mickaël Salaün <mic@digikod.net>
>> Reviewed-by: Philippe Trébuchet <philippe.trebuchet@ssi.gouv.fr>
>> Reviewed-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr>
>> Cc: Aleksa Sarai <cyphar@cyphar.com>
>> Cc: Al Viro <viro@zeniv.linux.org.uk>
>> Cc: Kees Cook <keescook@chromium.org>
> 
> Are there any existing LSMs which plan to use this aspect?

This commit message was initially for the first version of O_MAYEXEC,
which extended Yama. The current enforcement implementation is now
directly in the FS subsystem (as requested by Kees Cook). However, this
MAY_EXECMOUNT flag is still used by the current FS implementation and it
could still be useful for LSMs.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 3/5] fs: Enable to enforce noexec mounts or file exec through RESOLVE_MAYEXEC
  2020-05-01  4:22   ` James Morris
@ 2020-05-01 14:32     ` Mickaël Salaün
  2020-05-01 18:05       ` James Morris
  0 siblings, 1 reply; 23+ messages in thread
From: Mickaël Salaün @ 2020-05-01 14:32 UTC (permalink / raw)
  To: James Morris
  Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
	Andy Lutomirski, Christian Heimes, Daniel Borkmann, Deven Bowers,
	Eric Chiang, Florian Weimer, Jan Kara, Jann Horn,
	Jonathan Corbet, Kees Cook, Matthew Garrett, Matthew Wilcox,
	Michael Kerrisk, Mickaël Salaün, Mimi Zohar,
	Philippe Trébuchet, Scott Shell, Sean Christopherson,
	Shuah Khan, Steve Dower, Steve Grubb, Thibaut Sautereau,
	Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel


On 01/05/2020 06:22, James Morris wrote:
> On Tue, 28 Apr 2020, Mickaël Salaün wrote:
> 
>> Enable to either propagate the mount options from the underlying VFS
>> mount to prevent execution, or to propagate the file execute permission.
>> This may allow a script interpreter to check execution permissions
>> before reading commands from a file.
> 
> I'm finding the description of this patch difficult to understand.
> 
> In the first case, this seems to mean: if you open a file with 
> RESOLVE_MAYEXEC from a noexec mount, then it will fail. Correct?

Yes.

> 
> In the second case, do you mean a RESOLVE_MAYEXEC open will fail if the 
> file does not have +x set for the user?

Yes, and this is still in the hands sysadmins.

As explain in the documentation patch, the sysctl takes a bitfield
consisting of "mount !noexec" or "file exec permission". It is not an
exclusive OR. The "file exec permission" could be seen as a more strict
restriction than only the mount one.

> 
> 
>> The main goal is to be able to protect the kernel by restricting
>> arbitrary syscalls that an attacker could perform with a crafted binary
>> or certain script languages.
> 
> This sounds like the job of seccomp. Why is this part of MAYEXEC?

The initial goal of O_MAYEXEC (in CLIP OS 4) is to prevent untrusted
code execution. Code execution leads to system calls, which could lead
to data access/modification, and kernel attacks. seccomp can't enable
execution of only some files, it only enables an on/off execution policy
(i.e. by filtering execve(2) ).

> 
>>  It also improves multilevel isolation
>> by reducing the ability of an attacker to use side channels with
>> specific code.  These restrictions can natively be enforced for ELF
>> binaries (with the noexec mount option) but require this kernel
>> extension to properly handle scripts (e.g., Python, Perl).
> 
> Again, not sure why you're talking about side channels and MAYEXEC and 
> mount options. Are you more generally talking about being able to prevent 
> execution of arbitrary script files included by an interpreter?

Yes, I explain the thread model, especially the risk of scripts.
Multilevel isolation can be bypassed simply by using CPU instructions
(e.g. side channel attacks), not even syscalls. The ability to execute
arbitrary code, including advanced scripting languages, can lead to this
kind of CPU attacks.

> 
>> Add a new sysctl fs.open_mayexec_enforce to control this behavior.
>> Indeed, because of compatibility with installed systems, only the system
>> administrator is able to check that this new enforcement is in line with
>> the system mount points and file permissions.  A following patch adds
>> documentation.
> 
> I don't like the idea of any of this feature set being configurable. 
> RESOLVE_MAYEXEC as a new flag should have well-defined, stable semantics.

Unfortunately, as discussed in the v2 email thread [1], if we impose
such restrictions with the O_MAYEXEC flag, then almost no userspace
application will use it because it could cause unexpected behavior.
Indeed, the application developers may not know the configuration of the
system their applications will be run on. Only sysadmins know the mount
points configuration (either they are have noexec or not), and if the
set of application installed on the system works well with the set of
files (e.g. according to their permissions). It is the same issue as
with a system-wide LSM policy configuration. Processes should be able to
tell their use of a file, but the sysadmin using common distro binaries
should be able to control the execution policy according to the maturity
of the current system installation.

However, for fully controlled distros such as CLIP OS, it make sense to
enforce such restrictions at kernel build time. I can add an alternative
kernel configuration to enforce a particular policy at boot and disable
this sysctl.

[1]
https://lore.kernel.org/lkml/1fbf54f6-7597-3633-a76c-11c4b2481add@ssi.gouv.fr/

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 3/5] fs: Enable to enforce noexec mounts or file exec through RESOLVE_MAYEXEC
  2020-05-01 14:32     ` Mickaël Salaün
@ 2020-05-01 18:05       ` James Morris
  0 siblings, 0 replies; 23+ messages in thread
From: James Morris @ 2020-05-01 18:05 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: linux-kernel, Aleksa Sarai, Alexei Starovoitov, Al Viro,
	Andy Lutomirski, Christian Heimes, Daniel Borkmann, Deven Bowers,
	Eric Chiang, Florian Weimer, Jan Kara, Jann Horn,
	Jonathan Corbet, Kees Cook, Matthew Garrett, Matthew Wilcox,
	Michael Kerrisk, Mickaël Salaün, Mimi Zohar,
	Philippe Trébuchet, Scott Shell, Sean Christopherson,
	Shuah Khan, Steve Dower, Steve Grubb, Thibaut Sautereau,
	Vincent Strubel, kernel-hardening, linux-api,
	linux-security-module, linux-fsdevel

[-- Attachment #1: Type: text/plain, Size: 336 bytes --]

On Fri, 1 May 2020, Mickaël Salaün wrote:

> 
> However, for fully controlled distros such as CLIP OS, it make sense to
> enforce such restrictions at kernel build time. I can add an alternative
> kernel configuration to enforce a particular policy at boot and disable
> this sysctl.

Sounds good.

-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC
  2020-05-01 11:47       ` Christian Heimes
@ 2020-05-05 14:57         ` Mickaël Salaün
  0 siblings, 0 replies; 23+ messages in thread
From: Mickaël Salaün @ 2020-05-05 14:57 UTC (permalink / raw)
  To: Christian Heimes, Jann Horn, Florian Weimer
  Cc: kernel list, Aleksa Sarai, Alexei Starovoitov, Al Viro,
	Andy Lutomirski, Daniel Borkmann, Deven Bowers, Eric Chiang,
	James Morris, Jan Kara, Jonathan Corbet, Kees Cook,
	Matthew Garrett, Matthew Wilcox, Michael Kerrisk,
	Mickaël Salaün, Mimi Zohar, Philippe Trébuchet,
	Scott Shell, Sean Christopherson, Shuah Khan, Steve Dower,
	Steve Grubb, Thibaut Sautereau, Vincent Strubel,
	Kernel Hardening, Linux API, linux-security-module,
	linux-fsdevel


On 01/05/2020 13:47, Christian Heimes wrote:
> On 29/04/2020 00.01, Jann Horn wrote:
>> On Tue, Apr 28, 2020 at 11:21 PM Florian Weimer <fw@deneb.enyo.de> wrote:
>>> * Jann Horn:
>>>
>>>> Just as a comment: You'd probably also have to use RESOLVE_MAYEXEC in
>>>> the dynamic linker.
>>>
>>> Absolutely.  In typical configurations, the kernel does not enforce
>>> that executable mappings must be backed by files which are executable.
>>> It's most obvious with using an explicit loader invocation to run
>>> executables on noexec mounts.  RESOLVE_MAYEXEC is much more useful
>>> than trying to reimplement the kernel permission checks (or what some
>>> believe they should be) in userspace.
>>
>> Oh, good point.
>>
>> That actually seems like something Mickaël could add to his series? If
>> someone turns on that knob for "When an interpreter wants to execute
>> something, enforce that we have execute access to it", they probably
>> also don't want it to be possible to just map files as executable? So
>> perhaps when that flag is on, the kernel should either refuse to map
>> anything as executable if it wasn't opened with RESOLVE_MAYEXEC or
>> (less strict) if RESOLVE_MAYEXEC wasn't used, print a warning, then
>> check whether the file is executable and bail out if not?
>>
>> A configuration where interpreters verify that scripts are executable,
>> but other things can just mmap executable pages, seems kinda
>> inconsistent...
> 
> +1
> 
> I worked with Steve Downer on Python PEP 578 [1] that added audit hooks
> and PyFile_OpenCode() to CPython. A PyFile_OpenCode() implementation
> with RESOLVE_MAYEXEC will hep to secure loading of Python code. But
> Python also includes a wrapper of libffi. ctypes or cffi can load native
> code from either shared libraries with dlopen() or execute native code
> from mmap() regions. For example SnakeEater [2] is a clever attack that
> abused memfd_create syscall and proc filesystem to execute code.
> 
> A consistent security policy must also ensure that mmap() PROT_EXEC
> enforces the same restrictions as RESOLVE_MAYEXEC. The restriction
> doesn't have be part of this patch, though.
> 
> Christian
> 
> [1] https://www.python.org/dev/peps/pep-0578/
> [2] https://github.com/nullbites/SnakeEater/blob/master/SnakeEater2.py

To be consistent, a "noexec" policy must indeed also restricts features
such as mprotect(2) and mmap(2) which may enable to set arbitrary memory
as executable. This can be restricted with SELinux (i.e. execmem,
execmod,execheap and execstack permissions), PaX MPROTECT [1] or SARA [2].

[1] https://pax.grsecurity.net/docs/mprotect.txt
[2]
https://lore.kernel.org/lkml/1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com/

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2020-05-05 14:58 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-28 17:51 [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC Mickaël Salaün
2020-04-28 17:51 ` [PATCH v3 1/5] fs: Add support for a RESOLVE_MAYEXEC flag on openat2(2) Mickaël Salaün
2020-05-01  4:04   ` James Morris
2020-05-01 14:14     ` Mickaël Salaün
2020-04-28 17:51 ` [PATCH v3 2/5] fs: Add a MAY_EXECMOUNT flag to infer the noexec mount property Mickaël Salaün
2020-05-01  4:02   ` James Morris
2020-05-01 14:17     ` Mickaël Salaün
2020-04-28 17:51 ` [PATCH v3 3/5] fs: Enable to enforce noexec mounts or file exec through RESOLVE_MAYEXEC Mickaël Salaün
2020-05-01  4:22   ` James Morris
2020-05-01 14:32     ` Mickaël Salaün
2020-05-01 18:05       ` James Morris
2020-04-28 17:51 ` [PATCH v3 4/5] selftest/openat2: Add tests for RESOLVE_MAYEXEC enforcing Mickaël Salaün
2020-04-28 17:51 ` [PATCH v3 5/5] doc: Add documentation for the fs.open_mayexec_enforce sysctl Mickaël Salaün
2020-04-28 19:21 ` [PATCH v3 0/5] Add support for RESOLVE_MAYEXEC Jann Horn
2020-04-28 21:20   ` Florian Weimer
2020-04-28 22:01     ` Jann Horn
2020-04-29  8:50       ` Mickaël Salaün
2020-05-01 11:47       ` Christian Heimes
2020-05-05 14:57         ` Mickaël Salaün
2020-04-30  1:54 ` Aleksa Sarai
2020-04-30  8:07   ` Christian Brauner
2020-04-30 10:45     ` Mickaël Salaün
2020-05-01  3:53 ` James Morris

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).