Linux-Security-Module Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v5 00/12] S.A.R.A. a new stacked LSM
@ 2019-07-06 10:54 Salvatore Mesoraca
  2019-07-06 10:54 ` [PATCH v5 01/12] S.A.R.A.: add documentation Salvatore Mesoraca
                   ` (13 more replies)
  0 siblings, 14 replies; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 10:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Salvatore Mesoraca, Serge E. Hallyn, Thomas Gleixner

S.A.R.A. (S.A.R.A. is Another Recursive Acronym) is a stacked Linux
Security Module that aims to collect heterogeneous security measures,
providing a common interface to manage them.
It can be useful to allow minor security features to use advanced
management options, like user-space configuration files and tools, without
too much overhead.
Some submodules that use this framework are also introduced.
The code is quite long, I apologize for this. Thank you in advance to
anyone who will take the time to review this patchset.

S.A.R.A. is meant to be stacked but it needs cred blobs and the procattr
interface, so I temporarily implemented those parts in a way that won't
be acceptable for upstream, but it works for now. I know that there
is some ongoing work to make cred blobs and procattr stackable, as soon
as the new interfaces will be available I'll reimplement the involved
parts.
At the moment I've been able to test it only on x86.

The only submodule introduced in this patchset is WX Protection.

The kernel-space part is complemented by its user-space counterpart:
saractl [1].
A test suite for WX Protection, called sara-test [2], is also available.

WX Protection aims to improve user-space programs security by applying:
- W^X enforcement: program can't have a page of memory that is marked, at
                   the same time, writable and executable.
- W!->X restriction: any page that could have been marked as writable in
                     the past won't ever be allowed to be marked as
                     executable.
- Executable MMAP prevention: prevents the creation of new executable mmaps
                              after the dynamic libraries have been loaded.
All of the above features can be enabled or disabled both system wide
or on a per executable basis through the use of configuration files managed
by "saractl".
It is important to note that some programs may have issues working with
WX Protection. In particular:
- W^X enforcement will cause problems to any programs that needs
  memory pages mapped both as writable and executable at the same time e.g.
  programs with executable stack markings in the PT_GNU_STACK segment.
- W!->X restriction will cause problems to any program that
  needs to generate executable code at run time or to modify executable
  pages e.g. programs with a JIT compiler built-in or linked against a
  non-PIC library.
- Executable MMAP prevention can work only with programs that have at least
  partial RELRO support. It's disabled automatically for programs that
  lack this feature. It will cause problems to any program that uses dlopen
  or tries to do an executable mmap. Unfortunately this feature is the one
  that could create most problems and should be enabled only after careful
  evaluation.
To extend the scope of the above features, despite the issues that they may
cause, they are complemented by:
- procattr interface: can be used by a program to discover which WX
                      Protection features are enabled and/or to tighten
                      them.
- Trampoline emulation: emulates the execution of well-known "trampolines"
                        even when they are placed in non-executable memory.
Parts of WX Protection are inspired by some of the features available in
PaX.

Thanks to the addition of extended attributes support, it's now possible to
use S.A.R.A. without being forced to rely on any special userspace tool.

More information can be found in the documentation introduced in the first
patch and in the "commit message" of the following emails.

Changes in v2:
        - Removed USB filtering submodule and relative hook
        - s/saralib/libsara/ typo
        - STR macro renamed to avoid conflicts
        - check_vmflags hook now returns an error code instead of just 1
          or 0. (suggested by Casey Schaufler)
        - pr_wxp macro rewritten as function for readability
        - Fixed i386 compilation warnings
        - Documentation now states clearly that changes done via procattr
          interface only apply to current thread. (suggested by Jann Horn)

Changes in v3:
        - Documentation has been moved to match the new directory structure.
        - Kernel cmdline arguments are now accessed via module_param interface
          (suggested by Kees Cook).
        - Created "sara_warn_or_return" macro to make WX Protection code more
          readable (suggested by Kees Cook).
        - Added more comments, in the most important places, to clarify my
          intentions (suggested by Kees Cook).
        - The "pagefault_handler" hook has been rewritten in a more "arch
          agnostic" way. Though it only support x86 at the moment
          (suggested by Kees Cook).

Changes in v4:
        - Documentation improved and some mistakes have been fixed.
        - Reduced dmesg verbosity.
        - check_vmflags is now also used to decide whether to ignore 
          GNU executable stack markings or not.
        - Added the check_vmflags hook in setup_arg_pages too.
        - Added support for extended attributes.
        - Moved trampoline emulation to arch/x86/ (suggested by Kees Cook).
        - SARA_WXP_MMAP now depends on SARA_WXP_OTHER.
        - MAC_ADMIN capability is now required also for config read.
        - Some other minor fixes not worth mentionig here.

Changes in v5:
        - Updated the code to use the new stacking interface.
        - Path matching is now done using a DFA

Salvatore Mesoraca (12):
  S.A.R.A.: add documentation
  S.A.R.A.: create framework
  S.A.R.A.: cred blob management
  S.A.R.A.: generic DFA for string matching
  LSM: creation of "check_vmflags" LSM hook
  S.A.R.A.: WX protection
  LSM: creation of "pagefault_handler" LSM hook
  S.A.R.A.: trampoline emulation
  S.A.R.A.: WX protection procattr interface
  S.A.R.A.: XATTRs support
  S.A.R.A.: /proc/*/mem write limitation
  MAINTAINERS: take maintainership for S.A.R.A.

 Documentation/admin-guide/LSM/SARA.rst          | 197 +++++
 Documentation/admin-guide/LSM/index.rst         |   1 +
 Documentation/admin-guide/kernel-parameters.txt |  40 +
 MAINTAINERS                                     |   9 +
 arch/Kconfig                                    |   6 +
 arch/x86/Kbuild                                 |   2 +
 arch/x86/Kconfig                                |   1 +
 arch/x86/mm/fault.c                             |   6 +
 arch/x86/security/Makefile                      |   2 +
 arch/x86/security/sara/Makefile                 |   1 +
 arch/x86/security/sara/emutramp.c               |  57 ++
 arch/x86/security/sara/trampolines32.h          | 137 ++++
 arch/x86/security/sara/trampolines64.h          | 164 ++++
 fs/binfmt_elf.c                                 |   3 +-
 fs/binfmt_elf_fdpic.c                           |   3 +-
 fs/exec.c                                       |   4 +
 fs/proc/base.c                                  |  11 +
 include/linux/lsm_hooks.h                       |  19 +
 include/linux/security.h                        |  17 +
 include/uapi/linux/xattr.h                      |   4 +
 mm/mmap.c                                       |  13 +
 security/Kconfig                                |  11 +-
 security/Makefile                               |   2 +
 security/sara/Kconfig                           | 176 +++++
 security/sara/Makefile                          |   5 +
 security/sara/dfa.c                             | 335 ++++++++
 security/sara/dfa_test.c                        | 135 ++++
 security/sara/include/dfa.h                     |  52 ++
 security/sara/include/dfa_test.h                |  29 +
 security/sara/include/emutramp.h                |  35 +
 security/sara/include/sara.h                    |  29 +
 security/sara/include/sara_data.h               | 100 +++
 security/sara/include/securityfs.h              |  61 ++
 security/sara/include/utils.h                   |  80 ++
 security/sara/include/wxprot.h                  |  29 +
 security/sara/main.c                            | 134 ++++
 security/sara/sara_data.c                       |  77 ++
 security/sara/securityfs.c                      | 565 ++++++++++++++
 security/sara/utils.c                           |  92 +++
 security/sara/wxprot.c                          | 998 ++++++++++++++++++++++++
 security/security.c                             |  16 +
 41 files changed, 3651 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/admin-guide/LSM/SARA.rst
 create mode 100644 arch/x86/security/Makefile
 create mode 100644 arch/x86/security/sara/Makefile
 create mode 100644 arch/x86/security/sara/emutramp.c
 create mode 100644 arch/x86/security/sara/trampolines32.h
 create mode 100644 arch/x86/security/sara/trampolines64.h
 create mode 100644 security/sara/Kconfig
 create mode 100644 security/sara/Makefile
 create mode 100644 security/sara/dfa.c
 create mode 100644 security/sara/dfa_test.c
 create mode 100644 security/sara/include/dfa.h
 create mode 100644 security/sara/include/dfa_test.h
 create mode 100644 security/sara/include/emutramp.h
 create mode 100644 security/sara/include/sara.h
 create mode 100644 security/sara/include/sara_data.h
 create mode 100644 security/sara/include/securityfs.h
 create mode 100644 security/sara/include/utils.h
 create mode 100644 security/sara/include/wxprot.h
 create mode 100644 security/sara/main.c
 create mode 100644 security/sara/sara_data.c
 create mode 100644 security/sara/securityfs.c
 create mode 100644 security/sara/utils.c
 create mode 100644 security/sara/wxprot.c

-- 
1.9.1


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

* [PATCH v5 01/12] S.A.R.A.: add documentation
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
@ 2019-07-06 10:54 ` Salvatore Mesoraca
  2019-07-06 17:14   ` Randy Dunlap
  2019-07-13  0:14   ` James Morris
  2019-07-06 10:54 ` [PATCH v5 02/12] S.A.R.A.: create framework Salvatore Mesoraca
                   ` (12 subsequent siblings)
  13 siblings, 2 replies; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 10:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Salvatore Mesoraca, Serge E. Hallyn, Thomas Gleixner

Adding documentation for S.A.R.A. LSM.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 Documentation/admin-guide/LSM/SARA.rst          | 177 ++++++++++++++++++++++++
 Documentation/admin-guide/LSM/index.rst         |   1 +
 Documentation/admin-guide/kernel-parameters.txt |  24 ++++
 3 files changed, 202 insertions(+)
 create mode 100644 Documentation/admin-guide/LSM/SARA.rst

diff --git a/Documentation/admin-guide/LSM/SARA.rst b/Documentation/admin-guide/LSM/SARA.rst
new file mode 100644
index 0000000..fdde04c
--- /dev/null
+++ b/Documentation/admin-guide/LSM/SARA.rst
@@ -0,0 +1,177 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+========
+S.A.R.A.
+========
+
+S.A.R.A. (S.A.R.A. is Another Recursive Acronym) is a stacked Linux Security
+Module that aims to collect heterogeneous security measures, providing a common
+interface to manage them.
+As of today it consists of one submodule:
+
+- WX Protection
+
+
+The kernel-space part is complemented by its user-space counterpart: `saractl`
+[2]_.
+A test suite for WX Protection, called `sara-test` [4]_, is also available.
+More information about where to find these tools and the full S.A.R.A.
+documentation are in the `External Links and Documentation`_ section.
+
+-------------------------------------------------------------------------------
+
+S.A.R.A.'s Submodules
+=====================
+
+WX Protection
+-------------
+WX Protection aims to improve user-space programs security by applying:
+
+- `W^X enforcement`_
+- `W!->X (once writable never executable) mprotect restriction`_
+- `Executable MMAP prevention`_
+
+All of the above features can be enabled or disabled both system wide
+or on a per executable basis through the use of configuration files managed by
+`saractl` [2]_.
+
+It is important to note that some programs may have issues working with
+WX Protection. In particular:
+
+- **W^X enforcement** will cause problems to any programs that needs
+  memory pages mapped both as writable and executable at the same time e.g.
+  programs with executable stack markings in the *PT_GNU_STACK* segment.
+- **W!->X mprotect restriction** will cause problems to any program that
+  needs to generate executable code at run time or to modify executable
+  pages e.g. programs with a *JIT* compiler built-in or linked against a
+  *non-PIC* library.
+- **Executable MMAP prevention** can work only with programs that have at least
+  partial *RELRO* support. It's disabled automatically for programs that
+  lack this feature. It will cause problems to any program that uses *dlopen*
+  or tries to do an executable mmap. Unfortunately this feature is the one
+  that could create most problems and should be enabled only after careful
+  evaluation.
+
+To extend the scope of the above features, despite the issues that they may
+cause, they are complemented by **/proc/PID/attr/sara/wxprot** interface
+and **trampoline emulation**.
+
+At the moment, WX Protection (unless specified otherwise) should work on
+any architecture supporting the NX bit, including, but not limited to:
+`x86_64`, `x86_32` (with PAE), `ARM` and `ARM64`.
+
+Parts of WX Protection are inspired by some of the features available in PaX.
+
+For further information about configuration file format and user-space
+utilities please take a look at the full documentation [1]_.
+
+W^X enforcement
+^^^^^^^^^^^^^^^
+W^X means that a program can't have a page of memory that is marked, at the
+same time, writable and executable. This also allow to detect many bad
+behaviours that make life much more easy for attackers. Programs running with
+this feature enabled will be more difficult to exploit in the case they are
+affected by some vulnerabilities, because the attacker will be forced
+to make more steps in order to exploit them.
+This feature also blocks accesses to /proc/*/mem files that would allow to
+write the current process read-only memory, bypassing any protection.
+
+W!->X (once writable never executable) mprotect restriction
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+"Once writable never executable" means that any page that could have been
+marked as writable in the past won't ever be allowed to be marked (e.g. via
+an mprotect syscall) as executable.
+This goes on the same track as W^X, but is much stricter and prevents
+the runtime creation of new executable code in memory.
+Obviously, this feature does not prevent a program from creating a new file and
+*mmapping* it as executable, however, it will be way more difficult for
+attackers to exploit vulnerabilities if this feature is enabled.
+
+Executable MMAP prevention
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+This feature prevents the creation of new executable mmaps after the dynamic
+libraries have been loaded. When used in combination with **W!->X mprotect
+restriction** this feature will completely prevent the creation of new
+executable code from the current thread.
+Obviously, this feature does not prevent cases in which an attacker uses an
+*execve* to start a completely new program. This kind of restriction, if
+needed, can be applied using one of the other LSM that focuses on MAC.
+Please be aware that this feature can break many programs and so it should be
+enabled after careful evaluation.
+
+/proc/PID/attr/sara/wxprot interface
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The `procattr` interface can be used by a thread to discover which
+WX Protection features are enabled and/or to tighten them: protection
+can't be softened via procattr.
+The interface is simple: it's a text file with an hexadecimal
+number in it representing enabled features (more information can be
+found in the `Flags values`_ section). Via this interface it is also
+possible to perform a complete memory scan to remove the write permission
+from pages that are both writable and executable, please note that this
+change will also affect other threads of the same process.
+
+Protections that prevent the runtime creation of executable code
+can be troublesome for all those programs that actually need to do it
+e.g. programs shipping with a JIT compiler built-in.
+This feature can be use to run the JIT compiler with few restrictions
+while enforcing full WX Protection in the rest of the program.
+
+The preferred way to access this interface is via `libsara` [3]_.
+If you don't want it as a dependency, you can just statically link it
+in your project or copy/paste parts of it.
+To make things simpler `libsara` is the only part of S.A.R.A. released under
+*CC0 - No Rights Reserved* license.
+
+Trampoline emulation
+^^^^^^^^^^^^^^^^^^^^
+Some programs need to generate part of their code at runtime. Luckily enough,
+in some cases they only generate well-known code sequences (the
+*trampolines*) that can be easily recognized and emulated by the kernel.
+This way WX Protection can still be active, so a potential attacker won't be
+able to generate arbitrary sequences of code, but just those that are
+explicitly allowed. This is not ideal, but it's still better than having WX
+Protection completely disabled.
+
+In particular S.A.R.A. is able to recognize trampolines used by GCC for nested
+C functions and libffi's trampolines.
+This feature is available only on `x86_32` and `x86_64`.
+
+Flags values
+^^^^^^^^^^^^
+Flags are represented as a 16 bit unsigned integer in which every bit indicates
+the status of a given feature:
+
++------------------------------+----------+
+|           Feature            |  Value   |
++==============================+==========+
+| W!->X Heap                   |  0x0001  |
++------------------------------+----------+
+| W!->X Stack                  |  0x0002  |
++------------------------------+----------+
+| W!->X Other memory           |  0x0004  |
++------------------------------+----------+
+| W^X                          |  0x0008  |
++------------------------------+----------+
+| Don't enforce, just complain |  0x0010  |
++------------------------------+----------+
+| Be Verbose                   |  0x0020  |
++------------------------------+----------+
+| Executable MMAP prevention   |  0x0040  |
++------------------------------+----------+
+| Force W^X on setprocattr     |  0x0080  |
++------------------------------+----------+
+| Trampoline emulation         |  0x0100  |
++------------------------------+----------+
+| Children will inherit flags  |  0x0200  |
++------------------------------+----------+
+
+-------------------------------------------------------------------------------
+
+External Links and Documentation
+================================
+
+.. [1] `Documentation	<https://sara.smeso.it>`_
+.. [2] `saractl		<https://github.com/smeso/saractl>`_
+.. [3] `libsara		<https://github.com/smeso/libsara>`_
+.. [4] `sara-test	<https://github.com/smeso/sara-test>`_
diff --git a/Documentation/admin-guide/LSM/index.rst b/Documentation/admin-guide/LSM/index.rst
index a6ba95f..81b50e4 100644
--- a/Documentation/admin-guide/LSM/index.rst
+++ b/Documentation/admin-guide/LSM/index.rst
@@ -47,3 +47,4 @@ subdirectories.
    tomoyo
    Yama
    SafeSetID
+   SARA
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 138f666..3d6e86d 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -4230,6 +4230,30 @@
 			1 -- enable.
 			Default value is set via kernel config option.
 
+	sara.enabled=	[SARA] Disable or enable S.A.R.A. at boot time.
+			If disabled this way S.A.R.A. can't be enabled
+			again.
+			Format: { "0" | "1" }
+			See security/sara/Kconfig help text
+			0 -- disable.
+			1 -- enable.
+			Default value is set via kernel config option.
+
+	sara.wxprot_enabled= [SARA]
+			Disable or enable S.A.R.A. WX Protection
+			at boot time.
+			Format: { "0" | "1" }
+			See security/sara/Kconfig help text
+			0 -- disable.
+			1 -- enable.
+			Default value is set via kernel config option.
+
+	sara.wxprot_default_flags= [SARA]
+			Set S.A.R.A. WX Protection default flags.
+			Format: <integer>
+			See S.A.R.A. documentation.
+			Default value is set via kernel config option.
+
 	serialnumber	[BUGS=X86-32]
 
 	shapers=	[NET]
-- 
1.9.1


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

* [PATCH v5 02/12] S.A.R.A.: create framework
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
  2019-07-06 10:54 ` [PATCH v5 01/12] S.A.R.A.: add documentation Salvatore Mesoraca
@ 2019-07-06 10:54 ` Salvatore Mesoraca
  2019-07-06 15:29   ` Randy Dunlap
  2019-07-06 10:54 ` [PATCH v5 03/12] S.A.R.A.: cred blob management Salvatore Mesoraca
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 10:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Salvatore Mesoraca, Serge E. Hallyn, Thomas Gleixner

Initial S.A.R.A. framework setup.
Creation of a simplified interface to securityfs API to store and retrieve
configurations and flags from user-space.
Creation of some generic functions and macros to handle concurrent access
to configurations, memory allocation and path resolution.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 security/Kconfig                   |  11 +-
 security/Makefile                  |   2 +
 security/sara/Kconfig              |  40 +++
 security/sara/Makefile             |   3 +
 security/sara/include/sara.h       |  29 ++
 security/sara/include/securityfs.h |  61 ++++
 security/sara/include/utils.h      |  80 ++++++
 security/sara/main.c               | 115 ++++++++
 security/sara/securityfs.c         | 565 +++++++++++++++++++++++++++++++++++++
 security/sara/utils.c              |  92 ++++++
 10 files changed, 993 insertions(+), 5 deletions(-)
 create mode 100644 security/sara/Kconfig
 create mode 100644 security/sara/Makefile
 create mode 100644 security/sara/include/sara.h
 create mode 100644 security/sara/include/securityfs.h
 create mode 100644 security/sara/include/utils.h
 create mode 100644 security/sara/main.c
 create mode 100644 security/sara/securityfs.c
 create mode 100644 security/sara/utils.c

diff --git a/security/Kconfig b/security/Kconfig
index 466cc1f..4cae0ec 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -237,6 +237,7 @@ source "security/apparmor/Kconfig"
 source "security/loadpin/Kconfig"
 source "security/yama/Kconfig"
 source "security/safesetid/Kconfig"
+source "security/sara/Kconfig"
 
 source "security/integrity/Kconfig"
 
@@ -276,11 +277,11 @@ endchoice
 
 config LSM
 	string "Ordered list of enabled LSMs"
-	default "yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor" if DEFAULT_SECURITY_SMACK
-	default "yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" if DEFAULT_SECURITY_APPARMOR
-	default "yama,loadpin,safesetid,integrity,tomoyo" if DEFAULT_SECURITY_TOMOYO
-	default "yama,loadpin,safesetid,integrity" if DEFAULT_SECURITY_DAC
-	default "yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor"
+	default "yama,loadpin,safesetid,integrity,sara,smack,selinux,tomoyo,apparmor" if DEFAULT_SECURITY_SMACK
+	default "yama,loadpin,safesetid,integrity,sara,apparmor,selinux,smack,tomoyo" if DEFAULT_SECURITY_APPARMOR
+	default "yama,loadpin,safesetid,integrity,sara,tomoyo" if DEFAULT_SECURITY_TOMOYO
+	default "yama,loadpin,safesetid,integrity,sara" if DEFAULT_SECURITY_DAC
+	default "yama,loadpin,safesetid,integrity,sara,selinux,smack,tomoyo,apparmor"
 	help
 	  A comma-separated list of LSMs, in initialization order.
 	  Any LSMs left off this list will be ignored. This can be
diff --git a/security/Makefile b/security/Makefile
index c598b90..4b0fd11 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -11,6 +11,7 @@ subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
 subdir-$(CONFIG_SECURITY_YAMA)		+= yama
 subdir-$(CONFIG_SECURITY_LOADPIN)	+= loadpin
 subdir-$(CONFIG_SECURITY_SAFESETID)    += safesetid
+subdir-$(CONFIG_SECURITY_SARA)		+= sara
 
 # always enable default capabilities
 obj-y					+= commoncap.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/
 obj-$(CONFIG_SECURITY_YAMA)		+= yama/
 obj-$(CONFIG_SECURITY_LOADPIN)		+= loadpin/
 obj-$(CONFIG_SECURITY_SAFESETID)       += safesetid/
+obj-$(CONFIG_SECURITY_SARA)		+= sara/
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
 
 # Object integrity file lists
diff --git a/security/sara/Kconfig b/security/sara/Kconfig
new file mode 100644
index 0000000..0456220
--- /dev/null
+++ b/security/sara/Kconfig
@@ -0,0 +1,40 @@
+menuconfig SECURITY_SARA
+	bool "S.A.R.A."
+	depends on SECURITY
+	select SECURITYFS
+	default n
+	help
+	  This selects S.A.R.A. LSM which aims to collect heterogeneous
+	  security measures providing a common interface to manage them.
+	  This LSM will always be stacked with the selected primary LSM and
+	  other stacked LSMs.
+	  Further information can be found in
+	  Documentation/admin-guide/LSM/SARA.rst.
+
+	  If unsure, answer N.
+
+config SECURITY_SARA_DEFAULT_DISABLED
+	bool "S.A.R.A. will be disabled at boot."
+	depends on SECURITY_SARA
+	default n
+	help
+	  If you say Y here, S.A.R.A. will not be enabled at startup. You can
+	  override this option at boot time via "sara.enabled=[1|0]" kernel
+	  parameter or via user-space utilities.
+	  This option is useful for distro kernels.
+
+	  If unsure, answer N.
+
+config SECURITY_SARA_NO_RUNTIME_ENABLE
+	bool "S.A.R.A. can be turn on only at boot time."
+	depends on SECURITY_SARA_DEFAULT_DISABLED
+	default y
+	help
+	  By enabling this option it won't be possible to turn on S.A.R.A.
+	  at runtime via user-space utilities. However it can still be
+	  turned on at boot time via the "sara.enabled=1" kernel parameter.
+	  This option is functionally equivalent to "sara.enabled=0" kernel
+	  parameter. This option is useful for distro kernels.
+
+	  If unsure, answer Y.
+
diff --git a/security/sara/Makefile b/security/sara/Makefile
new file mode 100644
index 0000000..8acd291
--- /dev/null
+++ b/security/sara/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SECURITY_SARA) := sara.o
+
+sara-y := main.o securityfs.o utils.o
diff --git a/security/sara/include/sara.h b/security/sara/include/sara.h
new file mode 100644
index 0000000..cd12f52
--- /dev/null
+++ b/security/sara/include/sara.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __SARA_H
+#define __SARA_H
+
+#include <linux/types.h>
+#include <uapi/linux/limits.h>
+
+#define SARA_VERSION 0
+#define SARA_PATH_MAX PATH_MAX
+
+#undef pr_fmt
+#define pr_fmt(fmt) "SARA: " fmt
+
+extern int sara_config_locked __read_mostly;
+extern int sara_enabled __read_mostly;
+
+#endif /* __SARA_H */
diff --git a/security/sara/include/securityfs.h b/security/sara/include/securityfs.h
new file mode 100644
index 0000000..92d6180
--- /dev/null
+++ b/security/sara/include/securityfs.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __SARA_SECURITYFS_H
+#define __SARA_SECURITYFS_H
+
+#include <linux/init.h>
+
+#define SARA_SUBTREE_NN_LEN 24
+#define SARA_CONFIG_HASH_LEN 20
+
+struct sara_secfs_node;
+
+int sara_secfs_init(void) __init;
+int sara_secfs_subtree_register(const char *subtree_name,
+				const struct sara_secfs_node *nodes,
+				size_t size) __init;
+
+enum sara_secfs_node_type {
+	SARA_SECFS_BOOL,
+	SARA_SECFS_READONLY_INT,
+	SARA_SECFS_CONFIG_LOAD,
+	SARA_SECFS_CONFIG_DUMP,
+	SARA_SECFS_CONFIG_HASH,
+};
+
+struct sara_secfs_node {
+	const enum sara_secfs_node_type type;
+	void *const data;
+	const size_t dir_contents_len;
+	const char name[SARA_SUBTREE_NN_LEN];
+};
+
+struct sara_secfs_fptrs {
+	int (*const load)(const char *, size_t);
+	ssize_t (*const dump)(char **);
+	int (*const hash)(char **);
+};
+
+struct sara_secfs_bool_flag {
+	const char notice_line[SARA_SUBTREE_NN_LEN];
+	int *const flag;
+};
+
+#define DEFINE_SARA_SECFS_BOOL_FLAG(NAME, VAR)		\
+const struct sara_secfs_bool_flag NAME = {		\
+	.notice_line = #VAR,				\
+	.flag = &(VAR),					\
+}
+
+#endif /* __SARA_SECURITYFS_H */
diff --git a/security/sara/include/utils.h b/security/sara/include/utils.h
new file mode 100644
index 0000000..ce9d5fb
--- /dev/null
+++ b/security/sara/include/utils.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __SARA_UTILS_H
+#define __SARA_UTILS_H
+
+#include <linux/kref.h>
+#include <linux/rcupdate.h>
+#include <linux/spinlock.h>
+
+char *get_absolute_path(const struct path *spath, char **buf);
+char *get_current_path(char **buf);
+
+static inline void release_entry(struct kref *ref)
+{
+	/* All work is done after the return from kref_put(). */
+}
+
+
+/*
+ * The following macros must be used to access S.A.R.A. configuration
+ * structures.
+ * They are thread-safe under the assumption that a configuration
+ * won't ever be deleted but just replaced using SARA_CONFIG_REPLACE,
+ * possibly using an empty configuration.
+ * i.e. every call to SARA_CONFIG_PUT *must* be preceded by a matching
+ * SARA_CONFIG_GET invocation.
+ */
+
+#define SARA_CONFIG_GET_RCU(DEST, CONFIG) do {	\
+	rcu_read_lock();			\
+	(DEST) = rcu_dereference(CONFIG);	\
+} while (0)
+
+#define SARA_CONFIG_PUT_RCU(DATA) do {		\
+	rcu_read_unlock();			\
+	(DATA) = NULL;				\
+} while (0)
+
+#define SARA_CONFIG_GET(DEST, CONFIG) do {				\
+	rcu_read_lock();						\
+	do {								\
+		(DEST) = rcu_dereference(CONFIG);			\
+	} while ((DEST) && !kref_get_unless_zero(&(DEST)->refcount));	\
+	rcu_read_unlock();						\
+} while (0)
+
+#define SARA_CONFIG_PUT(DATA, FREE) do {			\
+	if (kref_put(&(DATA)->refcount, release_entry)) {	\
+		synchronize_rcu();				\
+		(FREE)(DATA);					\
+	}							\
+	(DATA) = NULL;						\
+} while (0)
+
+#define SARA_CONFIG_REPLACE(CONFIG, NEW, FREE, LOCK) do {	\
+	typeof(NEW) tmp;					\
+	spin_lock(LOCK);					\
+	tmp = rcu_dereference_protected(CONFIG,			\
+					lockdep_is_held(LOCK));	\
+	rcu_assign_pointer(CONFIG, NEW);			\
+	if (kref_put(&tmp->refcount, release_entry)) {		\
+		spin_unlock(LOCK);				\
+		synchronize_rcu();				\
+		FREE(tmp);					\
+	} else							\
+		spin_unlock(LOCK);				\
+} while (0)
+
+#endif /* __SARA_UTILS_H */
diff --git a/security/sara/main.c b/security/sara/main.c
new file mode 100644
index 0000000..52e6d18
--- /dev/null
+++ b/security/sara/main.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/lsm_hooks.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+
+#include "include/sara.h"
+#include "include/securityfs.h"
+
+static const int sara_version = SARA_VERSION;
+
+#ifdef CONFIG_SECURITY_SARA_NO_RUNTIME_ENABLE
+int sara_config_locked __read_mostly = true;
+#else
+int sara_config_locked __read_mostly;
+#endif
+
+#ifdef CONFIG_SECURITY_SARA_DEFAULT_DISABLED
+int sara_enabled __read_mostly;
+#else
+int sara_enabled __read_mostly = true;
+#endif
+
+static DEFINE_SARA_SECFS_BOOL_FLAG(sara_enabled_data, sara_enabled);
+static DEFINE_SARA_SECFS_BOOL_FLAG(sara_config_locked_data, sara_config_locked);
+
+static int param_set_senabled(const char *val, const struct kernel_param *kp)
+{
+	if (!val)
+		return 0;
+	if (strtobool(val, kp->arg))
+		return -EINVAL;
+	/* config must by locked when S.A.R.A. is disabled at boot
+	 * and unlocked when it's enabled
+	 */
+	sara_config_locked = !(*(int *) kp->arg);
+	return 0;
+}
+
+static struct kernel_param_ops param_ops_senabled = {
+	.set = param_set_senabled,
+};
+
+#define param_check_senabled(name, p) __param_check(name, p, int)
+
+module_param_named(enabled, sara_enabled, senabled, 0000);
+MODULE_PARM_DESC(enabled, "Disable or enable S.A.R.A. at boot time. If disabled this way S.A.R.A. can't be enabled again.");
+
+static const struct sara_secfs_node main_fs[] __initconst = {
+	{
+		.name = "enabled",
+		.type = SARA_SECFS_BOOL,
+		.data = (void *) &sara_enabled_data,
+	},
+	{
+		.name = "locked",
+		.type = SARA_SECFS_BOOL,
+		.data = (void *) &sara_config_locked_data,
+	},
+	{
+		.name = "version",
+		.type = SARA_SECFS_READONLY_INT,
+		.data = (int *) &sara_version,
+	},
+};
+
+static int __init sara_init(void)
+{
+	if (!sara_enabled && sara_config_locked) {
+		pr_notice("permanently disabled.\n");
+		return 0;
+	}
+
+	pr_debug("initializing...\n");
+
+	if (sara_secfs_subtree_register("main",
+					main_fs,
+					ARRAY_SIZE(main_fs))) {
+		pr_crit("impossible to register main fs.\n");
+		goto error;
+	}
+
+	pr_debug("initialized.\n");
+
+	if (sara_enabled)
+		pr_info("enabled\n");
+	else
+		pr_notice("disabled\n");
+	return 0;
+
+error:
+	sara_enabled = false;
+	sara_config_locked = true;
+	pr_crit("permanently disabled.\n");
+	return 1;
+}
+
+DEFINE_LSM(sara) = {
+	.name = "sara",
+	.enabled = &sara_enabled,
+	.init = sara_init,
+};
diff --git a/security/sara/securityfs.c b/security/sara/securityfs.c
new file mode 100644
index 0000000..f6b152c
--- /dev/null
+++ b/security/sara/securityfs.c
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/capability.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/printk.h>
+#include <linux/security.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+
+#include "include/sara.h"
+#include "include/utils.h"
+#include "include/securityfs.h"
+
+#define __SARA_STR_HELPER(x) #x
+#define SARA_STR(x) __SARA_STR_HELPER(x)
+
+static struct dentry *fs_root;
+
+static inline bool check_config_write_access(void)
+{
+	if (unlikely(sara_config_locked)) {
+		pr_warn("config write access blocked.\n");
+		return false;
+	}
+	return true;
+}
+
+static bool check_config_access(const struct file *file)
+{
+	if (!capable(CAP_MAC_ADMIN))
+		return false;
+	if (file->f_flags & O_WRONLY || file->f_flags & O_RDWR)
+		if (unlikely(!check_config_write_access()))
+			return false;
+	return true;
+}
+
+static int file_flag_show(struct seq_file *seq, void *v)
+{
+	int *flag = ((struct sara_secfs_bool_flag *)seq->private)->flag;
+
+	seq_printf(seq, "%d\n", *flag);
+	return 0;
+}
+
+static ssize_t file_flag_write(struct file *file,
+				const char __user *ubuf,
+				size_t buf_size,
+				loff_t *offset)
+{
+	struct sara_secfs_bool_flag *bool_flag =
+		((struct seq_file *) file->private_data)->private;
+	char kbuf[2] = {'A', '\n'};
+	int nf;
+
+	if (unlikely(*offset != 0))
+		return -ESPIPE;
+
+	if (unlikely(buf_size != 1 && buf_size != 2))
+		return -EPERM;
+
+	if (unlikely(copy_from_user(kbuf, ubuf, buf_size)))
+		return -EFAULT;
+
+	if (unlikely(kbuf[1] != '\n'))
+		return -EPERM;
+
+	switch (kbuf[0]) {
+	case '0':
+		nf = false;
+		break;
+	case '1':
+		nf = true;
+		break;
+	default:
+		return -EPERM;
+	}
+
+	*bool_flag->flag = nf;
+
+	if (strlen(bool_flag->notice_line) > 0)
+		pr_notice("flag \"%s\" set to %d\n",
+			  bool_flag->notice_line,
+			  nf);
+
+	return buf_size;
+}
+
+static int file_flag_open(struct inode *inode, struct file *file)
+{
+	if (unlikely(!check_config_access(file)))
+		return -EACCES;
+	return single_open(file, file_flag_show, inode->i_private);
+}
+
+static const struct file_operations file_flag = {
+	.owner		= THIS_MODULE,
+	.open		= file_flag_open,
+	.write		= file_flag_write,
+	.read		= seq_read,
+	.release	= single_release,
+};
+
+static int file_readonly_int_show(struct seq_file *seq, void *v)
+{
+	int *flag = seq->private;
+
+	seq_printf(seq, "%d\n", *flag);
+	return 0;
+}
+
+static int file_readonly_int_open(struct inode *inode, struct file *file)
+{
+	if (unlikely(!check_config_access(file)))
+		return -EACCES;
+	return single_open(file, file_readonly_int_show, inode->i_private);
+}
+
+static const struct file_operations file_readonly_int = {
+	.owner		= THIS_MODULE,
+	.open		= file_readonly_int_open,
+	.read		= seq_read,
+	.release	= single_release,
+};
+
+static ssize_t file_config_loader_write(struct file *file,
+					const char __user *ubuf,
+					size_t buf_size,
+					loff_t *offset)
+{
+	const struct sara_secfs_fptrs *fptrs = file->private_data;
+	char *kbuf = NULL;
+	ssize_t ret;
+
+	ret = -ESPIPE;
+	if (unlikely(*offset != 0))
+		goto out;
+
+	ret = -ENOMEM;
+	kbuf = kvmalloc(buf_size, GFP_KERNEL_ACCOUNT);
+	if (unlikely(kbuf == NULL))
+		goto out;
+
+	ret = -EFAULT;
+	if (unlikely(copy_from_user(kbuf, ubuf, buf_size)))
+		goto out;
+
+	ret = fptrs->load(kbuf, buf_size);
+
+	if (unlikely(ret))
+		goto out;
+
+	ret = buf_size;
+
+out:
+	kvfree(kbuf);
+	return ret;
+}
+
+static int file_config_loader_open(struct inode *inode, struct file *file)
+{
+	if (unlikely(!check_config_access(file)))
+		return -EACCES;
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations file_config_loader = {
+	.owner		= THIS_MODULE,
+	.open		= file_config_loader_open,
+	.write		= file_config_loader_write,
+};
+
+static int file_config_show(struct seq_file *seq, void *v)
+{
+	const struct sara_secfs_fptrs *fptrs = seq->private;
+	char *buf = NULL;
+	ssize_t ret;
+
+	ret = fptrs->dump(&buf);
+	if (unlikely(ret <= 0))
+		goto out;
+	seq_write(seq, buf, ret);
+	kvfree(buf);
+	ret = 0;
+out:
+	return ret;
+}
+
+static int file_dumper_open(struct inode *inode, struct file *file)
+{
+	if (unlikely(!check_config_access(file)))
+		return -EACCES;
+	return single_open(file, file_config_show, inode->i_private);
+}
+
+static const struct file_operations file_config_dumper = {
+	.owner		= THIS_MODULE,
+	.open		= file_dumper_open,
+	.read		= seq_read,
+	.release	= single_release,
+};
+
+static int file_hash_show(struct seq_file *seq, void *v)
+{
+	const struct sara_secfs_fptrs *fptrs = seq->private;
+	char *buf = NULL;
+	int ret;
+
+	ret = fptrs->hash(&buf);
+	if (unlikely(ret))
+		goto out;
+	seq_printf(seq, "%" SARA_STR(SARA_CONFIG_HASH_LEN) "phN\n", buf);
+	kvfree(buf);
+	ret = 0;
+out:
+	return ret;
+}
+
+static int file_hash_open(struct inode *inode, struct file *file)
+{
+	if (unlikely(!check_config_access(file)))
+		return -EACCES;
+	return single_open(file, file_hash_show, inode->i_private);
+}
+
+static const struct file_operations file_hash = {
+	.owner		= THIS_MODULE,
+	.open		= file_hash_open,
+	.read		= seq_read,
+	.release	= single_release,
+};
+
+static int mk_dir(struct dentry *parent,
+		const char *dir_name,
+		struct dentry **dir_out)
+{
+	int ret = 0;
+
+	*dir_out = securityfs_create_dir(dir_name, parent);
+	if (IS_ERR(*dir_out)) {
+		ret = -PTR_ERR(*dir_out);
+		*dir_out = NULL;
+	}
+	return ret;
+}
+
+static int mk_bool_flag(struct dentry *parent,
+			const char *file_name,
+			struct dentry **dir_out,
+			void *flag)
+{
+	int ret = 0;
+
+	*dir_out = securityfs_create_file(file_name,
+					0600,
+					parent,
+					flag,
+					&file_flag);
+	if (IS_ERR(*dir_out)) {
+		ret = -PTR_ERR(*dir_out);
+		*dir_out = NULL;
+	}
+	return ret;
+}
+
+static int mk_readonly_int(struct dentry *parent,
+			const char *file_name,
+			struct dentry **dir_out,
+			void *readonly_int)
+{
+	int ret = 0;
+
+	*dir_out = securityfs_create_file(file_name,
+					0400,
+					parent,
+					readonly_int,
+					&file_readonly_int);
+	if (IS_ERR(*dir_out)) {
+		ret = -PTR_ERR(*dir_out);
+		*dir_out = NULL;
+	}
+	return ret;
+}
+
+static int mk_config_loader(struct dentry *parent,
+			const char *file_name,
+			struct dentry **dir_out,
+			void *fptrs)
+{
+	int ret = 0;
+
+	*dir_out = securityfs_create_file(file_name,
+					0200,
+					parent,
+					fptrs,
+					&file_config_loader);
+	if (IS_ERR(*dir_out)) {
+		ret = -PTR_ERR(*dir_out);
+		*dir_out = NULL;
+	}
+	return ret;
+}
+
+static int mk_config_dumper(struct dentry *parent,
+				const char *file_name,
+				struct dentry **dir_out,
+				void *fptrs)
+{
+	int ret = 0;
+
+	*dir_out = securityfs_create_file(file_name,
+					0400,
+					parent,
+					fptrs,
+					&file_config_dumper);
+	if (IS_ERR(*dir_out)) {
+		ret = -PTR_ERR(*dir_out);
+		*dir_out = NULL;
+	}
+	return ret;
+}
+
+static int mk_config_hash(struct dentry *parent,
+			const char *file_name,
+			struct dentry **dir_out,
+			void *fptrs)
+{
+	int ret = 0;
+
+	*dir_out = securityfs_create_file(file_name,
+					0400,
+					parent,
+					fptrs,
+					&file_hash);
+	if (IS_ERR(*dir_out)) {
+		ret = -PTR_ERR(*dir_out);
+		*dir_out = NULL;
+	}
+	return ret;
+}
+
+struct sara_secfs_subtree {
+	char name[SARA_SUBTREE_NN_LEN];
+	size_t size;
+	struct dentry **nodes;
+	const struct sara_secfs_node *nodes_description;
+	struct list_head subtree_list;
+};
+
+static LIST_HEAD(subtree_list);
+
+int __init sara_secfs_subtree_register(const char *subtree_name,
+				const struct sara_secfs_node *nodes,
+				size_t size)
+{
+	int ret;
+	struct sara_secfs_subtree *subtree = NULL;
+
+	ret = -EINVAL;
+	if (unlikely(size < 1))
+		goto error;
+	ret = -ENOMEM;
+	subtree = kmalloc(sizeof(*subtree), GFP_KERNEL);
+	if (unlikely(subtree == NULL))
+		goto error;
+	strncpy(subtree->name,
+		subtree_name,
+		sizeof(subtree->name));
+	subtree->name[sizeof(subtree->name)-1] = '\0';
+	subtree->size = size+1;
+	subtree->nodes = kcalloc(subtree->size,
+				sizeof(*subtree->nodes),
+				GFP_KERNEL);
+	if (unlikely(subtree->nodes == NULL))
+		goto error;
+	subtree->nodes_description = nodes;
+	INIT_LIST_HEAD(&subtree->subtree_list);
+	list_add(&subtree->subtree_list, &subtree_list);
+	return 0;
+
+error:
+	kfree(subtree);
+	pr_warn("SECFS: Impossible to register '%s' (%d).\n",
+		subtree_name, ret);
+	return ret;
+}
+
+static inline int __init create_node(enum sara_secfs_node_type type,
+					struct dentry *parent,
+					const char *name,
+					struct dentry **output,
+					void *data)
+{
+	switch (type) {
+	case SARA_SECFS_BOOL:
+		return mk_bool_flag(parent, name, output, data);
+	case SARA_SECFS_READONLY_INT:
+		return mk_readonly_int(parent, name, output, data);
+	case SARA_SECFS_CONFIG_LOAD:
+		return mk_config_loader(parent, name, output, data);
+	case SARA_SECFS_CONFIG_DUMP:
+		return mk_config_dumper(parent, name, output, data);
+	case SARA_SECFS_CONFIG_HASH:
+		return mk_config_hash(parent, name, output, data);
+	default:
+		return -EINVAL;
+	}
+}
+
+static void subtree_unplug(struct sara_secfs_subtree *subtree)
+{
+	int i;
+
+	for (i = 0; i < subtree->size; ++i) {
+		if (subtree->nodes[i] != NULL) {
+			securityfs_remove(subtree->nodes[i]);
+			subtree->nodes[i] = NULL;
+		}
+	}
+}
+
+static int __init subtree_plug(struct sara_secfs_subtree *subtree)
+{
+	int ret;
+	int i;
+	const struct sara_secfs_node *nodes = subtree->nodes_description;
+
+	ret = -EINVAL;
+	if (unlikely(fs_root == NULL))
+		goto out;
+	ret = mk_dir(fs_root,
+			subtree->name,
+			&subtree->nodes[subtree->size-1]);
+	if (unlikely(ret))
+		goto out_unplug;
+	for (i = 0; i < subtree->size-1; ++i) {
+		ret = create_node(nodes[i].type,
+				  subtree->nodes[subtree->size-1],
+				  nodes[i].name,
+				  &subtree->nodes[i],
+				  nodes[i].data);
+		if (unlikely(ret))
+			goto out_unplug;
+	}
+	return 0;
+
+out_unplug:
+	subtree_unplug(subtree);
+out:
+	pr_warn("SECFS: Impossible to plug '%s' (%d).\n", subtree->name, ret);
+	return ret;
+}
+
+static int __init subtree_plug_all(void)
+{
+	int ret;
+	struct list_head *position;
+	struct sara_secfs_subtree *subtree;
+
+	ret = -EINVAL;
+	if (unlikely(fs_root == NULL))
+		goto out;
+	ret = 0;
+	list_for_each(position, &subtree_list) {
+		subtree = list_entry(position,
+					struct sara_secfs_subtree,
+					subtree_list);
+		if (subtree->nodes[0] == NULL) {
+			ret = subtree_plug(subtree);
+			if (unlikely(ret))
+				goto out;
+		}
+	}
+out:
+	if (unlikely(ret))
+		pr_warn("SECFS: Impossible to plug subtrees (%d).\n", ret);
+	return ret;
+}
+
+static void __init subtree_free_all(bool unplug)
+{
+	struct list_head *position;
+	struct list_head *next;
+	struct sara_secfs_subtree *subtree;
+
+	list_for_each_safe(position, next, &subtree_list) {
+		subtree = list_entry(position,
+					struct sara_secfs_subtree,
+					subtree_list);
+		list_del(position);
+		if (unplug)
+			subtree_unplug(subtree);
+		kfree(subtree->nodes);
+		kfree(subtree);
+	}
+}
+
+static int mk_root(void)
+{
+	int ret = -1;
+
+	if (fs_root == NULL)
+		ret = mk_dir(NULL, "sara", &fs_root);
+	if (unlikely(ret || fs_root == NULL))
+		pr_warn("SECFS: Impossible to create root (%d).\n", ret);
+	return ret;
+}
+
+static inline void rm_root(void)
+{
+	if (likely(fs_root != NULL)) {
+		securityfs_remove(fs_root);
+		fs_root = NULL;
+	}
+}
+
+static inline void __init sara_secfs_destroy(void)
+{
+	subtree_free_all(true);
+	rm_root();
+}
+
+int __init sara_secfs_init(void)
+{
+	int ret;
+
+	if (!sara_enabled && sara_config_locked)
+		return 0;
+
+	fs_root = NULL;
+
+	ret = mk_root();
+	if (unlikely(ret))
+		goto error;
+
+	ret = subtree_plug_all();
+	if (unlikely(ret))
+		goto error;
+
+	subtree_free_all(false);
+
+	pr_debug("securityfs initilaized.\n");
+	return 0;
+
+error:
+	sara_secfs_destroy();
+	pr_crit("impossible to build securityfs.\n");
+	return ret;
+}
+
+fs_initcall(sara_secfs_init);
diff --git a/security/sara/utils.c b/security/sara/utils.c
new file mode 100644
index 0000000..d63febb
--- /dev/null
+++ b/security/sara/utils.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/dcache.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include "include/sara.h"
+#include "include/utils.h"
+
+/**
+ * get_absolute_path - return the absolute path for a struct path
+ * @spath: the struct path to report
+ * @buf: double pointer where the newly allocated buffer will be placed
+ *
+ * Returns a pointer into @buf or an error code.
+ *
+ * The caller MUST kvfree @buf when finished using it.
+ */
+char *get_absolute_path(const struct path *spath, char **buf)
+{
+	size_t size = 128;
+	char *work_buf = NULL;
+	char *path = NULL;
+
+	do {
+		kvfree(work_buf);
+		work_buf = NULL;
+		if (size > SARA_PATH_MAX) {
+			path = ERR_PTR(-ENAMETOOLONG);
+			goto error;
+		}
+		work_buf = kvmalloc(size, GFP_KERNEL);
+		if (unlikely(work_buf == NULL)) {
+			path = ERR_PTR(-ENOMEM);
+			goto error;
+		}
+		path = d_absolute_path(spath, work_buf, size);
+		size *= 2;
+	} while (PTR_ERR(path) == -ENAMETOOLONG);
+	if (!IS_ERR(path))
+		goto out;
+
+error:
+	kvfree(work_buf);
+	work_buf = NULL;
+out:
+	*buf = work_buf;
+	return path;
+}
+
+/**
+ * get_current_path - return the absolute path for the exe_file
+ *		      in the current task_struct, falling back
+ *		      to the contents of the comm field.
+ * @buf: double pointer where the newly allocated buffer will be placed
+ *
+ * Returns a pointer into @buf or an error code.
+ *
+ * The caller MUST kvfree @buf when finished using it.
+ */
+char *get_current_path(char **buf)
+{
+	struct file *exe_file;
+	char *path = NULL;
+
+	exe_file = get_task_exe_file(current);
+	if (exe_file) {
+		path = get_absolute_path(&exe_file->f_path, buf);
+		fput(exe_file);
+	}
+	if (IS_ERR_OR_NULL(path)) {
+		*buf = kzalloc(TASK_COMM_LEN, GFP_KERNEL);
+		__get_task_comm(*buf, TASK_COMM_LEN, current);
+		path = *buf;
+	}
+	return path;
+}
-- 
1.9.1


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

* [PATCH v5 03/12] S.A.R.A.: cred blob management
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
  2019-07-06 10:54 ` [PATCH v5 01/12] S.A.R.A.: add documentation Salvatore Mesoraca
  2019-07-06 10:54 ` [PATCH v5 02/12] S.A.R.A.: create framework Salvatore Mesoraca
@ 2019-07-06 10:54 ` Salvatore Mesoraca
  2019-07-12 23:35   ` James Morris
  2019-07-06 10:54 ` [PATCH v5 04/12] S.A.R.A.: generic DFA for string matching Salvatore Mesoraca
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 10:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Salvatore Mesoraca, Serge E. Hallyn, Thomas Gleixner

Creation of the S.A.R.A. cred blob management "API".
In order to allow S.A.R.A. to be stackable with other LSMs, it doesn't use
the "security" field of struct cred, instead it uses an ad hoc field named
security_sara.
This solution is probably not acceptable for upstream, so this part will
be modified as soon as the LSM stackable cred blob management will be
available.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 security/sara/Makefile            |  2 +-
 security/sara/include/sara_data.h | 84 +++++++++++++++++++++++++++++++++++++++
 security/sara/main.c              |  7 ++++
 security/sara/sara_data.c         | 69 ++++++++++++++++++++++++++++++++
 4 files changed, 161 insertions(+), 1 deletion(-)
 create mode 100644 security/sara/include/sara_data.h
 create mode 100644 security/sara/sara_data.c

diff --git a/security/sara/Makefile b/security/sara/Makefile
index 8acd291..14bf7a8 100644
--- a/security/sara/Makefile
+++ b/security/sara/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_SECURITY_SARA) := sara.o
 
-sara-y := main.o securityfs.o utils.o
+sara-y := main.o securityfs.o utils.o sara_data.o
diff --git a/security/sara/include/sara_data.h b/security/sara/include/sara_data.h
new file mode 100644
index 0000000..9216c47
--- /dev/null
+++ b/security/sara/include/sara_data.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __SARA_DATA_H
+#define __SARA_DATA_H
+
+#include <linux/cred.h>
+#include <linux/init.h>
+#include <linux/lsm_hooks.h>
+#include <linux/spinlock.h>
+
+int sara_data_init(void) __init;
+
+extern struct lsm_blob_sizes sara_blob_sizes __lsm_ro_after_init;
+
+#ifdef CONFIG_SECURITY_SARA_WXPROT
+
+struct sara_data {
+	unsigned long	relro_page;
+	struct file	*relro_file;
+	u16		wxp_flags;
+	u16		execve_flags;
+	bool		relro_page_found;
+	bool		mmap_blocked;
+};
+
+struct sara_shm_data {
+	bool		no_exec;
+	bool		no_write;
+	spinlock_t	lock;
+};
+
+
+static inline struct sara_data *get_sara_data(const struct cred *cred)
+{
+	return cred->security + sara_blob_sizes.lbs_cred;
+}
+
+#define get_current_sara_data() get_sara_data(current_cred())
+
+#define get_sara_wxp_flags(X) (get_sara_data((X))->wxp_flags)
+#define get_current_sara_wxp_flags() get_sara_wxp_flags(current_cred())
+
+#define get_sara_execve_flags(X) (get_sara_data((X))->execve_flags)
+#define get_current_sara_execve_flags() get_sara_execve_flags(current_cred())
+
+#define get_sara_relro_page(X) (get_sara_data((X))->relro_page)
+#define get_current_sara_relro_page() get_sara_relro_page(current_cred())
+
+#define get_sara_relro_file(X) (get_sara_data((X))->relro_file)
+#define get_current_sara_relro_file() get_sara_relro_file(current_cred())
+
+#define get_sara_relro_page_found(X) (get_sara_data((X))->relro_page_found)
+#define get_current_sara_relro_page_found() \
+	get_sara_relro_page_found(current_cred())
+
+#define get_sara_mmap_blocked(X) (get_sara_data((X))->mmap_blocked)
+#define get_current_sara_mmap_blocked() get_sara_mmap_blocked(current_cred())
+
+
+static inline struct sara_shm_data *get_sara_shm_data(
+					const struct kern_ipc_perm *ipc)
+{
+	return ipc->security + sara_blob_sizes.lbs_ipc;
+}
+
+#define get_sara_shm_no_exec(X) (get_sara_shm_data((X))->no_exec)
+#define get_sara_shm_no_write(X) (get_sara_shm_data((X))->no_write)
+#define lock_sara_shm(X) (spin_lock(&get_sara_shm_data((X))->lock))
+#define unlock_sara_shm(X) (spin_unlock(&get_sara_shm_data((X))->lock))
+
+#endif
+
+#endif /* __SARA_H */
diff --git a/security/sara/main.c b/security/sara/main.c
index 52e6d18..dc5dda4 100644
--- a/security/sara/main.c
+++ b/security/sara/main.c
@@ -18,6 +18,7 @@
 #include <linux/printk.h>
 
 #include "include/sara.h"
+#include "include/sara_data.h"
 #include "include/securityfs.h"
 
 static const int sara_version = SARA_VERSION;
@@ -93,6 +94,11 @@ static int __init sara_init(void)
 		goto error;
 	}
 
+	if (sara_data_init()) {
+		pr_crit("impossible to initialize creds.\n");
+		goto error;
+	}
+
 	pr_debug("initialized.\n");
 
 	if (sara_enabled)
@@ -112,4 +118,5 @@ static int __init sara_init(void)
 	.name = "sara",
 	.enabled = &sara_enabled,
 	.init = sara_init,
+	.blobs = &sara_blob_sizes,
 };
diff --git a/security/sara/sara_data.c b/security/sara/sara_data.c
new file mode 100644
index 0000000..9afca37
--- /dev/null
+++ b/security/sara/sara_data.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include "include/sara_data.h"
+
+#ifdef CONFIG_SECURITY_SARA_WXPROT
+#include <linux/cred.h>
+#include <linux/lsm_hooks.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+
+static int sara_cred_prepare(struct cred *new, const struct cred *old,
+			     gfp_t gfp)
+{
+	*get_sara_data(new) = *get_sara_data(old);
+	return 0;
+}
+
+static void sara_cred_transfer(struct cred *new, const struct cred *old)
+{
+	*get_sara_data(new) = *get_sara_data(old);
+}
+
+static int sara_shm_alloc_security(struct kern_ipc_perm *shp)
+{
+	struct sara_shm_data *d;
+
+	d = get_sara_shm_data(shp);
+	spin_lock_init(&d->lock);
+	return 0;
+}
+
+static struct security_hook_list data_hooks[] __lsm_ro_after_init = {
+	LSM_HOOK_INIT(cred_prepare, sara_cred_prepare),
+	LSM_HOOK_INIT(cred_transfer, sara_cred_transfer),
+	LSM_HOOK_INIT(shm_alloc_security, sara_shm_alloc_security),
+};
+
+struct lsm_blob_sizes sara_blob_sizes __lsm_ro_after_init = {
+	.lbs_cred = sizeof(struct sara_data),
+	.lbs_ipc = sizeof(struct sara_shm_data),
+};
+
+int __init sara_data_init(void)
+{
+	security_add_hooks(data_hooks, ARRAY_SIZE(data_hooks), "sara");
+	return 0;
+}
+
+#else /* CONFIG_SECURITY_SARA_WXPROT */
+
+struct lsm_blob_sizes sara_blob_sizes __lsm_ro_after_init = { };
+
+int __init sara_data_init(void)
+{
+	return 0;
+}
+
+#endif
-- 
1.9.1


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

* [PATCH v5 04/12] S.A.R.A.: generic DFA for string matching
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
                   ` (2 preceding siblings ...)
  2019-07-06 10:54 ` [PATCH v5 03/12] S.A.R.A.: cred blob management Salvatore Mesoraca
@ 2019-07-06 10:54 ` Salvatore Mesoraca
  2019-07-06 18:32   ` Jann Horn
  2019-07-06 10:54 ` [PATCH v5 05/12] LSM: creation of "check_vmflags" LSM hook Salvatore Mesoraca
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 10:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Salvatore Mesoraca, Serge E. Hallyn, Thomas Gleixner

Creation of a generic Discrete Finite Automata implementation
for string matching. The transition tables have to be produced
in user-space.
This allows us to possibly support advanced string matching
patterns like regular expressions, but they need to be supported
by user-space tools.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 security/sara/Kconfig            |  22 +++
 security/sara/Makefile           |   3 +-
 security/sara/dfa.c              | 335 +++++++++++++++++++++++++++++++++++++++
 security/sara/dfa_test.c         | 135 ++++++++++++++++
 security/sara/include/dfa.h      |  52 ++++++
 security/sara/include/dfa_test.h |  29 ++++
 security/sara/main.c             |   6 +
 7 files changed, 581 insertions(+), 1 deletion(-)
 create mode 100644 security/sara/dfa.c
 create mode 100644 security/sara/dfa_test.c
 create mode 100644 security/sara/include/dfa.h
 create mode 100644 security/sara/include/dfa_test.h

diff --git a/security/sara/Kconfig b/security/sara/Kconfig
index 0456220..b98cf27 100644
--- a/security/sara/Kconfig
+++ b/security/sara/Kconfig
@@ -13,6 +13,28 @@ menuconfig SECURITY_SARA
 
 	  If unsure, answer N.
 
+config SECURITY_SARA_DFA_32BIT
+	bool "Use 32 bits instead of 16 bits for DFA states' id"
+	depends on SECURITY_SARA
+	default n
+	help
+	  If you say Y here S.A.R.A. will use more memory, but you will be
+	  able to configure more rules.
+	  See Documentation/admin-guide/LSM/SARA.rst. for further information.
+
+	  If unsure, answer N.
+
+config SECURITY_SARA_DFA_TEST
+	bool "Enable test interface for the internal DFA engine"
+	depends on SECURITY_SARA
+	default n
+	help
+	  If you say Y here S.A.R.A. will enable a user-space interface
+	  that can be used to test the DFA engine (e.g. via `saractl test`).
+	  See Documentation/admin-guide/LSM/SARA.rst. for further information.
+
+	  If unsure, answer N.
+
 config SECURITY_SARA_DEFAULT_DISABLED
 	bool "S.A.R.A. will be disabled at boot."
 	depends on SECURITY_SARA
diff --git a/security/sara/Makefile b/security/sara/Makefile
index 14bf7a8..ffa1be1 100644
--- a/security/sara/Makefile
+++ b/security/sara/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_SECURITY_SARA) := sara.o
 
-sara-y := main.o securityfs.o utils.o sara_data.o
+sara-y := main.o securityfs.o utils.o sara_data.o dfa.o
+sara-$(CONFIG_SECURITY_SARA_DFA_TEST) += dfa_test.o
diff --git a/security/sara/dfa.c b/security/sara/dfa.c
new file mode 100644
index 0000000..e39b27e
--- /dev/null
+++ b/security/sara/dfa.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/slab.h>
+
+#include "include/sara.h"
+#include "include/dfa.h"
+#include "include/securityfs.h"
+
+#define DFA_MAGIC_SIZE 8
+#define DFA_MAGIC "SARADFAT"
+
+#define DFA_INPUTS 255
+
+#ifndef CONFIG_SECURITY_SARA_DFA_32BIT
+#define pr_err_dfa_size() \
+	pr_err_ratelimited("DFA: too many states. Recompile kernel with CONFIG_SARA_DFA_32BIT.\n")
+#else
+#define pr_err_dfa_size() pr_err_ratelimited("DFA: too many states.\n")
+#endif
+
+void sara_dfa_free_tables(struct sara_dfa_tables *dfa)
+{
+	if (dfa) {
+		kvfree(dfa->output);
+		kvfree(dfa->def);
+		kvfree(dfa->base);
+		kvfree(dfa->next);
+		kvfree(dfa->check);
+		kvfree(dfa);
+	}
+}
+
+static struct sara_dfa_tables *sara_dfa_alloc_tables(sara_dfa_state states,
+						     sara_dfa_state cmp_states)
+{
+	struct sara_dfa_tables *tmp = NULL;
+
+	tmp = kvzalloc(sizeof(*tmp), GFP_KERNEL_ACCOUNT);
+	if (!tmp)
+		goto err;
+	tmp->output = kvcalloc(states,
+			       sizeof(*tmp->output),
+			       GFP_KERNEL_ACCOUNT);
+	if (!tmp->output)
+		goto err;
+	tmp->def = kvcalloc(states,
+			    sizeof(*tmp->def),
+			    GFP_KERNEL_ACCOUNT);
+	if (!tmp->def)
+		goto err;
+	tmp->base = kvcalloc(states,
+			     sizeof(*tmp->base),
+			     GFP_KERNEL_ACCOUNT);
+	if (!tmp->base)
+		goto err;
+	tmp->next = kvcalloc(cmp_states,
+			     sizeof(*tmp->next) * DFA_INPUTS,
+			     GFP_KERNEL_ACCOUNT);
+	if (!tmp->next)
+		goto err;
+	tmp->check = kvcalloc(cmp_states,
+			      sizeof(*tmp->check) * DFA_INPUTS,
+			      GFP_KERNEL_ACCOUNT);
+	if (!tmp->check)
+		goto err;
+	tmp->states = states;
+	tmp->cmp_states = cmp_states;
+	return tmp;
+
+err:
+	sara_dfa_free_tables(tmp);
+	return ERR_PTR(-ENOMEM);
+}
+
+int sara_dfa_match(struct sara_dfa_tables *dfa,
+		   const unsigned char *s,
+		   sara_dfa_output *output)
+{
+	sara_dfa_state i, j;
+	sara_dfa_state c_state = 0;
+
+	/* Max s[x] value must be == DFA_INPUTS */
+	BUILD_BUG_ON((((1ULL << (sizeof(*s) * 8)) - 1) != DFA_INPUTS));
+
+	/*
+	 * The DFA transition table is compressed using 5 linear arrays
+	 * as shown in the Dragon Book.
+	 * These arrays are: default, base, next, check and output.
+	 * default, base and output have the same size and are indexed by
+	 * state number.
+	 * next and check tables have the same size and are indexed by
+	 * the value from base for a given state and the input symbol.
+	 * To match a string against this set of arrays we need to:
+	 * - Use the base arrays to recover the index to use
+	 *   with check and next arrays for the current state and symbol.
+	 * - If the value in the check array matches the current state
+	 *   number the next state should be retrieved from the next array,
+	 *   otherwise we take it from the default array.
+	 * - If the next state is not valid we should return immediately
+	 * - If the input sequence is over and the value in the output array
+	 *   is valid, the string matches, and we should return the output
+	 *   value.
+	 */
+
+	for (i = 0; s[i]; i++) {
+		j = (dfa->base[c_state] * DFA_INPUTS) + s[i] - 1;
+		if (dfa->check[j] != c_state)
+			c_state = dfa->def[c_state];
+		else
+			c_state = dfa->next[j];
+		if (c_state == SARA_INVALID_DFA_VALUE)
+			return 0;
+	}
+
+	if (dfa->output[c_state] != SARA_INVALID_DFA_VALUE) {
+		*output = dfa->output[c_state];
+		return 1;
+	}
+	return 0;
+}
+
+struct sara_dfa_tables *sara_dfa_make_null(void)
+{
+	int i;
+	struct sara_dfa_tables *dfa = NULL;
+
+	dfa = sara_dfa_alloc_tables(1, 1);
+	if (unlikely(IS_ERR_OR_NULL(dfa)))
+		return NULL;
+	dfa->output[0] = SARA_INVALID_DFA_VALUE;
+	dfa->def[0] = SARA_INVALID_DFA_VALUE;
+	dfa->base[0] = 0;
+	for (i = 0; i < DFA_INPUTS; ++i)
+		dfa->next[i] = SARA_INVALID_DFA_VALUE;
+	for (i = 0; i < DFA_INPUTS; ++i)
+		dfa->check[i] = 0;
+	memset(dfa->hash, 0, SARA_CONFIG_HASH_LEN);
+	return dfa;
+}
+
+struct binary_dfa_header {
+	char magic[DFA_MAGIC_SIZE];
+	__le32 version;
+	__le32 states;
+	__le32 cmp_states;
+	char hash[SARA_CONFIG_HASH_LEN];
+} __packed;
+
+#define SARA_INVALID_DFA_VALUE_LOAD 0xffffffffu
+
+struct sara_dfa_tables *sara_dfa_load(const char *buf,
+				      size_t buf_len,
+				      bool (*is_valid)(sara_dfa_output))
+{
+	int ret;
+	struct sara_dfa_tables *dfa = NULL;
+	struct binary_dfa_header *h = (struct binary_dfa_header *) buf;
+	__le32 *p;
+	uint64_t i;
+	u32 version, states, cmp_states, tmp;
+
+	ret = -EINVAL;
+	if (unlikely(buf_len < sizeof(*h)))
+		goto out;
+
+	ret = -EINVAL;
+	if (unlikely(memcmp(h->magic, DFA_MAGIC, DFA_MAGIC_SIZE) != 0))
+		goto out;
+	version = le32_to_cpu(h->version);
+	states = le32_to_cpu(h->states);
+	cmp_states = le32_to_cpu(h->cmp_states);
+	if (unlikely(version != SARA_DFA_VERSION)) {
+		pr_err_ratelimited("DFA: unsupported version\n");
+		goto out;
+	}
+	if (unlikely(states >= SARA_INVALID_DFA_VALUE ||
+		     cmp_states >= SARA_INVALID_DFA_VALUE)) {
+		pr_err_dfa_size();
+		goto out;
+	}
+	if (unlikely(states == 0 ||
+		     cmp_states == 0))
+		goto out;
+	if (unlikely(((states * sizeof(u32) * 3) +
+		      (cmp_states * sizeof(u32) * 2 * DFA_INPUTS) +
+		      sizeof(*h)) != buf_len))
+		goto out;
+
+	ret = -ENOMEM;
+	dfa = sara_dfa_alloc_tables(h->states, h->cmp_states);
+	if (unlikely(IS_ERR_OR_NULL(dfa)))
+		goto out;
+
+	dfa->states = states;
+	dfa->cmp_states = cmp_states;
+
+	ret = -EINVAL;
+	p = (__le32 *) (buf + sizeof(*h));
+	for (i = 0; i < dfa->states; i++) {
+		tmp = le32_to_cpu(*p);
+		if (unlikely(tmp != SARA_INVALID_DFA_VALUE_LOAD &&
+			     tmp >= dfa->states))
+			goto out_alloc;
+		dfa->def[i] = (sara_dfa_state) tmp;
+		++p;
+	}
+	for (i = 0; i < dfa->states; i++) {
+		tmp = le32_to_cpu(*p);
+		if (unlikely(tmp >= dfa->cmp_states))
+			goto out_alloc;
+		dfa->base[i] = (sara_dfa_state) tmp;
+		++p;
+	}
+	for (i = 0; i < (dfa->cmp_states * DFA_INPUTS); i++) {
+		tmp = le32_to_cpu(*p);
+		if (unlikely(tmp != SARA_INVALID_DFA_VALUE_LOAD &&
+			     tmp >= dfa->states))
+			goto out_alloc;
+		dfa->next[i] = (sara_dfa_state) tmp;
+		++p;
+	}
+	for (i = 0; i < (dfa->cmp_states * DFA_INPUTS); i++) {
+		tmp = le32_to_cpu(*p);
+		if (unlikely(tmp != SARA_INVALID_DFA_VALUE_LOAD &&
+			     tmp >= dfa->states))
+			goto out_alloc;
+		dfa->check[i] = (sara_dfa_state) tmp;
+		++p;
+	}
+	for (i = 0; i < dfa->states; i++) {
+		tmp = le32_to_cpu(*p);
+		if (unlikely(tmp != SARA_INVALID_DFA_VALUE_LOAD &&
+			     !is_valid(tmp)))
+			goto out_alloc;
+		dfa->output[i] = (sara_dfa_state) tmp;
+		++p;
+	}
+	if (unlikely((void *) p != (void *) (buf + buf_len)))
+		goto out_alloc;
+
+	BUILD_BUG_ON(sizeof(dfa->hash) != sizeof(h->hash));
+	memcpy(dfa->hash, h->hash, sizeof(dfa->hash));
+
+	return dfa;
+out_alloc:
+	sara_dfa_free_tables(dfa);
+out:
+	pr_err_ratelimited("DFA: invalid load\n");
+	return ERR_PTR(ret);
+}
+
+ssize_t sara_dfa_dump(const struct sara_dfa_tables *dfa, char **buffer)
+{
+	char *buf;
+	size_t buf_len = 0;
+	struct binary_dfa_header *h;
+	__le32 *p;
+	int i;
+
+	buf_len = sizeof(*h) +
+		  dfa->states * sizeof(__le32) * 3 +
+		  dfa->cmp_states * sizeof(__le32) * DFA_INPUTS * 2;
+	buf = kvmalloc(buf_len, GFP_KERNEL_ACCOUNT);
+	if (unlikely(!buf))
+		return -ENOMEM;
+
+	h = (struct binary_dfa_header *) buf;
+	memcpy(h->magic, DFA_MAGIC, DFA_MAGIC_SIZE);
+	h->version = cpu_to_le32(SARA_DFA_VERSION);
+	h->states = cpu_to_le32(dfa->states);
+	h->cmp_states = cpu_to_le32(dfa->cmp_states);
+	BUILD_BUG_ON(sizeof(dfa->hash) != sizeof(h->hash));
+	memcpy(h->hash, dfa->hash, sizeof(dfa->hash));
+
+	p = (__le32 *) (buf + sizeof(*h));
+	for (i = 0; i < dfa->states; i++) {
+		if (dfa->def[i] == SARA_INVALID_DFA_VALUE)
+			*p++ = cpu_to_le32(SARA_INVALID_DFA_VALUE_LOAD);
+		else
+			*p++ = cpu_to_le32(dfa->def[i]);
+	}
+	for (i = 0; i < dfa->states; i++) {
+		if (dfa->base[i] == SARA_INVALID_DFA_VALUE)
+			*p++ = cpu_to_le32(SARA_INVALID_DFA_VALUE_LOAD);
+		else
+			*p++ = cpu_to_le32(dfa->base[i]);
+	}
+	for (i = 0; i < (dfa->cmp_states * DFA_INPUTS); i++) {
+		if (dfa->next[i] == SARA_INVALID_DFA_VALUE)
+			*p++ = cpu_to_le32(SARA_INVALID_DFA_VALUE_LOAD);
+		else
+			*p++ = cpu_to_le32(dfa->next[i]);
+	}
+	for (i = 0; i < (dfa->cmp_states * DFA_INPUTS); i++) {
+		if (dfa->check[i] == SARA_INVALID_DFA_VALUE)
+			*p++ = cpu_to_le32(SARA_INVALID_DFA_VALUE_LOAD);
+		else
+			*p++ = cpu_to_le32(dfa->check[i]);
+	}
+	for (i = 0; i < dfa->states; i++) {
+		if (dfa->output[i] == SARA_INVALID_DFA_VALUE)
+			*p++ = cpu_to_le32(SARA_INVALID_DFA_VALUE_LOAD);
+		else
+			*p++ = cpu_to_le32(dfa->output[i]);
+	}
+
+	if (unlikely((void *) p != (void *) (buf + buf_len))) {
+		/*
+		 * We can calculate the correct buffer size upfront.
+		 * This should never happen.
+		 */
+		kvfree(buf);
+		pr_crit("memory corruption in %s\n", __func__);
+		return 0;
+	}
+
+	*buffer = buf;
+	return buf_len;
+}
+
+#undef SARA_INVALID_DFA_VALUE_LOAD
diff --git a/security/sara/dfa_test.c b/security/sara/dfa_test.c
new file mode 100644
index 0000000..9c06414
--- /dev/null
+++ b/security/sara/dfa_test.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include "include/dfa.h"
+#include "include/securityfs.h"
+#include <linux/lsm_hooks.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#define SARA_DFA_MAX_RES_SIZE 20
+
+struct sara_dfa_tables *table;
+
+static DEFINE_MUTEX(test_lock);
+static sara_dfa_output result;
+
+static bool is_valid_output(sara_dfa_output output)
+{
+	return true;
+}
+
+static int config_load(const char *buf, size_t buf_len)
+{
+	struct sara_dfa_tables *dfa, *tmp;
+
+	dfa = sara_dfa_load(buf, buf_len, is_valid_output);
+	if (unlikely(IS_ERR_OR_NULL(dfa))) {
+		if (unlikely(dfa == NULL))
+			return -EINVAL;
+		else
+			return PTR_ERR(dfa);
+	}
+	mutex_lock(&test_lock);
+	tmp = table;
+	table = dfa;
+	mutex_unlock(&test_lock);
+	sara_dfa_free_tables(tmp);
+	return 0;
+}
+
+static int config_load_str(const char *buf, size_t buf_len)
+{
+	char *s;
+
+	s = kmalloc(buf_len+1, GFP_KERNEL_ACCOUNT);
+	if (unlikely(s == NULL))
+		return -ENOMEM;
+	s[buf_len] = '\0';
+	memcpy(s, buf, buf_len);
+
+	mutex_lock(&test_lock);
+	result = SARA_INVALID_DFA_VALUE;
+	sara_dfa_match(table, s, &result);
+	mutex_unlock(&test_lock);
+
+	kfree(s);
+
+	return 0;
+}
+
+static ssize_t config_dump_result(char **buf)
+{
+	char *s;
+
+	s = kzalloc(SARA_DFA_MAX_RES_SIZE, GFP_KERNEL_ACCOUNT);
+	if (unlikely(s == NULL))
+		return -ENOMEM;
+	mutex_lock(&test_lock);
+	if (result == SARA_INVALID_DFA_VALUE)
+		snprintf(s, SARA_DFA_MAX_RES_SIZE, "%u\n", 0xffffffff);
+	else
+		snprintf(s,
+			 SARA_DFA_MAX_RES_SIZE,
+			 "%u\n",
+			 (unsigned int) result);
+	mutex_unlock(&test_lock);
+	*buf = s;
+	return strlen(s);
+}
+
+static struct sara_secfs_fptrs fptrs __lsm_ro_after_init = {
+	.load = config_load,
+};
+
+static struct sara_secfs_fptrs teststr __lsm_ro_after_init = {
+	.load = config_load_str,
+	.dump = config_dump_result,
+};
+
+static const struct sara_secfs_node dfa_test_fs[] __initconst = {
+	{
+		.name = ".load",
+		.type = SARA_SECFS_CONFIG_LOAD,
+		.data = &fptrs,
+	},
+	{
+		.name = "test",
+		.type = SARA_SECFS_CONFIG_LOAD,
+		.data = &teststr,
+	},
+	{
+		.name = "result",
+		.type = SARA_SECFS_CONFIG_DUMP,
+		.data = &teststr,
+	},
+};
+
+int __init sara_dfa_test_init(void)
+{
+	int ret;
+
+	table = sara_dfa_make_null();
+	if (unlikely(!table))
+		return -ENOMEM;
+	ret = sara_secfs_subtree_register("dfa_test",
+					  dfa_test_fs,
+					  ARRAY_SIZE(dfa_test_fs));
+	if (unlikely(ret))
+		goto out_fail;
+	return 0;
+
+out_fail:
+	sara_dfa_free_tables(table);
+	return ret;
+}
diff --git a/security/sara/include/dfa.h b/security/sara/include/dfa.h
new file mode 100644
index 0000000..a536b60
--- /dev/null
+++ b/security/sara/include/dfa.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __SARA_DFA_H
+#define __SARA_DFA_H
+
+#include "securityfs.h"
+
+#ifdef CONFIG_SARA_DFA_32BIT
+typedef uint32_t sara_dfa_state;
+typedef uint32_t sara_dfa_output;
+#define SARA_INVALID_DFA_VALUE 0xffffffffu
+#else
+typedef uint16_t sara_dfa_state;
+typedef uint16_t sara_dfa_output;
+#define SARA_INVALID_DFA_VALUE 0xffffu
+#endif
+
+#define SARA_DFA_VERSION 2
+
+struct sara_dfa_tables {
+	sara_dfa_state states;
+	sara_dfa_state cmp_states;
+	sara_dfa_output *output;
+	sara_dfa_state *def;
+	sara_dfa_state *base;
+	sara_dfa_state *next;
+	sara_dfa_state *check;
+	char hash[SARA_CONFIG_HASH_LEN];
+};
+
+int sara_dfa_match(struct sara_dfa_tables *dfa,
+		   const unsigned char *s,
+		   sara_dfa_output *output);
+struct sara_dfa_tables *sara_dfa_make_null(void);
+struct sara_dfa_tables *sara_dfa_load(const char *buf,
+				      size_t buf_len,
+				      bool (*is_valid)(sara_dfa_output));
+ssize_t sara_dfa_dump(const struct sara_dfa_tables *dfa, char **buffer);
+void sara_dfa_free_tables(struct sara_dfa_tables *dfa);
+
+#endif /* __SARA_DFA_H */
diff --git a/security/sara/include/dfa_test.h b/security/sara/include/dfa_test.h
new file mode 100644
index 0000000..f10f78a
--- /dev/null
+++ b/security/sara/include/dfa_test.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __SARA_DFA_TEST_H
+#define __SARA_DFA_TEST_H
+
+#ifdef CONFIG_SECURITY_SARA_DFA_TEST
+
+#include <linux/init.h>
+int sara_dfa_test_init(void) __init;
+
+#else /* CONFIG_SECURITY_SARA_DFA_TEST */
+inline int sara_dfa_test_init(void)
+{
+	return 0;
+}
+#endif /* CONFIG_SECURITY_SARA_DFA_TEST */
+
+#endif /* __SARA_DFA_TEST_H */
diff --git a/security/sara/main.c b/security/sara/main.c
index dc5dda4..6b09500 100644
--- a/security/sara/main.c
+++ b/security/sara/main.c
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/printk.h>
 
+#include "include/dfa_test.h"
 #include "include/sara.h"
 #include "include/sara_data.h"
 #include "include/securityfs.h"
@@ -99,6 +100,11 @@ static int __init sara_init(void)
 		goto error;
 	}
 
+	if (sara_dfa_test_init()) {
+		pr_crit("impossible to initialize DFA test interface.\n");
+		goto error;
+	}
+
 	pr_debug("initialized.\n");
 
 	if (sara_enabled)
-- 
1.9.1


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

* [PATCH v5 05/12] LSM: creation of "check_vmflags" LSM hook
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
                   ` (3 preceding siblings ...)
  2019-07-06 10:54 ` [PATCH v5 04/12] S.A.R.A.: generic DFA for string matching Salvatore Mesoraca
@ 2019-07-06 10:54 ` Salvatore Mesoraca
  2019-07-06 10:54 ` [PATCH v5 06/12] S.A.R.A.: WX protection Salvatore Mesoraca
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 10:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Salvatore Mesoraca, Serge E. Hallyn, Thomas Gleixner

Creation of a new LSM hook to check if a given configuration of vmflags,
for a new memory allocation request, should be allowed or not.
It's placed in "do_mmap", "do_brk_flags", "__install_special_mapping"
and "setup_arg_pages".
When loading an ELF, this hook is also used to determine what to do
with an RWE PT_GNU_STACK header. This allows LSM to force the loader
to silently ignore executable stack markings, which is useful a thing to
do when trampoline emulation is available.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 fs/binfmt_elf.c           |  3 ++-
 fs/binfmt_elf_fdpic.c     |  3 ++-
 fs/exec.c                 |  4 ++++
 include/linux/lsm_hooks.h |  7 +++++++
 include/linux/security.h  |  6 ++++++
 mm/mmap.c                 | 13 +++++++++++++
 security/security.c       |  5 +++++
 7 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 8264b46..1d98737 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -806,7 +806,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
 	for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++)
 		switch (elf_ppnt->p_type) {
 		case PT_GNU_STACK:
-			if (elf_ppnt->p_flags & PF_X)
+			if (elf_ppnt->p_flags & PF_X &&
+			    !security_check_vmflags(VM_EXEC|VM_READ|VM_WRITE))
 				executable_stack = EXSTACK_ENABLE_X;
 			else
 				executable_stack = EXSTACK_DISABLE_X;
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index d86ebd0d..6e0dee1 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -163,7 +163,8 @@ static int elf_fdpic_fetch_phdrs(struct elf_fdpic_params *params,
 		if (phdr->p_type != PT_GNU_STACK)
 			continue;
 
-		if (phdr->p_flags & PF_X)
+		if (phdr->p_flags & PF_X &&
+		    !security_check_vmflags(VM_EXEC|VM_READ|VM_WRITE))
 			params->flags |= ELF_FDPIC_FLAG_EXEC_STACK;
 		else
 			params->flags |= ELF_FDPIC_FLAG_NOEXEC_STACK;
diff --git a/fs/exec.c b/fs/exec.c
index 89a500b..abf770a 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -756,6 +756,10 @@ int setup_arg_pages(struct linux_binprm *bprm,
 	vm_flags |= mm->def_flags;
 	vm_flags |= VM_STACK_INCOMPLETE_SETUP;
 
+	ret = security_check_vmflags(vm_flags);
+	if (ret)
+		goto out_unlock;
+
 	ret = mprotect_fixup(vma, &prev, vma->vm_start, vma->vm_end,
 			vm_flags);
 	if (ret)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 47f58cf..12ce609 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -513,6 +513,11 @@
  *	@reqprot contains the protection requested by the application.
  *	@prot contains the protection that will be applied by the kernel.
  *	Return 0 if permission is granted.
+ * @check_vmflags:
+ *	Check if the requested @vmflags are allowed.
+ *	@vmflags contains the requested vmflags.
+ *	Return 0 if the operation is allowed to continue otherwise return
+ *	the appropriate error code.
  * @file_lock:
  *	Check permission before performing file locking operations.
  *	Note the hook mediates both flock and fcntl style locks.
@@ -1597,6 +1602,7 @@
 				unsigned long prot, unsigned long flags);
 	int (*file_mprotect)(struct vm_area_struct *vma, unsigned long reqprot,
 				unsigned long prot);
+	int (*check_vmflags)(vm_flags_t vmflags);
 	int (*file_lock)(struct file *file, unsigned int cmd);
 	int (*file_fcntl)(struct file *file, unsigned int cmd,
 				unsigned long arg);
@@ -1897,6 +1903,7 @@ struct security_hook_heads {
 	struct hlist_head mmap_addr;
 	struct hlist_head mmap_file;
 	struct hlist_head file_mprotect;
+	struct hlist_head check_vmflags;
 	struct hlist_head file_lock;
 	struct hlist_head file_fcntl;
 	struct hlist_head file_set_fowner;
diff --git a/include/linux/security.h b/include/linux/security.h
index 659071c..aed78eb 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -312,6 +312,7 @@ int security_mmap_file(struct file *file, unsigned long prot,
 int security_mmap_addr(unsigned long addr);
 int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
 			   unsigned long prot);
+int security_check_vmflags(vm_flags_t vmflags);
 int security_file_lock(struct file *file, unsigned int cmd);
 int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg);
 void security_file_set_fowner(struct file *file);
@@ -859,6 +860,11 @@ static inline int security_file_mprotect(struct vm_area_struct *vma,
 	return 0;
 }
 
+static inline int security_check_vmflags(vm_flags_t vmflags)
+{
+	return 0;
+}
+
 static inline int security_file_lock(struct file *file, unsigned int cmd)
 {
 	return 0;
diff --git a/mm/mmap.c b/mm/mmap.c
index 7e8c3e8a..ec9c0e3d 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1390,6 +1390,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
 {
 	struct mm_struct *mm = current->mm;
 	int pkey = 0;
+	int error;
 
 	*populate = 0;
 
@@ -1453,6 +1454,10 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
 	vm_flags |= calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) |
 			mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
 
+	error = security_check_vmflags(vm_flags);
+	if (error)
+		return error;
+
 	if (flags & MAP_LOCKED)
 		if (!can_do_mlock())
 			return -EPERM;
@@ -2996,6 +3001,10 @@ static int do_brk_flags(unsigned long addr, unsigned long len, unsigned long fla
 		return -EINVAL;
 	flags |= VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
 
+	error = security_check_vmflags(flags);
+	if (error)
+		return error;
+
 	error = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED);
 	if (offset_in_page(error))
 		return error;
@@ -3393,6 +3402,10 @@ static struct vm_area_struct *__install_special_mapping(
 	int ret;
 	struct vm_area_struct *vma;
 
+	ret = security_check_vmflags(vm_flags);
+	if (ret)
+		return ERR_PTR(ret);
+
 	vma = vm_area_alloc(mm);
 	if (unlikely(vma == NULL))
 		return ERR_PTR(-ENOMEM);
diff --git a/security/security.c b/security/security.c
index f493db0..3308e89 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1421,6 +1421,11 @@ int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
 	return call_int_hook(file_mprotect, 0, vma, reqprot, prot);
 }
 
+int security_check_vmflags(vm_flags_t vmflags)
+{
+	return call_int_hook(check_vmflags, 0, vmflags);
+}
+
 int security_file_lock(struct file *file, unsigned int cmd)
 {
 	return call_int_hook(file_lock, 0, file, cmd);
-- 
1.9.1


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

* [PATCH v5 06/12] S.A.R.A.: WX protection
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
                   ` (4 preceding siblings ...)
  2019-07-06 10:54 ` [PATCH v5 05/12] LSM: creation of "check_vmflags" LSM hook Salvatore Mesoraca
@ 2019-07-06 10:54 ` Salvatore Mesoraca
  2019-07-06 15:38   ` Randy Dunlap
                     ` (2 more replies)
  2019-07-06 10:54 ` [PATCH v5 07/12] LSM: creation of "pagefault_handler" LSM hook Salvatore Mesoraca
                   ` (7 subsequent siblings)
  13 siblings, 3 replies; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 10:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Salvatore Mesoraca, Serge E. Hallyn, Thomas Gleixner

Introduction of S.A.R.A. WX Protection.
It aims to improve user-space programs security by applying:
- W^X enforcement
- W!->X (once writable never executable) mprotect restriction
- Executable MMAP prevention

All of the above features can be enabled or disabled both system wide
or on a per executable basis through the use of configuration.
W^X enforcement works by blocking any memory allocation or mprotect
invocation with both the WRITE and the EXEC flags enabled.
W!->X restriction works by preventing any mprotect invocation that makes
executable any page that is flagged VM_MAYWRITE.
Additional restrictions are in place for System V shared memory segments:
if a segment was attached as writable (executable) in the past it won't be
allowed to be attached as executable (writable) in the future.
This feature can be configured separately for stack, heap and other
allocations.
Executable MMAP prevention works by preventing any new executable
allocation after the dynamic libraries have been loaded. It works under the
assumption that, when the dynamic libraries have been finished loading, the
RELRO section will be marked read only.

Parts of WX Protection are inspired by some of the features available in
PaX according to my understanding of the code. Changes or omissions from
the original code are mine and don't reflect the original grsecurity/PaX
code.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 security/sara/Kconfig          |  74 +++++
 security/sara/Makefile         |   1 +
 security/sara/include/wxprot.h |  29 ++
 security/sara/main.c           |   6 +
 security/sara/wxprot.c         | 679 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 789 insertions(+)
 create mode 100644 security/sara/include/wxprot.h
 create mode 100644 security/sara/wxprot.c

diff --git a/security/sara/Kconfig b/security/sara/Kconfig
index b98cf27..54a96e0 100644
--- a/security/sara/Kconfig
+++ b/security/sara/Kconfig
@@ -60,3 +60,77 @@ config SECURITY_SARA_NO_RUNTIME_ENABLE
 
 	  If unsure, answer Y.
 
+config SECURITY_SARA_WXPROT
+	bool "WX Protection: W^X and W!->X protections"
+	depends on SECURITY_SARA
+	default y
+	help
+	  WX Protection aims to improve user-space programs security by applying:
+	    - W^X memory restriction
+	    - W!->X (once writable never executable) mprotect restriction
+	    - Executable MMAP prevention
+	  See Documentation/admin-guide/LSM/SARA.rst. for further information.
+
+	  If unsure, answer Y.
+
+choice
+	prompt "Default action for W^X and W!->X protections"
+	depends on SECURITY_SARA
+	depends on SECURITY_SARA_WXPROT
+	default SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_COMPLAIN_VERBOSE
+
+        help
+	  Choose the default behaviour of WX Protection when no config
+	  rule matches or no rule is loaded.
+	  For further information on available flags and their meaning
+	  see Documentation/admin-guide/LSM/SARA.rst.
+
+	config SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_COMPLAIN_VERBOSE
+		bool "Protections enabled but not enforced."
+		help
+		  All features enabled except "Executable MMAP prevention",
+		  verbose reporting, but no actual enforce: it just complains.
+		  Its numeric value is 0x3f, for more information see
+		  Documentation/admin-guide/LSM/SARA.rst.
+
+        config SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_ENFORCE_VERBOSE
+		bool "Full protection, verbose."
+		help
+		  All features enabled except "Executable MMAP prevention".
+		  The enabled features will be enforced with verbose reporting.
+		  Its numeric value is 0x2f, for more information see
+		  Documentation/admin-guide/LSM/SARA.rst.
+
+        config SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_ENFORCE
+		bool "Full protection, quiet."
+		help
+		  All features enabled except "Executable MMAP prevention".
+		  The enabled features will be enforced quietly.
+		  Its numeric value is 0xf, for more information see
+		  Documentation/admin-guide/LSM/SARA.rst.
+
+	config SECURITY_SARA_WXPROT_DEFAULT_FLAGS_NONE
+		bool "No protection at all."
+		help
+		  All features disabled.
+		  Its numeric value is 0, for more information see
+		  Documentation/admin-guide/LSM/SARA.rst.
+endchoice
+
+config SECURITY_SARA_WXPROT_DISABLED
+	bool "WX protection will be disabled at boot."
+	depends on SECURITY_SARA_WXPROT
+	default n
+	help
+	  If you say Y here WX protection won't be enabled at startup. You can
+	  override this option via user-space utilities or at boot time via
+	  "sara.wxprot_enabled=[0|1]" kernel parameter.
+
+	  If unsure, answer N.
+
+config SECURITY_SARA_WXPROT_DEFAULT_FLAGS
+	hex
+	default "0x3f" if SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_COMPLAIN_VERBOSE
+	default "0x2f" if SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_ENFORCE_VERBOSE
+	default "0xf" if SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_ENFORCE
+	default "0" if SECURITY_SARA_WXPROT_DEFAULT_FLAGS_NONE
diff --git a/security/sara/Makefile b/security/sara/Makefile
index ffa1be1..07751a5 100644
--- a/security/sara/Makefile
+++ b/security/sara/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_SECURITY_SARA) := sara.o
 
 sara-y := main.o securityfs.o utils.o sara_data.o dfa.o
 sara-$(CONFIG_SECURITY_SARA_DFA_TEST) += dfa_test.o
+sara-$(CONFIG_SECURITY_SARA_WXPROT) += wxprot.o
diff --git a/security/sara/include/wxprot.h b/security/sara/include/wxprot.h
new file mode 100644
index 0000000..df8705a
--- /dev/null
+++ b/security/sara/include/wxprot.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __SARA_WXPROT_H
+#define __SARA_WXPROT_H
+
+#ifdef CONFIG_SECURITY_SARA_WXPROT
+
+#include <linux/init.h>
+int sara_wxprot_init(void) __init;
+
+#else /* CONFIG_SECURITY_SARA_WXPROT */
+inline int sara_wxprot_init(void)
+{
+	return 0;
+}
+#endif /* CONFIG_SECURITY_SARA_WXPROT */
+
+#endif /* __SARA_WXPROT_H */
diff --git a/security/sara/main.c b/security/sara/main.c
index 6b09500..676e901 100644
--- a/security/sara/main.c
+++ b/security/sara/main.c
@@ -21,6 +21,7 @@
 #include "include/sara.h"
 #include "include/sara_data.h"
 #include "include/securityfs.h"
+#include "include/wxprot.h"
 
 static const int sara_version = SARA_VERSION;
 
@@ -105,6 +106,11 @@ static int __init sara_init(void)
 		goto error;
 	}
 
+	if (sara_wxprot_init()) {
+		pr_crit("impossible to initialize WX protections.\n");
+		goto error;
+	}
+
 	pr_debug("initialized.\n");
 
 	if (sara_enabled)
diff --git a/security/sara/wxprot.c b/security/sara/wxprot.c
new file mode 100644
index 0000000..8a3d002
--- /dev/null
+++ b/security/sara/wxprot.c
@@ -0,0 +1,679 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifdef CONFIG_SECURITY_SARA_WXPROT
+
+#include <linux/binfmts.h>
+#include <linux/cred.h>
+#include <linux/elf.h>
+#include <linux/kref.h>
+#include <linux/lsm_hooks.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/spinlock.h>
+
+#include "include/dfa.h"
+#include "include/sara.h"
+#include "include/sara_data.h"
+#include "include/utils.h"
+#include "include/securityfs.h"
+#include "include/wxprot.h"
+
+#define SARA_WXPROT_CONFIG_VERSION 0
+
+#define SARA_WXP_HEAP		0x0001
+#define SARA_WXP_STACK		0x0002
+#define SARA_WXP_OTHER		0x0004
+#define SARA_WXP_WXORX		0x0008
+#define SARA_WXP_COMPLAIN	0x0010
+#define SARA_WXP_VERBOSE	0x0020
+#define SARA_WXP_MMAP		0x0040
+#define SARA_WXP_TRANSFER	0x0200
+#define SARA_WXP_NONE		0x0000
+#define SARA_WXP_MPROTECT	(SARA_WXP_HEAP	| \
+				 SARA_WXP_STACK	| \
+				 SARA_WXP_OTHER)
+#define __SARA_WXP_ALL		(SARA_WXP_MPROTECT	| \
+				 SARA_WXP_MMAP		| \
+				 SARA_WXP_WXORX		| \
+				 SARA_WXP_COMPLAIN	| \
+				 SARA_WXP_VERBOSE)
+#define SARA_WXP_ALL		__SARA_WXP_ALL
+
+struct wxprot_config_container {
+	struct sara_dfa_tables *dfa;
+	struct kref refcount;
+};
+
+static struct wxprot_config_container __rcu *wxprot_config;
+
+static const int wxprot_config_version = SARA_WXPROT_CONFIG_VERSION;
+static int wxprot_enabled __read_mostly = true;
+static DEFINE_SPINLOCK(wxprot_config_lock);
+
+static u16 default_flags __lsm_ro_after_init =
+				CONFIG_SECURITY_SARA_WXPROT_DEFAULT_FLAGS;
+
+static const bool wxprot_emutramp;
+
+static void pr_wxp(char *msg)
+{
+	char *buf, *path;
+
+	path = get_current_path(&buf);
+	pr_notice_ratelimited("WXP: %s in '%s' (%d).\n",
+			      msg, path, current->pid);
+	kvfree(buf);
+}
+
+/**
+ * are_flags_valid - check whether the given combination of flags is valid
+ * @flags: the flags to be checked
+ *
+ * Returns true if flags are valid, false otherwise.
+ *
+ * Rules checked:
+ *   - Unused bits must be set to 0.
+ *   - Any feature in the "MPROTECT" group require "WXORX".
+ *   - "COMPLAIN" and "VERBOSE" can only be used if some other feature is
+ *     enabled.
+ *   - Trampoline emulation can only be used when all "MPROTECT"
+ *     features are active.
+ *   - "MMAP" protection requires SARA_WXP_OTHER
+ */
+static bool are_flags_valid(u16 flags)
+{
+	flags &= ~SARA_WXP_TRANSFER;
+	if (unlikely((flags & SARA_WXP_ALL) != flags))
+		return false;
+	if (unlikely(flags & SARA_WXP_MPROTECT &&
+		     !(flags & SARA_WXP_WXORX)))
+		return false;
+	if (unlikely(flags & (SARA_WXP_COMPLAIN | SARA_WXP_VERBOSE) &&
+		     !(flags & (SARA_WXP_MPROTECT |
+				SARA_WXP_WXORX |
+				SARA_WXP_MMAP))))
+		return false;
+	if (unlikely(flags & SARA_WXP_MMAP &&
+		     !(flags & SARA_WXP_OTHER)))
+		return false;
+	return true;
+}
+
+module_param(wxprot_enabled, int, 0);
+MODULE_PARM_DESC(wxprot_enabled,
+		 "Disable or enable S.A.R.A. WX Protection at boot time.");
+
+static int param_set_wxpflags(const char *val, const struct kernel_param *kp)
+{
+	u16 flags;
+
+	if (!val || kstrtou16(val, 0, &flags) != 0 || !are_flags_valid(flags))
+		return -EINVAL;
+	*(u16 *) kp->arg = flags;
+	return 0;
+}
+
+static struct kernel_param_ops param_ops_wxpflags = {
+	.set = param_set_wxpflags,
+};
+
+#define param_check_wxpflags(name, p) __param_check(name, p, u16)
+
+module_param_named(wxprot_default_flags, default_flags, wxpflags, 0);
+MODULE_PARM_DESC(wxprot_default_flags,
+		 "Disable or enable S.A.R.A. WX Protection at boot time.");
+
+/*
+ * MMAP exec restriction
+ */
+#define PT_GNU_RELRO (PT_LOOS + 0x474e552)
+
+union elfh {
+	struct elf32_hdr c32;
+	struct elf64_hdr c64;
+};
+
+union elfp {
+	struct elf32_phdr c32;
+	struct elf64_phdr c64;
+};
+
+#define find_relro_section(ELFH, ELFP, FILE, RELRO, FOUND) do {		\
+	unsigned long i;						\
+	int _tmp;							\
+	loff_t _pos = 0;						\
+	if (ELFH.e_type == ET_DYN || ELFH.e_type == ET_EXEC) {		\
+		for (i = 0; i < ELFH.e_phnum; ++i) {			\
+			_pos = ELFH.e_phoff + i*sizeof(ELFP);		\
+			_tmp = kernel_read(FILE, &ELFP, sizeof(ELFP),	\
+					   &_pos);			\
+			if (_tmp != sizeof(ELFP))			\
+				break;					\
+			if (ELFP.p_type == PT_GNU_RELRO) {		\
+				RELRO = ELFP.p_offset >> PAGE_SHIFT;	\
+				FOUND = true;				\
+				break;					\
+			}						\
+		}							\
+	}								\
+} while (0)
+
+static int set_relro_page(struct linux_binprm *bprm)
+{
+	union elfh elf_h;
+	union elfp elf_p;
+	unsigned long relro_page = 0;
+	bool relro_page_found = false;
+	int ret;
+	loff_t pos = 0;
+
+	ret = kernel_read(bprm->file, &elf_h, sizeof(elf_h), &pos);
+	if (ret == sizeof(elf_h) &&
+	    strncmp(elf_h.c32.e_ident, ELFMAG, SELFMAG) == 0) {
+		if (elf_h.c32.e_ident[EI_CLASS] == ELFCLASS32) {
+			find_relro_section(elf_h.c32,
+					   elf_p.c32,
+					   bprm->file,
+					   relro_page,
+					   relro_page_found);
+		} else if (IS_ENABLED(CONFIG_64BIT) &&
+			   elf_h.c64.e_ident[EI_CLASS] == ELFCLASS64) {
+			find_relro_section(elf_h.c64,
+					   elf_p.c64,
+					   bprm->file,
+					   relro_page,
+					   relro_page_found);
+		}
+	} else
+		return 2; /* It isn't an ELF */
+
+	if (relro_page_found) {
+		get_sara_relro_page(bprm->cred) = relro_page;
+		get_sara_relro_page_found(bprm->cred) = relro_page_found;
+		get_sara_relro_file(bprm->cred) = bprm->file;
+		return 0;
+	} else
+		return 1; /* It's an ELF without a RELRO section */
+}
+
+static inline int is_relro_page(const struct vm_area_struct *vma)
+{
+	if (get_current_sara_relro_page_found() &&
+	    get_current_sara_relro_page() == vma->vm_pgoff &&
+	    get_current_sara_relro_file() == vma->vm_file)
+		return 1;
+	return 0;
+}
+
+/*
+ * LSM hooks
+ */
+static int sara_bprm_set_creds(struct linux_binprm *bprm)
+{
+	int i;
+	struct wxprot_config_container *c;
+	u16 sara_wxp_flags = default_flags;
+	sara_dfa_output outfl;
+	char *buf = NULL;
+	char *path = NULL;
+	struct cred *current_new;
+
+	sara_wxp_flags = get_sara_wxp_flags(bprm->cred);
+	get_sara_mmap_blocked(bprm->cred) = false;
+	get_sara_relro_page_found(bprm->cred) = false;
+	get_sara_relro_page(bprm->cred) = 0;
+	get_sara_relro_file(bprm->cred) = NULL;
+	get_sara_wxp_flags(bprm->cred) = SARA_WXP_NONE;
+	get_sara_execve_flags(bprm->cred) = SARA_WXP_NONE;
+
+	if (!sara_enabled || !wxprot_enabled)
+		return 0;
+
+	/*
+	 * SARA_WXP_TRANSFER means that the parent
+	 * wants this child to inherit its flags.
+	 */
+	if (!(sara_wxp_flags & SARA_WXP_TRANSFER)) {
+		sara_wxp_flags = default_flags;
+		path = get_absolute_path(&bprm->file->f_path, &buf);
+		if (IS_ERR(path)) {
+			path = (char *) bprm->interp;
+			if (PTR_ERR(path) == -ENAMETOOLONG)
+				pr_warn_ratelimited("WXP: path too long for '%s'. Default flags will be used.\n",
+						path);
+			else
+				pr_warn_ratelimited("WXP: can't find path for '%s'. Default flags will be used.\n",
+						path);
+			goto skip_flags;
+		}
+		SARA_CONFIG_GET_RCU(c, wxprot_config);
+		if (sara_dfa_match(c->dfa, path, &outfl))
+			sara_wxp_flags = (u16) outfl;
+		SARA_CONFIG_PUT_RCU(c);
+	} else
+		path = (char *) bprm->interp;
+
+	if (sara_wxp_flags != default_flags &&
+	    sara_wxp_flags & SARA_WXP_VERBOSE)
+		pr_debug_ratelimited("WXP: '%s' run with flags '0x%x'.\n",
+				     path, sara_wxp_flags);
+
+skip_flags:
+	i = set_relro_page(bprm);
+	/*
+	 * i != 0 means no relro segment
+	 * i == 1 means the file wasn't an ELF
+	 *
+	 * We want to disable SARA_WXP_MMAP when the file is missing
+	 * the RELRO segment.
+	 * We want to verbosely report this case only if the file
+	 * was an ELF.
+	 *
+	 */
+	if (i != 0) {
+		if (sara_wxp_flags & SARA_WXP_VERBOSE &&
+		    sara_wxp_flags & SARA_WXP_MMAP &&
+		    i == 1)
+			pr_notice_ratelimited("WXP: failed to find RELRO section in '%s'.\n",
+					      path);
+		sara_wxp_flags &= ~SARA_WXP_MMAP;
+	}
+	kvfree(buf);
+	get_sara_wxp_flags(bprm->cred) = sara_wxp_flags;
+
+	/*
+	 * Set the flags to be used for validation
+	 * during the execve and discard SARA_WXP_MMAP:
+	 * it doesn't make sense to prevent executable
+	 * mmap during execve.
+	 */
+	current_new = prepare_creds();
+	if (unlikely(current_new == NULL))
+		return -ENOMEM;
+	get_sara_execve_flags(current_new) = sara_wxp_flags & ~SARA_WXP_MMAP;
+	commit_creds(current_new);
+
+	return 0;
+}
+
+#define sara_warn_or_return(err, msg) do {		\
+	if ((sara_wxp_flags & SARA_WXP_VERBOSE))	\
+		pr_wxp(msg);				\
+	if (!(sara_wxp_flags & SARA_WXP_COMPLAIN))	\
+		return -err;				\
+} while (0)
+
+#define sara_warn_or_goto(label, msg) do {		\
+	if ((sara_wxp_flags & SARA_WXP_VERBOSE))	\
+		pr_wxp(msg);				\
+	if (!(sara_wxp_flags & SARA_WXP_COMPLAIN))	\
+		goto label;				\
+} while (0)
+
+static int sara_check_vmflags(vm_flags_t vm_flags)
+{
+	u16 sara_wxp_flags;
+
+	if (!sara_enabled || !wxprot_enabled)
+		return 0;
+
+	/*
+	 * Memory allocations done during an execve should be
+	 * checked against the rules of the new executable,
+	 * instead of those of the current one.
+	 */
+	if (current->in_execve)
+		sara_wxp_flags = get_current_sara_execve_flags();
+	else
+		sara_wxp_flags = get_current_sara_wxp_flags();
+
+	/*
+	 * Be quiet when using security_check_vmflags to decide
+	 * what to do with a PT_GNU_STACK header
+	 */
+	if (current->in_execve && vm_flags == (VM_EXEC|VM_READ|VM_WRITE))
+		sara_wxp_flags &= ~SARA_WXP_VERBOSE;
+
+	/*
+	 * If "W xor X" is active for the current thread
+	 * this function must not allow new allocations that
+	 * have both the VM_WRITE and the VM_EXEC flags.
+	 */
+	if (unlikely(sara_wxp_flags & SARA_WXP_WXORX &&
+		     vm_flags & VM_WRITE &&
+		     vm_flags & VM_EXEC))
+		sara_warn_or_return(EPERM, "W^X");
+	/*
+	 * When the "MMAP" protection is on and shared libraries have
+	 * been already loaded (i.e. get_current_sara_mmap_blocked
+	 * returns true), this function must not allow:
+	 *    - new executable allocations
+	 *    - new non-executable allocations that may become
+	 *      executable bypassing the "MPROTECT" restriction;
+	 *      the "MPROTECT" protection will prevent a non-executable
+	 *      area to became executable only if it has the
+	 *      "VM_MAYWRITE" flag on.
+	 */
+	if (unlikely(sara_wxp_flags & SARA_WXP_MMAP &&
+		     (vm_flags & VM_EXEC ||
+		      (!(vm_flags & VM_MAYWRITE) && (vm_flags & VM_MAYEXEC))) &&
+		     get_current_sara_mmap_blocked()))
+		sara_warn_or_return(EPERM, "executable mmap");
+
+	return 0;
+}
+
+static int sara_shm_shmat(struct kern_ipc_perm *shp,
+			  char __user *shmaddr,
+			  int shmflg)
+{
+	int block = 0;
+	u16 sara_wxp_flags;
+	char buf[TASK_COMM_LEN];
+
+	if (!sara_enabled || !wxprot_enabled)
+		return 0;
+
+	sara_wxp_flags = get_current_sara_wxp_flags();
+
+	/*
+	 * Allow executable mappings if and only if this shm
+	 * was never attached as writable.
+	 *
+	 * Allow writable mappings if and only if this shm
+	 * was never attached as executable.
+	 *
+	 * We don't need to handle the case in which this
+	 * shm is attached as both writable and executable:
+	 * sara_check_vmflags takes care of that.
+	 */
+	if (sara_wxp_flags & SARA_WXP_OTHER) {
+		if (shmflg & SHM_EXEC && shmflg & SHM_RDONLY) {
+			lock_sara_shm(shp);
+			if (unlikely(get_sara_shm_no_exec(shp)))
+				block = 1;
+			else
+				get_sara_shm_no_write(shp) = true;
+			unlock_sara_shm(shp);
+		} else if (!(shmflg & (SHM_EXEC | SHM_RDONLY))) {
+			lock_sara_shm(shp);
+			if (unlikely(get_sara_shm_no_write(shp)))
+				block = 2;
+			else
+				get_sara_shm_no_exec(shp) = true;
+			unlock_sara_shm(shp);
+		}
+	}
+
+	if ((sara_wxp_flags & SARA_WXP_VERBOSE)) {
+		if (unlikely(block)) {
+			get_task_comm(buf, current);
+			if (block == 1)
+				pr_notice_ratelimited("WXP: executable SHM in '%s' (%d).\n",
+						      buf, current->pid);
+			else if (block == 2)
+				pr_notice_ratelimited("WXP: writable SHM in '%s' (%d).\n",
+						      buf, current->pid);
+		}
+	}
+	if (unlikely(block) && !(sara_wxp_flags & SARA_WXP_COMPLAIN))
+		return -EACCES;
+	return 0;
+}
+
+static int sara_file_mprotect(struct vm_area_struct *vma,
+				unsigned long reqprot,
+				unsigned long prot)
+{
+	u16 sara_wxp_flags;
+
+	if (!sara_enabled || !wxprot_enabled)
+		return 0;
+
+	if (current->in_execve)
+		sara_wxp_flags = get_current_sara_execve_flags();
+	else
+		sara_wxp_flags = get_current_sara_wxp_flags();
+
+	/*
+	 * vmas that may have been writable at some time in the past
+	 * (i.e. have the VM_MAYWRITE flag on) shouldn't be allowed
+	 * to be marked executable, unless they already are.
+	 */
+	if (unlikely(sara_wxp_flags & SARA_WXP_MPROTECT &&
+		     prot & PROT_EXEC &&
+		     !(vma->vm_flags & VM_EXEC) &&
+		     vma->vm_flags & VM_MAYWRITE)) {
+		/*
+		 * If every MPROTECT flag is on and verbose reporting
+		 * isn't needed, skip checking where the vma points to.
+		 * Otherwise check if it points to a file mapping,
+		 * to heap, to stack or to anywhere else.
+		 */
+		if ((sara_wxp_flags & SARA_WXP_MPROTECT) == SARA_WXP_MPROTECT &&
+		    !(sara_wxp_flags & SARA_WXP_COMPLAIN) &&
+		    !(sara_wxp_flags & SARA_WXP_VERBOSE))
+			return -EACCES;
+		else if (vma->vm_file) {
+			if (sara_wxp_flags & SARA_WXP_OTHER)
+				sara_warn_or_return(EACCES,
+						    "mprotect on file mmap");
+		} else if (vma->vm_start >= vma->vm_mm->start_brk &&
+			vma->vm_end <= vma->vm_mm->brk) {
+			if (sara_wxp_flags & SARA_WXP_HEAP)
+				sara_warn_or_return(EACCES,
+						    "mprotect on heap");
+		} else if ((vma->vm_start <= vma->vm_mm->start_stack &&
+			    vma->vm_end >= vma->vm_mm->start_stack) ||
+			   vma_is_stack_for_current(vma)) {
+			if (sara_wxp_flags & SARA_WXP_STACK)
+				sara_warn_or_return(EACCES,
+						    "mprotect on stack");
+		} else if (sara_wxp_flags & SARA_WXP_OTHER)
+			sara_warn_or_return(EACCES,
+					    "mprotect on anon mmap");
+	}
+
+	/*
+	 * If "W xor X" is active for the current thread
+	 * VM_EXEC and VM_WRITE can't be turned on at
+	 * the same time, unless they already are.
+	 */
+	if (unlikely(sara_wxp_flags & SARA_WXP_WXORX &&
+		     prot & PROT_EXEC &&
+		     prot & PROT_WRITE &&
+		     (!(vma->vm_flags & VM_EXEC) ||
+		      !(vma->vm_flags & VM_WRITE))))
+		sara_warn_or_return(EACCES, "W^X");
+
+	/*
+	 * If the dynamic loader marks the "relro section" as
+	 * read-only then it has finished loading shared libraries
+	 * and, if the SARA_WXP_MMAP flag is on, new executable
+	 * mmaps will be blocked from now on.
+	 */
+	if (unlikely(vma->vm_flags & VM_WRITE &&
+		     !(prot & PROT_WRITE) &&
+		     is_relro_page(vma)))
+		get_current_sara_mmap_blocked() = true;
+
+	return 0;
+}
+
+static struct security_hook_list wxprot_hooks[] __lsm_ro_after_init = {
+	LSM_HOOK_INIT(bprm_set_creds, sara_bprm_set_creds),
+	LSM_HOOK_INIT(check_vmflags, sara_check_vmflags),
+	LSM_HOOK_INIT(shm_shmat, sara_shm_shmat),
+	LSM_HOOK_INIT(file_mprotect, sara_file_mprotect),
+};
+
+static void config_free(struct wxprot_config_container *data)
+{
+	sara_dfa_free_tables(data->dfa);
+	kfree(data);
+}
+
+static bool are_flags_valid_dfa(sara_dfa_output flags)
+{
+	return are_flags_valid((u16) flags);
+}
+
+static int config_load(const char *buf, size_t buf_len)
+{
+	struct sara_dfa_tables *dfa = NULL;
+	struct wxprot_config_container *new;
+	int ret;
+
+	dfa = sara_dfa_load(buf, buf_len, are_flags_valid_dfa);
+	if (unlikely(IS_ERR_OR_NULL(dfa))) {
+		if (IS_ERR(dfa))
+			ret = PTR_ERR(dfa);
+		else
+			ret = -EINVAL;
+		goto error;
+	}
+	new = kmalloc(sizeof(*new), GFP_KERNEL);
+	if (unlikely(!new)) {
+		ret = -ENOMEM;
+		goto error_dfa;
+	}
+	kref_init(&new->refcount);
+	new->dfa = dfa;
+	SARA_CONFIG_REPLACE(wxprot_config,
+			    new,
+			    config_free,
+			    &wxprot_config_lock);
+	pr_notice("WXP: new rules loaded.\n");
+	return 0;
+error_dfa:
+	sara_dfa_free_tables(dfa);
+error:
+	pr_notice("WXP: failed to load rules.\n");
+	return ret;
+}
+
+static ssize_t config_dump(char **buf)
+{
+	ssize_t ret;
+	struct wxprot_config_container *c;
+
+	SARA_CONFIG_GET(c, wxprot_config);
+	ret = sara_dfa_dump(c->dfa, buf);
+	SARA_CONFIG_PUT(c, config_free);
+	return ret;
+}
+
+static int config_hash(char **buf)
+{
+	int ret;
+	struct wxprot_config_container *config;
+
+	ret = -ENOMEM;
+	*buf = kzalloc(sizeof(config->dfa->hash), GFP_KERNEL);
+	if (unlikely(*buf == NULL))
+		goto out;
+
+	SARA_CONFIG_GET_RCU(config, wxprot_config);
+	memcpy(*buf, config->dfa->hash, sizeof(config->dfa->hash));
+	SARA_CONFIG_PUT_RCU(config);
+
+	ret = 0;
+out:
+	return ret;
+}
+
+static DEFINE_SARA_SECFS_BOOL_FLAG(wxprot_enabled_data,
+				   wxprot_enabled);
+
+static struct sara_secfs_fptrs fptrs __lsm_ro_after_init = {
+	.load = config_load,
+	.dump = config_dump,
+	.hash = config_hash,
+};
+
+static const struct sara_secfs_node wxprot_fs[] __initconst = {
+	{
+		.name = "enabled",
+		.type = SARA_SECFS_BOOL,
+		.data = (void *) &wxprot_enabled_data,
+	},
+	{
+		.name = "version",
+		.type = SARA_SECFS_READONLY_INT,
+		.data = (int *) &wxprot_config_version,
+	},
+	{
+		.name = "default_flags",
+		.type = SARA_SECFS_READONLY_INT,
+		.data = &default_flags,
+	},
+	{
+		.name = "emutramp_available",
+		.type = SARA_SECFS_READONLY_INT,
+		.data = (int *) &wxprot_emutramp,
+	},
+	{
+		.name = ".load",
+		.type = SARA_SECFS_CONFIG_LOAD,
+		.data = &fptrs,
+	},
+	{
+		.name = ".dump",
+		.type = SARA_SECFS_CONFIG_DUMP,
+		.data = &fptrs,
+	},
+	{
+		.name = "hash",
+		.type = SARA_SECFS_CONFIG_HASH,
+		.data = &fptrs,
+	},
+};
+
+
+int __init sara_wxprot_init(void)
+{
+	int ret;
+	struct wxprot_config_container *tmpc = NULL;
+
+	ret = -EINVAL;
+	if (!are_flags_valid(default_flags))
+		goto out_fail;
+	ret = -ENOMEM;
+	tmpc = kzalloc(sizeof(*tmpc), GFP_KERNEL);
+	if (unlikely(tmpc == NULL))
+		goto out_fail;
+	kref_init(&tmpc->refcount);
+	tmpc->dfa = sara_dfa_make_null();
+	if (unlikely(!tmpc->dfa))
+		goto out_fail;
+	wxprot_config = (struct wxprot_config_container __rcu *) tmpc;
+	ret = sara_secfs_subtree_register("wxprot",
+					  wxprot_fs,
+					  ARRAY_SIZE(wxprot_fs));
+	if (unlikely(ret))
+		goto out_fail_dfa;
+	security_add_hooks(wxprot_hooks, ARRAY_SIZE(wxprot_hooks), "sara");
+	return 0;
+
+out_fail_dfa:
+	sara_dfa_free_tables(tmpc->dfa);
+out_fail:
+	kfree(tmpc);
+	return ret;
+}
+
+#endif /* CONFIG_SECURITY_SARA_WXPROT */
-- 
1.9.1


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

* [PATCH v5 07/12] LSM: creation of "pagefault_handler" LSM hook
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
                   ` (5 preceding siblings ...)
  2019-07-06 10:54 ` [PATCH v5 06/12] S.A.R.A.: WX protection Salvatore Mesoraca
@ 2019-07-06 10:54 ` Salvatore Mesoraca
  2019-07-06 10:54 ` [PATCH v5 08/12] S.A.R.A.: trampoline emulation Salvatore Mesoraca
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 10:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Salvatore Mesoraca, Serge E. Hallyn, Thomas Gleixner

Creation of a new hook to let LSM modules handle user-space pagefaults on
x86.
It can be used to avoid segfaulting the originating process.
If it's the case it can modify process registers before returning.
This is not a security feature by itself, it's a way to soften some
unwanted side-effects of restrictive security features.
In particular this is used by S.A.R.A. to implement what PaX call
"trampoline emulation" that, in practice, allows for some specific
code sequences to be executed even if they are in non executable memory.
This may look like a bad thing at first, but you have to consider
that:
- This allows for strict memory restrictions (e.g. W^X) to stay on even
  when they should be turned off. And, even if this emulation
  makes those features less effective, it's still better than having
  them turned off completely.
- The only code sequences emulated are trampolines used to make
  function calls. In many cases, when you have the chance to
  make arbitrary memory writes, you can already manipulate the
  control flow of the program by overwriting function pointers or
  return values. So, in many cases, "trampoline emulation"
  doesn't introduce new exploit vectors.
- It's a feature that can be turned on only if needed, on a per
  executable file basis.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 arch/Kconfig              |  6 ++++++
 arch/x86/Kconfig          |  1 +
 arch/x86/mm/fault.c       |  6 ++++++
 include/linux/lsm_hooks.h | 12 ++++++++++++
 include/linux/security.h  | 11 +++++++++++
 security/security.c       | 11 +++++++++++
 6 files changed, 47 insertions(+)

diff --git a/arch/Kconfig b/arch/Kconfig
index c47b328..16997c3 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -252,6 +252,12 @@ config ARCH_HAS_FORTIFY_SOURCE
 config ARCH_HAS_KEEPINITRD
 	bool
 
+config ARCH_HAS_LSM_PAGEFAULT
+	bool
+	help
+	  An architecture should select this if it supports
+	  "pagefault_handler" LSM hook.
+
 # Select if arch has all set_memory_ro/rw/x/nx() functions in asm/cacheflush.h
 config ARCH_HAS_SET_MEMORY
 	bool
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 2bbbd4d..a3c7660 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -67,6 +67,7 @@ config X86
 	select ARCH_HAS_FORTIFY_SOURCE
 	select ARCH_HAS_GCOV_PROFILE_ALL
 	select ARCH_HAS_KCOV			if X86_64
+	select ARCH_HAS_LSM_PAGEFAULT
 	select ARCH_HAS_MEMBARRIER_SYNC_CORE
 	select ARCH_HAS_PMEM_API		if X86_64
 	select ARCH_HAS_PTE_SPECIAL
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 46df4c6..7fe36f1 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -18,6 +18,7 @@
 #include <linux/uaccess.h>		/* faulthandler_disabled()	*/
 #include <linux/efi.h>			/* efi_recover_from_page_fault()*/
 #include <linux/mm_types.h>
+#include <linux/security.h>		/* security_pagefault_handler	*/
 
 #include <asm/cpufeature.h>		/* boot_cpu_has, ...		*/
 #include <asm/traps.h>			/* dotraplinkage, ...		*/
@@ -1360,6 +1361,11 @@ void do_user_addr_fault(struct pt_regs *regs,
 			local_irq_enable();
 	}
 
+	if (unlikely(security_pagefault_handler(regs,
+						hw_error_code,
+						address)))
+		return;
+
 	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
 
 	if (hw_error_code & X86_PF_WRITE)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 12ce609..478a187 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -518,6 +518,14 @@
  *	@vmflags contains the requested vmflags.
  *	Return 0 if the operation is allowed to continue otherwise return
  *	the appropriate error code.
+ * @pagefault_handler:
+ *	Handle pagefaults on supported architectures, that is any architecture
+ *	which defines CONFIG_ARCH_HAS_LSM_PAGEFAULT.
+ *	@regs contains process' registers.
+ *	@error_code contains error code for the pagefault.
+ *	@address contains the address that caused the pagefault.
+ *	Return 0 to let the kernel handle the pagefault as usually, any other
+ *	value to let the process continue its execution.
  * @file_lock:
  *	Check permission before performing file locking operations.
  *	Note the hook mediates both flock and fcntl style locks.
@@ -1603,6 +1611,9 @@
 	int (*file_mprotect)(struct vm_area_struct *vma, unsigned long reqprot,
 				unsigned long prot);
 	int (*check_vmflags)(vm_flags_t vmflags);
+	int (*pagefault_handler)(struct pt_regs *regs,
+				 unsigned long error_code,
+				 unsigned long address);
 	int (*file_lock)(struct file *file, unsigned int cmd);
 	int (*file_fcntl)(struct file *file, unsigned int cmd,
 				unsigned long arg);
@@ -1904,6 +1915,7 @@ struct security_hook_heads {
 	struct hlist_head mmap_file;
 	struct hlist_head file_mprotect;
 	struct hlist_head check_vmflags;
+	struct hlist_head pagefault_handler;
 	struct hlist_head file_lock;
 	struct hlist_head file_fcntl;
 	struct hlist_head file_set_fowner;
diff --git a/include/linux/security.h b/include/linux/security.h
index aed78eb..c287eb2 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -313,6 +313,9 @@ int security_mmap_file(struct file *file, unsigned long prot,
 int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
 			   unsigned long prot);
 int security_check_vmflags(vm_flags_t vmflags);
+int __maybe_unused security_pagefault_handler(struct pt_regs *regs,
+					      unsigned long error_code,
+					      unsigned long address);
 int security_file_lock(struct file *file, unsigned int cmd);
 int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg);
 void security_file_set_fowner(struct file *file);
@@ -865,6 +868,14 @@ static inline int security_check_vmflags(vm_flags_t vmflags)
 	return 0;
 }
 
+static inline int __maybe_unused security_pagefault_handler(
+						struct pt_regs *regs,
+						unsigned long error_code,
+						unsigned long address)
+{
+	return 0;
+}
+
 static inline int security_file_lock(struct file *file, unsigned int cmd)
 {
 	return 0;
diff --git a/security/security.c b/security/security.c
index 3308e89..a8bdcf3 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1426,6 +1426,17 @@ int security_check_vmflags(vm_flags_t vmflags)
 	return call_int_hook(check_vmflags, 0, vmflags);
 }
 
+int __maybe_unused security_pagefault_handler(struct pt_regs *regs,
+					      unsigned long error_code,
+					      unsigned long address)
+{
+	return call_int_hook(pagefault_handler,
+			     0,
+			     regs,
+			     error_code,
+			     address);
+}
+
 int security_file_lock(struct file *file, unsigned int cmd)
 {
 	return call_int_hook(file_lock, 0, file, cmd);
-- 
1.9.1


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

* [PATCH v5 08/12] S.A.R.A.: trampoline emulation
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
                   ` (6 preceding siblings ...)
  2019-07-06 10:54 ` [PATCH v5 07/12] LSM: creation of "pagefault_handler" LSM hook Salvatore Mesoraca
@ 2019-07-06 10:54 ` Salvatore Mesoraca
  2019-07-06 15:31   ` Randy Dunlap
  2019-07-06 10:54 ` [PATCH v5 09/12] S.A.R.A.: WX protection procattr interface Salvatore Mesoraca
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 10:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Salvatore Mesoraca, Serge E. Hallyn, Thomas Gleixner

Some programs need to generate part of their code at runtime. Luckily
enough, in some cases they only generate well-known code sequences (the
"trampolines") that can be easily recognized and emulated by the kernel.
This way WX Protection can still be active, so a potential attacker won't
be able to generate arbitrary sequences of code, but just those that are
explicitly allowed. This is not ideal, but it's still better than having WX
Protection completely disabled.
In particular S.A.R.A. is able to recognize trampolines used by GCC for
nested C functions and libffi's trampolines.
This feature is implemented only on x86_32 and x86_64.
Trampoline emulation is modified from Brad Spengler/PaX Team's code in the
last public patch of grsecurity/PaX based on my understanding of the code.
Changes or omissions from the original code are mine and don't reflect the
original grsecurity/PaX code.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 arch/x86/Kbuild                        |   2 +
 arch/x86/security/Makefile             |   2 +
 arch/x86/security/sara/Makefile        |   1 +
 arch/x86/security/sara/emutramp.c      |  57 ++++++++++++
 arch/x86/security/sara/trampolines32.h | 137 +++++++++++++++++++++++++++
 arch/x86/security/sara/trampolines64.h | 164 +++++++++++++++++++++++++++++++++
 security/sara/Kconfig                  |  18 ++++
 security/sara/include/emutramp.h       |  35 +++++++
 security/sara/wxprot.c                 |  29 ++++++
 9 files changed, 445 insertions(+)
 create mode 100644 arch/x86/security/Makefile
 create mode 100644 arch/x86/security/sara/Makefile
 create mode 100644 arch/x86/security/sara/emutramp.c
 create mode 100644 arch/x86/security/sara/trampolines32.h
 create mode 100644 arch/x86/security/sara/trampolines64.h
 create mode 100644 security/sara/include/emutramp.h

diff --git a/arch/x86/Kbuild b/arch/x86/Kbuild
index 30dec01..4fea778 100644
--- a/arch/x86/Kbuild
+++ b/arch/x86/Kbuild
@@ -25,3 +25,5 @@ obj-y += platform/
 obj-y += net/
 
 obj-$(CONFIG_KEXEC_FILE) += purgatory/
+
+obj-y += security/
diff --git a/arch/x86/security/Makefile b/arch/x86/security/Makefile
new file mode 100644
index 0000000..ba4be4c
--- /dev/null
+++ b/arch/x86/security/Makefile
@@ -0,0 +1,2 @@
+subdir-$(CONFIG_SECURITY_SARA)		+= sara
+obj-$(CONFIG_SECURITY_SARA)		+= sara/
diff --git a/arch/x86/security/sara/Makefile b/arch/x86/security/sara/Makefile
new file mode 100644
index 0000000..a4a76217
--- /dev/null
+++ b/arch/x86/security/sara/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP) := emutramp.o
diff --git a/arch/x86/security/sara/emutramp.c b/arch/x86/security/sara/emutramp.c
new file mode 100644
index 0000000..45122e5
--- /dev/null
+++ b/arch/x86/security/sara/emutramp.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * Assembly sequences used here were copied from
+ * PaX patch by PaX Team <pageexec@freemail.hu>
+ * Being just hexadecimal constants, they are not subject to
+ * any copyright.
+ *
+ */
+
+#define PF_PROT		(1 << 0)
+#define PF_USER		(1 << 2)
+#define PF_INSTR	(1 << 4)
+
+#ifdef CONFIG_X86_32
+
+#include "trampolines32.h"
+static inline int trampoline_emulator(struct pt_regs *regs,
+				      unsigned long address)
+{
+	return sara_trampoline_emulator_x86_32(regs);
+}
+
+#else /* CONFIG_X86_32 */
+
+#include "trampolines64.h"
+static inline int trampoline_emulator(struct pt_regs *regs,
+				      unsigned long address)
+{
+	return sara_trampoline_emulator_x86_64(regs, address);
+}
+
+#endif /* CONFIG_X86_32 */
+
+
+int sara_trampoline_emulator(struct pt_regs *regs,
+			     unsigned long error_code,
+			     unsigned long address)
+{
+	if (!(error_code & PF_USER) ||
+	    !(error_code & PF_INSTR) ||
+	    !(error_code & PF_PROT))
+		return 0;
+
+	local_irq_enable();
+	might_sleep();
+	might_fault();
+	return trampoline_emulator(regs, address);
+}
diff --git a/arch/x86/security/sara/trampolines32.h b/arch/x86/security/sara/trampolines32.h
new file mode 100644
index 0000000..b3622d0
--- /dev/null
+++ b/arch/x86/security/sara/trampolines32.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * Assembly sequences used here were copied from
+ * PaX patch by PaX Team <pageexec@freemail.hu>
+ * Being just hexadecimal constants, they are not subject to
+ * any copyright.
+ *
+ */
+
+#ifndef __SARA_TRAMPOLINES32_H
+#define __SARA_TRAMPOLINES32_H
+
+#include <linux/printk.h>
+#include <linux/uaccess.h>
+
+struct libffi_trampoline_x86_32 {
+	unsigned char mov;
+	unsigned int addr1;
+	unsigned char jmp;
+	unsigned int addr2;
+} __packed;
+
+struct gcc_trampoline_x86_32_t1 {
+	unsigned char mov1;
+	unsigned int addr1;
+	unsigned char mov2;
+	unsigned int addr2;
+	unsigned short jmp;
+} __packed;
+
+struct gcc_trampoline_x86_32_t2 {
+	unsigned char mov;
+	unsigned int addr1;
+	unsigned char jmp;
+	unsigned int addr2;
+} __packed;
+
+union trampolines_x86_32 {
+	struct libffi_trampoline_x86_32 lf;
+	struct gcc_trampoline_x86_32_t1 g1;
+	struct gcc_trampoline_x86_32_t2 g2;
+};
+
+static inline int is_libffi_tramp_x86_32(const union trampolines_x86_32 *u)
+{
+	return (u->lf.mov == 0xB8 && u->lf.jmp == 0xE9);
+}
+
+static inline void emu_libffi_tramp_x86_32(const union trampolines_x86_32 *u,
+					   struct pt_regs *regs)
+{
+	regs->ax = u->lf.addr1;
+	regs->ip = (unsigned int) (regs->ip +
+				   u->lf.addr2 +
+				   sizeof(u->lf));
+}
+
+static inline int is_gcc_tramp_x86_32_t1(const union trampolines_x86_32 *u,
+					 const struct pt_regs *regs)
+{
+	return (u->g1.mov1 == 0xB9 &&
+		u->g1.mov2 == 0xB8 &&
+		u->g1.jmp == 0xE0FF &&
+		regs->ip > regs->sp);
+}
+
+static inline void emu_gcc_tramp_x86_32_t1(const union trampolines_x86_32 *u,
+					   struct pt_regs *regs)
+{
+	regs->cx = u->g1.addr1;
+	regs->ax = u->g1.addr2;
+	regs->ip = u->g1.addr2;
+}
+
+static inline int is_gcc_tramp_x86_32_t2(const union trampolines_x86_32 *u,
+					 const struct pt_regs *regs)
+{
+	return (u->g2.mov == 0xB9 &&
+		u->g2.jmp == 0xE9 &&
+		regs->ip > regs->sp);
+}
+
+static inline void emu_gcc_tramp_x86_32_t2(const union trampolines_x86_32 *u,
+					   struct pt_regs *regs)
+{
+	regs->cx = u->g2.addr1;
+	regs->ip = (unsigned int) (regs->ip +
+				   u->g2.addr2 +
+				   sizeof(u->g2));
+}
+
+static inline int sara_trampoline_emulator_x86_32(struct pt_regs *regs)
+{
+	int ret;
+	void __user *ip = (void __user *) regs->ip;
+	union trampolines_x86_32 t; //zero init
+
+	BUILD_BUG_ON(sizeof(t.lf) > sizeof(t.g1));
+	BUILD_BUG_ON(sizeof(t.g2) > sizeof(t.lf));
+
+	ret = copy_from_user(&t, ip, sizeof(t.g1));
+	if (ret)
+		ret = copy_from_user(&t, ip, sizeof(t.lf));
+	if (ret)
+		ret = copy_from_user(&t, ip, sizeof(t.g2));
+	if (ret)
+		return 0;
+
+	if (is_gcc_tramp_x86_32_t1(&t, regs)) {
+		pr_debug("Trampoline: gcc1 x86_32.\n");
+		emu_gcc_tramp_x86_32_t1(&t, regs);
+		return 1;
+	} else if (is_libffi_tramp_x86_32(&t)) {
+		pr_debug("Trampoline: libffi x86_32.\n");
+		emu_libffi_tramp_x86_32(&t, regs);
+		return 1;
+	} else if (is_gcc_tramp_x86_32_t2(&t, regs)) {
+		pr_debug("Trampoline: gcc2 x86_32.\n");
+		emu_gcc_tramp_x86_32_t2(&t, regs);
+		return 1;
+	}
+
+	pr_debug("Not a trampoline (x86_32).\n");
+
+	return 0;
+}
+
+#endif /* __SARA_TRAMPOLINES32_H */
diff --git a/arch/x86/security/sara/trampolines64.h b/arch/x86/security/sara/trampolines64.h
new file mode 100644
index 0000000..c9aaa03
--- /dev/null
+++ b/arch/x86/security/sara/trampolines64.h
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * Assembly sequences used here were copied from
+ * PaX patch by PaX Team <pageexec@freemail.hu>
+ * Being just hexadecimal constants, they are not subject to
+ * any copyright.
+ *
+ */
+
+#ifndef __SARA_TRAMPOLINES64_H
+#define __SARA_TRAMPOLINES64_H
+
+#include <linux/printk.h>
+#include <linux/uaccess.h>
+
+#include "trampolines32.h"
+
+struct libffi_trampoline_x86_64 {
+	unsigned short mov1;
+	unsigned long addr1;
+	unsigned short mov2;
+	unsigned long addr2;
+	unsigned char stcclc;
+	unsigned short jmp1;
+	unsigned char jmp2;
+} __packed;
+
+struct gcc_trampoline_x86_64_type1 {
+	unsigned short mov1;
+	unsigned long addr1;
+	unsigned short mov2;
+	unsigned long addr2;
+	unsigned short jmp1;
+	unsigned char jmp2;
+} __packed;
+
+struct gcc_trampoline_x86_64_type2 {
+	unsigned short mov1;
+	unsigned int addr1;
+	unsigned short mov2;
+	unsigned long addr2;
+	unsigned short jmp1;
+	unsigned char jmp2;
+} __packed;
+
+union trampolines_x86_64 {
+	struct libffi_trampoline_x86_64 lf;
+	struct gcc_trampoline_x86_64_type1 g1;
+	struct gcc_trampoline_x86_64_type2 g2;
+};
+
+static inline int is_libffi_tramp_x86_64(const union trampolines_x86_64 *u)
+{
+	return (u->lf.mov1 == 0xBB49 &&
+		u->lf.mov2 == 0xBA49 &&
+		(u->lf.stcclc == 0xF8 ||
+		 u->lf.stcclc == 0xF9) &&
+		u->lf.jmp1 == 0xFF49 &&
+		u->lf.jmp2 == 0xE3);
+}
+
+static inline void emu_libffi_tramp_x86_64(const union trampolines_x86_64 *u,
+					   struct pt_regs *regs)
+{
+	regs->r11 = u->lf.addr1;
+	regs->r10 = u->lf.addr2;
+	regs->ip = u->lf.addr1;
+	if (u->lf.stcclc == 0xF8)
+		regs->flags &= ~X86_EFLAGS_CF;
+	else
+		regs->flags |= X86_EFLAGS_CF;
+}
+
+static inline int is_gcc_tramp_x86_64_t1(const union trampolines_x86_64 *u,
+					 const struct pt_regs *regs)
+{
+	return (u->g1.mov1 == 0xBB49 &&
+		u->g1.mov2 == 0xBA49 &&
+		u->g1.jmp1 == 0xFF49 &&
+		u->g1.jmp2 == 0xE3 &&
+		regs->ip > regs->sp);
+}
+
+static inline void emu_gcc_tramp_x86_64_t1(const union trampolines_x86_64 *u,
+					   struct pt_regs *regs)
+{
+	regs->r11 = u->g1.addr1;
+	regs->r10 = u->g1.addr2;
+	regs->ip = u->g1.addr1;
+}
+
+static inline int is_gcc_tramp_x86_64_t2(const union trampolines_x86_64 *u,
+					 const struct pt_regs *regs)
+{
+	return (u->g2.mov1 == 0xBB41 &&
+		u->g2.mov2 == 0xBA49 &&
+		u->g2.jmp1 == 0xFF49 &&
+		u->g2.jmp2 == 0xE3 &&
+		regs->ip > regs->sp);
+}
+
+static inline void emu_gcc_tramp_x86_64_t2(const union trampolines_x86_64 *u,
+					   struct pt_regs *regs)
+{
+	regs->r11 = u->g2.addr1;
+	regs->r10 = u->g2.addr2;
+	regs->ip = u->g2.addr1;
+}
+
+static inline int sara_trampoline_emulator_x86_64(struct pt_regs *regs,
+						  unsigned long address)
+{
+	int ret;
+	void __user *ip = (void __user *) regs->ip;
+	union trampolines_x86_64 t;
+
+	BUILD_BUG_ON(sizeof(t.g1) > sizeof(t.lf));
+	BUILD_BUG_ON(sizeof(t.g2) > sizeof(t.g1));
+
+	if (regs->cs == __USER32_CS ||
+	    regs->cs & (1<<2)) {
+		if (address >> 32)	/* K8 erratum #100 */
+			return 0;
+		return sara_trampoline_emulator_x86_32(regs);
+	}
+
+	ret = copy_from_user(&t, ip, sizeof(t.lf));
+	if (ret)
+		ret = copy_from_user(&t, ip, sizeof(t.g1));
+	if (ret)
+		ret = copy_from_user(&t, ip, sizeof(t.g2));
+	if (ret)
+		return 0;
+
+	if (is_libffi_tramp_x86_64(&t)) {
+		pr_debug("Trampoline: libffi x86_64.\n");
+		emu_libffi_tramp_x86_64(&t, regs);
+		return 1;
+	} else if (is_gcc_tramp_x86_64_t1(&t, regs)) {
+		pr_debug("Trampoline: gcc1 x86_64.\n");
+		emu_gcc_tramp_x86_64_t1(&t, regs);
+		return 1;
+	} else if (is_gcc_tramp_x86_64_t2(&t, regs)) {
+		pr_debug("Trampoline: gcc2 x86_64.\n");
+		emu_gcc_tramp_x86_64_t2(&t, regs);
+		return 1;
+	}
+
+	pr_debug("Not a trampoline (x86_64).\n");
+
+	return 0;
+
+}
+
+#endif /* __SARA_TRAMPOLINES64_H */
diff --git a/security/sara/Kconfig b/security/sara/Kconfig
index 54a96e0..458e0e8 100644
--- a/security/sara/Kconfig
+++ b/security/sara/Kconfig
@@ -117,6 +117,24 @@ choice
 		  Documentation/admin-guide/LSM/SARA.rst.
 endchoice
 
+config SECURITY_SARA_WXPROT_EMUTRAMP
+	bool "Enable emulation for some types of trampolines"
+	depends on SECURITY_SARA_WXPROT
+	depends on ARCH_HAS_LSM_PAGEFAULT
+	depends on X86
+	default y
+	help
+	  Some programs and libraries need to execute special small code
+	  snippets from non-executable memory pages.
+	  Most notable examples are the GCC and libffi trampolines.
+	  This features make it possible to execute those trampolines even
+	  if they reside in non-executable memory pages.
+	  This features need to be enabled on a per-executable basis
+	  via user-space utilities.
+	  See Documentation/admin-guide/LSM/SARA.rst. for further information.
+
+	  If unsure, answer y.
+
 config SECURITY_SARA_WXPROT_DISABLED
 	bool "WX protection will be disabled at boot."
 	depends on SECURITY_SARA_WXPROT
diff --git a/security/sara/include/emutramp.h b/security/sara/include/emutramp.h
new file mode 100644
index 0000000..d82f92d
--- /dev/null
+++ b/security/sara/include/emutramp.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * S.A.R.A. Linux Security Module
+ *
+ * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * Assembly sequences used here were copied from
+ * PaX patch by PaX Team <pageexec@freemail.hu>
+ * Being just hexadecimal constants, they are not subject to
+ * any copyright.
+ *
+ */
+
+#ifndef __SARA_EMUTRAMP_H
+#define __SARA_EMUTRAMP_H
+
+#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
+int sara_trampoline_emulator(struct pt_regs *regs,
+			     unsigned long error_code,
+			     unsigned long address);
+#else
+inline int sara_trampoline_emulator(struct pt_regs *regs,
+				    unsigned long error_code,
+				    unsigned long address)
+{
+	return 0;
+}
+#endif /* CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP */
+
+#endif /* __SARA_EMUTRAMP_H */
diff --git a/security/sara/wxprot.c b/security/sara/wxprot.c
index 8a3d002..9c42bfc 100644
--- a/security/sara/wxprot.c
+++ b/security/sara/wxprot.c
@@ -31,6 +31,7 @@
 #include "include/utils.h"
 #include "include/securityfs.h"
 #include "include/wxprot.h"
+#include "include/emutramp.h"
 
 #define SARA_WXPROT_CONFIG_VERSION 0
 
@@ -41,6 +42,7 @@
 #define SARA_WXP_COMPLAIN	0x0010
 #define SARA_WXP_VERBOSE	0x0020
 #define SARA_WXP_MMAP		0x0040
+#define SARA_WXP_EMUTRAMP	0x0100
 #define SARA_WXP_TRANSFER	0x0200
 #define SARA_WXP_NONE		0x0000
 #define SARA_WXP_MPROTECT	(SARA_WXP_HEAP	| \
@@ -51,7 +53,12 @@
 				 SARA_WXP_WXORX		| \
 				 SARA_WXP_COMPLAIN	| \
 				 SARA_WXP_VERBOSE)
+#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
+#define SARA_WXP_ALL		(__SARA_WXP_ALL		| \
+				 SARA_WXP_EMUTRAMP)
+#else /* CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP */
 #define SARA_WXP_ALL		__SARA_WXP_ALL
+#endif /* CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP */
 
 struct wxprot_config_container {
 	struct sara_dfa_tables *dfa;
@@ -67,7 +74,11 @@ struct wxprot_config_container {
 static u16 default_flags __lsm_ro_after_init =
 				CONFIG_SECURITY_SARA_WXPROT_DEFAULT_FLAGS;
 
+#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
+static const bool wxprot_emutramp = true;
+#else
 static const bool wxprot_emutramp;
+#endif
 
 static void pr_wxp(char *msg)
 {
@@ -110,6 +121,9 @@ static bool are_flags_valid(u16 flags)
 	if (unlikely(flags & SARA_WXP_MMAP &&
 		     !(flags & SARA_WXP_OTHER)))
 		return false;
+	if (unlikely(flags & SARA_WXP_EMUTRAMP &&
+		     ((flags & SARA_WXP_MPROTECT) != SARA_WXP_MPROTECT)))
+		return false;
 	return true;
 }
 
@@ -514,11 +528,26 @@ static int sara_file_mprotect(struct vm_area_struct *vma,
 	return 0;
 }
 
+#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
+static int sara_pagefault_handler(struct pt_regs *regs,
+				  unsigned long error_code,
+				  unsigned long address)
+{
+	if (!sara_enabled || !wxprot_enabled ||
+	    likely(!(get_current_sara_wxp_flags() & SARA_WXP_EMUTRAMP)))
+		return 0;
+	return sara_trampoline_emulator(regs, error_code, address);
+}
+#endif
+
 static struct security_hook_list wxprot_hooks[] __lsm_ro_after_init = {
 	LSM_HOOK_INIT(bprm_set_creds, sara_bprm_set_creds),
 	LSM_HOOK_INIT(check_vmflags, sara_check_vmflags),
 	LSM_HOOK_INIT(shm_shmat, sara_shm_shmat),
 	LSM_HOOK_INIT(file_mprotect, sara_file_mprotect),
+#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
+	LSM_HOOK_INIT(pagefault_handler, sara_pagefault_handler),
+#endif
 };
 
 static void config_free(struct wxprot_config_container *data)
-- 
1.9.1


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

* [PATCH v5 09/12] S.A.R.A.: WX protection procattr interface
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
                   ` (7 preceding siblings ...)
  2019-07-06 10:54 ` [PATCH v5 08/12] S.A.R.A.: trampoline emulation Salvatore Mesoraca
@ 2019-07-06 10:54 ` Salvatore Mesoraca
  2019-07-06 10:54 ` [PATCH v5 10/12] S.A.R.A.: XATTRs support Salvatore Mesoraca
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 10:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Salvatore Mesoraca, Serge E. Hallyn, Thomas Gleixner

This allow threads to get current WX Protection flags for themselves or
for other threads (if they have CAP_MAC_ADMIN).
It also allow a thread to set itself flags to a stricter set of rules than
the current one.
Via a new wxprot flag (SARA_WXP_FORCE_WXORX) is it possible to ask the
kernel to rescan the memory and remove the VM_WRITE flag from any area
that is marked both writable and executable.
Protections that prevent the runtime creation of executable code
can be troublesome for all those programs that actually need to do it
e.g. programs shipping with a JIT compiler built-in.
This feature can be use to run the JIT compiler with few restrictions while
enforcing full WX Protection in the rest of the program.
To simplify access to this interface a CC0 licensed library is available
here: https://github.com/smeso/libsara

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 fs/proc/base.c         |  11 ++++
 security/sara/wxprot.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 161 insertions(+)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 255f675..7873d27 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2612,6 +2612,13 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
 LSM_DIR_OPS(smack);
 #endif
 
+#ifdef CONFIG_SECURITY_SARA
+static const struct pid_entry sara_attr_dir_stuff[] = {
+	ATTR("sara", "wxprot", 0666),
+};
+LSM_DIR_OPS(sara);
+#endif
+
 static const struct pid_entry attr_dir_stuff[] = {
 	ATTR(NULL, "current",		0666),
 	ATTR(NULL, "prev",		0444),
@@ -2623,6 +2630,10 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
 	DIR("smack",			0555,
 	    proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops),
 #endif
+#ifdef CONFIG_SECURITY_SARA
+	DIR("sara",			0555,
+	    proc_sara_attr_dir_inode_ops, proc_sara_attr_dir_ops),
+#endif
 };
 
 static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx)
diff --git a/security/sara/wxprot.c b/security/sara/wxprot.c
index 9c42bfc..84f7b1e 100644
--- a/security/sara/wxprot.c
+++ b/security/sara/wxprot.c
@@ -14,6 +14,7 @@
 #ifdef CONFIG_SECURITY_SARA_WXPROT
 
 #include <linux/binfmts.h>
+#include <linux/capability.h>
 #include <linux/cred.h>
 #include <linux/elf.h>
 #include <linux/kref.h>
@@ -42,6 +43,7 @@
 #define SARA_WXP_COMPLAIN	0x0010
 #define SARA_WXP_VERBOSE	0x0020
 #define SARA_WXP_MMAP		0x0040
+#define SARA_WXP_FORCE_WXORX	0x0080
 #define SARA_WXP_EMUTRAMP	0x0100
 #define SARA_WXP_TRANSFER	0x0200
 #define SARA_WXP_NONE		0x0000
@@ -540,6 +542,152 @@ static int sara_pagefault_handler(struct pt_regs *regs,
 }
 #endif
 
+static int sara_getprocattr(struct task_struct *p, char *name, char **value)
+{
+	int ret;
+	u16 flags;
+	char *buf;
+
+	ret = -EINVAL;
+	if (strcmp(name, "wxprot") != 0)
+		goto out;
+
+	ret = -EACCES;
+	if (unlikely(current != p &&
+		     !capable(CAP_MAC_ADMIN)))
+		goto out;
+
+	ret = -ENOMEM;
+	buf = kzalloc(8, GFP_KERNEL);
+	if (unlikely(buf == NULL))
+		goto out;
+
+	if (!sara_enabled || !wxprot_enabled) {
+		flags = 0x0;
+	} else {
+		rcu_read_lock();
+		flags = get_sara_wxp_flags(__task_cred(p));
+		rcu_read_unlock();
+	}
+
+	snprintf(buf, 8, "0x%04x\n", flags);
+	ret = strlen(buf);
+	*value = buf;
+
+out:
+	return ret;
+}
+
+static int sara_setprocattr(const char *name, void *value, size_t size)
+{
+	int ret;
+	struct vm_area_struct *vma;
+	struct cred *new = prepare_creds();
+	u16 cur_flags;
+	u16 req_flags;
+	char *buf = NULL;
+
+	ret = -EINVAL;
+	if (!sara_enabled || !wxprot_enabled)
+		goto error;
+	if (unlikely(new == NULL))
+		return -ENOMEM;
+	if (strcmp(name, "wxprot") != 0)
+		goto error;
+	if (unlikely(value == NULL || size == 0 || size > 7))
+		goto error;
+	ret = -ENOMEM;
+	buf = kmalloc(size+1, GFP_KERNEL);
+	if (unlikely(buf == NULL))
+		goto error;
+	buf[size] = '\0';
+	memcpy(buf, value, size);
+	ret = -EINVAL;
+	if (unlikely(strlen(buf) != size))
+		goto error;
+	if (unlikely(kstrtou16(buf, 0, &req_flags) != 0))
+		goto error;
+	/*
+	 * SARA_WXP_FORCE_WXORX is a procattr only flag with a special
+	 * meaning and it isn't recognized by are_flags_valid
+	 */
+	if (unlikely(!are_flags_valid(req_flags & ~SARA_WXP_FORCE_WXORX)))
+		goto error;
+	/*
+	 * Extra checks on requested flags:
+	 *   - SARA_WXP_FORCE_WXORX requires SARA_WXP_WXORX
+	 *   - SARA_WXP_MMAP can only be activated if the program
+	 *     has a relro section
+	 *   - COMPLAIN mode can only be requested if it was already
+	 *     on (procattr can only be used to make protection stricter)
+	 *   - EMUTRAMP can only be activated if it was already on or
+	 *     if MPROTECT and WXORX weren't already on (procattr can
+	 *     only be used to make protection stricter)
+	 *   - VERBOSITY request is ignored
+	 */
+	if (unlikely(req_flags & SARA_WXP_FORCE_WXORX &&
+		     !(req_flags & SARA_WXP_WXORX)))
+		goto error;
+	if (unlikely(!get_current_sara_relro_page_found() &&
+		     req_flags & SARA_WXP_MMAP))
+		goto error;
+	cur_flags = get_current_sara_wxp_flags();
+	if (unlikely((req_flags & SARA_WXP_COMPLAIN) &&
+		     !(cur_flags & SARA_WXP_COMPLAIN)))
+		goto error;
+	if (unlikely((req_flags & SARA_WXP_EMUTRAMP) &&
+		     !(cur_flags & SARA_WXP_EMUTRAMP) &&
+		     (cur_flags & (SARA_WXP_MPROTECT |
+				   SARA_WXP_WXORX))))
+		goto error;
+	if (cur_flags & SARA_WXP_VERBOSE)
+		req_flags |= SARA_WXP_VERBOSE;
+	else
+		req_flags &= ~SARA_WXP_VERBOSE;
+	/*
+	 * Except SARA_WXP_COMPLAIN and SARA_WXP_EMUTRAMP,
+	 * any other flag can't be removed (procattr can
+	 * only be used to make protection stricter).
+	 */
+	if (unlikely(cur_flags & (req_flags ^ cur_flags) &
+		     ~(SARA_WXP_COMPLAIN|SARA_WXP_EMUTRAMP)))
+		goto error;
+	ret = -EINTR;
+	/*
+	 * When SARA_WXP_FORCE_WXORX is on we traverse all the
+	 * memory and remove the write permission from any area
+	 * that is both writable and executable.
+	 */
+	if (req_flags & SARA_WXP_FORCE_WXORX) {
+		if (down_write_killable(&current->mm->mmap_sem))
+			goto error;
+		for (vma = current->mm->mmap; vma; vma = vma->vm_next) {
+			if (vma->vm_flags & VM_EXEC &&
+			    vma->vm_flags & VM_WRITE) {
+				vma->vm_flags &= ~VM_WRITE;
+				vma_set_page_prot(vma);
+				change_protection(vma,
+						  vma->vm_start,
+						  vma->vm_end,
+						  vma->vm_page_prot,
+						  0,
+						  0);
+			}
+		}
+		up_write(&current->mm->mmap_sem);
+	}
+	get_sara_wxp_flags(new) = req_flags & ~SARA_WXP_FORCE_WXORX;
+	commit_creds(new);
+	ret = size;
+	goto out;
+
+error:
+	abort_creds(new);
+out:
+	kfree(buf);
+	return ret;
+}
+
 static struct security_hook_list wxprot_hooks[] __lsm_ro_after_init = {
 	LSM_HOOK_INIT(bprm_set_creds, sara_bprm_set_creds),
 	LSM_HOOK_INIT(check_vmflags, sara_check_vmflags),
@@ -548,6 +696,8 @@ static int sara_pagefault_handler(struct pt_regs *regs,
 #ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
 	LSM_HOOK_INIT(pagefault_handler, sara_pagefault_handler),
 #endif
+	LSM_HOOK_INIT(getprocattr, sara_getprocattr),
+	LSM_HOOK_INIT(setprocattr, sara_setprocattr),
 };
 
 static void config_free(struct wxprot_config_container *data)
-- 
1.9.1


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

* [PATCH v5 10/12] S.A.R.A.: XATTRs support
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
                   ` (8 preceding siblings ...)
  2019-07-06 10:54 ` [PATCH v5 09/12] S.A.R.A.: WX protection procattr interface Salvatore Mesoraca
@ 2019-07-06 10:54 ` Salvatore Mesoraca
  2019-07-06 10:54 ` [PATCH v5 11/12] S.A.R.A.: /proc/*/mem write limitation Salvatore Mesoraca
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 10:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Salvatore Mesoraca, Serge E. Hallyn, Thomas Gleixner

Adds support for extended filesystem attributes in security and user
namespaces. They can be used to override flags set via the centralized
configuration, even when S.A.R.A. configuration is locked or saractl
is not used at all.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 Documentation/admin-guide/LSM/SARA.rst          | 20 +++++
 Documentation/admin-guide/kernel-parameters.txt | 16 ++++
 include/uapi/linux/xattr.h                      |  4 +
 security/sara/Kconfig                           | 22 ++++++
 security/sara/wxprot.c                          | 99 +++++++++++++++++++++++++
 5 files changed, 161 insertions(+)

diff --git a/Documentation/admin-guide/LSM/SARA.rst b/Documentation/admin-guide/LSM/SARA.rst
index fdde04c..47d9364 100644
--- a/Documentation/admin-guide/LSM/SARA.rst
+++ b/Documentation/admin-guide/LSM/SARA.rst
@@ -55,6 +55,8 @@ WX Protection. In particular:
 To extend the scope of the above features, despite the issues that they may
 cause, they are complemented by **/proc/PID/attr/sara/wxprot** interface
 and **trampoline emulation**.
+It's also possible to override the centralized configuration via `Extended
+filesystem attributes`_.
 
 At the moment, WX Protection (unless specified otherwise) should work on
 any architecture supporting the NX bit, including, but not limited to:
@@ -123,6 +125,24 @@ in your project or copy/paste parts of it.
 To make things simpler `libsara` is the only part of S.A.R.A. released under
 *CC0 - No Rights Reserved* license.
 
+Extended filesystem attributes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+When this functionality is enabled, it's possible to override
+WX Protection flags set in the main configuration via extended attributes,
+even when S.A.R.A.'s configuration is in "locked" mode.
+If the user namespace is also enabled, its attributes will override settings
+configured via the security namespace.
+The xattrs currently in use are:
+
+- security.sara.wxprot
+- user.sara.wxprot
+
+They can be manually set to the desired value as a decimal, hexadecimal or
+octal number. When this functionality is enabled, S.A.R.A. can be easily used
+without the help of its userspace tools. Though the preferred way to change
+these attributes is `sara-xattr` which is part of `saractl` [2]_.
+
+
 Trampoline emulation
 ^^^^^^^^^^^^^^^^^^^^
 Some programs need to generate part of their code at runtime. Luckily enough,
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 3d6e86d..af40f1b 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -4254,6 +4254,22 @@
 			See S.A.R.A. documentation.
 			Default value is set via kernel config option.
 
+	sara.wxprot_xattrs_enabled= [SARA]
+			Enable support for security xattrs.
+			Format: { "0" | "1" }
+			See security/sara/Kconfig help text
+			0 -- disable.
+			1 -- enable.
+			Default value is set via kernel config option.
+
+	sara.wxprot_xattrs_user= [SARA]
+			Enable support for user xattrs.
+			Format: { "0" | "1" }
+			See security/sara/Kconfig help text
+			0 -- disable.
+			1 -- enable.
+			Default value is set via kernel config option.
+
 	serialnumber	[BUGS=X86-32]
 
 	shapers=	[NET]
diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h
index c1395b5..45c0333 100644
--- a/include/uapi/linux/xattr.h
+++ b/include/uapi/linux/xattr.h
@@ -77,5 +77,9 @@
 #define XATTR_POSIX_ACL_DEFAULT  "posix_acl_default"
 #define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT
 
+#define XATTR_SARA_SUFFIX "sara."
+#define XATTR_SARA_WXP_SUFFIX XATTR_SARA_SUFFIX "wxp"
+#define XATTR_NAME_SEC_SARA_WXP XATTR_SECURITY_PREFIX XATTR_SARA_WXP_SUFFIX
+#define XATTR_NAME_USR_SARA_WXP XATTR_USER_PREFIX XATTR_SARA_WXP_SUFFIX
 
 #endif /* _UAPI_LINUX_XATTR_H */
diff --git a/security/sara/Kconfig b/security/sara/Kconfig
index 458e0e8..773256b 100644
--- a/security/sara/Kconfig
+++ b/security/sara/Kconfig
@@ -135,6 +135,28 @@ config SECURITY_SARA_WXPROT_EMUTRAMP
 
 	  If unsure, answer y.
 
+config SECURITY_SARA_WXPROT_XATTRS_ENABLED
+	bool "xattrs support enabled by default."
+	depends on SECURITY_SARA_WXPROT
+	default n
+	help
+	  If you say Y here it will be possible to override WX protection
+	  configuration via extended attributes in the security namespace.
+	  Even when S.A.R.A.'s configuration has been locked.
+
+	  If unsure, answer N.
+
+config CONFIG_SECURITY_SARA_WXPROT_XATTRS_USER
+	bool "'user' namespace xattrs support enabled by default."
+	depends on SECURITY_SARA_WXPROT_XATTRS_ENABLED
+	default n
+	help
+	  If you say Y here it will be possible to override WX protection
+	  configuration via extended attributes in the user namespace.
+	  Even when S.A.R.A.'s configuration has been locked.
+
+	  If unsure, answer N.
+
 config SECURITY_SARA_WXPROT_DISABLED
 	bool "WX protection will be disabled at boot."
 	depends on SECURITY_SARA_WXPROT
diff --git a/security/sara/wxprot.c b/security/sara/wxprot.c
index 84f7b1e..773d1fd 100644
--- a/security/sara/wxprot.c
+++ b/security/sara/wxprot.c
@@ -25,6 +25,7 @@
 #include <linux/printk.h>
 #include <linux/ratelimit.h>
 #include <linux/spinlock.h>
+#include <linux/xattr.h>
 
 #include "include/dfa.h"
 #include "include/sara.h"
@@ -82,6 +83,18 @@ struct wxprot_config_container {
 static const bool wxprot_emutramp;
 #endif
 
+#ifdef CONFIG_SECURITY_SARA_WXPROT_XATTRS_ENABLED
+static int wxprot_xattrs_enabled __read_mostly = true;
+#else
+static int wxprot_xattrs_enabled __read_mostly;
+#endif
+
+#ifdef CONFIG_SECURITY_SARA_WXPROT_XATTRS_USER
+static int wxprot_xattrs_user __read_mostly = true;
+#else
+static int wxprot_xattrs_user __read_mostly;
+#endif
+
 static void pr_wxp(char *msg)
 {
 	char *buf, *path;
@@ -133,6 +146,14 @@ static bool are_flags_valid(u16 flags)
 MODULE_PARM_DESC(wxprot_enabled,
 		 "Disable or enable S.A.R.A. WX Protection at boot time.");
 
+module_param(wxprot_xattrs_enabled, int, 0);
+MODULE_PARM_DESC(wxprot_xattrs_enabled,
+		 "Disable or enable S.A.R.A. WXP extended attributes interfaces.");
+
+module_param(wxprot_xattrs_user, int, 0);
+MODULE_PARM_DESC(wxprot_xattrs_user,
+		 "Allow normal users to override S.A.R.A. WXP settings via extended attributes.");
+
 static int param_set_wxpflags(const char *val, const struct kernel_param *kp)
 {
 	u16 flags;
@@ -236,6 +257,65 @@ static inline int is_relro_page(const struct vm_area_struct *vma)
 }
 
 /*
+ * Extended attributes handling
+ */
+static int sara_wxprot_xattrs_name(struct dentry *d,
+				   const char *name,
+				   u16 *flags)
+{
+	int rc;
+	char buffer[10];
+	u16 tmp;
+
+	if (!(d->d_inode->i_opflags & IOP_XATTR))
+		return -EOPNOTSUPP;
+
+	rc = __vfs_getxattr(d, d->d_inode, name, buffer, sizeof(buffer) - 1);
+	if (rc > 0) {
+		buffer[rc] = '\0';
+		rc = kstrtou16(buffer, 0, &tmp);
+		if (rc)
+			return rc;
+		if (!are_flags_valid(tmp))
+			return -EINVAL;
+		*flags = tmp;
+		return 0;
+	} else if (rc < 0)
+		return rc;
+
+	return -ENODATA;
+}
+
+#define sara_xattrs_may_return(RC, XATTRNAME, FNAME) do {	\
+	if (RC == -EINVAL || RC == -ERANGE)			\
+		pr_info_ratelimited(				\
+			"WXP: malformed xattr '%s' on '%s'\n",	\
+			XATTRNAME,				\
+			FNAME);					\
+	else if (RC == 0)					\
+		return 0;					\
+} while (0)
+
+static inline int sara_wxprot_xattrs(struct dentry *d,
+				     u16 *flags)
+{
+	int rc;
+
+	if (!wxprot_xattrs_enabled)
+		return 1;
+	if (wxprot_xattrs_user) {
+		rc = sara_wxprot_xattrs_name(d, XATTR_NAME_USR_SARA_WXP,
+					     flags);
+		sara_xattrs_may_return(rc, XATTR_NAME_USR_SARA_WXP,
+				       d->d_name.name);
+	}
+	rc = sara_wxprot_xattrs_name(d, XATTR_NAME_SEC_SARA_WXP, flags);
+	sara_xattrs_may_return(rc, XATTR_NAME_SEC_SARA_WXP, d->d_name.name);
+	return 1;
+}
+
+
+/*
  * LSM hooks
  */
 static int sara_bprm_set_creds(struct linux_binprm *bprm)
@@ -259,6 +339,10 @@ static int sara_bprm_set_creds(struct linux_binprm *bprm)
 	if (!sara_enabled || !wxprot_enabled)
 		return 0;
 
+	if (sara_wxprot_xattrs(bprm->file->f_path.dentry,
+			       &sara_wxp_flags) == 0)
+		goto flags_set;
+
 	/*
 	 * SARA_WXP_TRANSFER means that the parent
 	 * wants this child to inherit its flags.
@@ -283,6 +367,7 @@ static int sara_bprm_set_creds(struct linux_binprm *bprm)
 	} else
 		path = (char *) bprm->interp;
 
+flags_set:
 	if (sara_wxp_flags != default_flags &&
 	    sara_wxp_flags & SARA_WXP_VERBOSE)
 		pr_debug_ratelimited("WXP: '%s' run with flags '0x%x'.\n",
@@ -777,6 +862,10 @@ static int config_hash(char **buf)
 
 static DEFINE_SARA_SECFS_BOOL_FLAG(wxprot_enabled_data,
 				   wxprot_enabled);
+static DEFINE_SARA_SECFS_BOOL_FLAG(wxprot_xattrs_enabled_data,
+				   wxprot_xattrs_enabled);
+static DEFINE_SARA_SECFS_BOOL_FLAG(wxprot_xattrs_user_data,
+				   wxprot_xattrs_user);
 
 static struct sara_secfs_fptrs fptrs __lsm_ro_after_init = {
 	.load = config_load,
@@ -820,6 +909,16 @@ static DEFINE_SARA_SECFS_BOOL_FLAG(wxprot_enabled_data,
 		.type = SARA_SECFS_CONFIG_HASH,
 		.data = &fptrs,
 	},
+	{
+		.name = "xattr_enabled",
+		.type = SARA_SECFS_BOOL,
+		.data = (void *) &wxprot_xattrs_enabled_data,
+	},
+	{
+		.name = "xattr_user_allowed",
+		.type = SARA_SECFS_BOOL,
+		.data = (void *) &wxprot_xattrs_user_data,
+	},
 };
 
 
-- 
1.9.1


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

* [PATCH v5 11/12] S.A.R.A.: /proc/*/mem write limitation
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
                   ` (9 preceding siblings ...)
  2019-07-06 10:54 ` [PATCH v5 10/12] S.A.R.A.: XATTRs support Salvatore Mesoraca
@ 2019-07-06 10:54 ` Salvatore Mesoraca
  2019-07-06 18:20   ` Jann Horn
  2019-07-06 10:54 ` [PATCH v5 12/12] MAINTAINERS: take maintainership for S.A.R.A Salvatore Mesoraca
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 10:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Salvatore Mesoraca, Serge E. Hallyn, Thomas Gleixner

Prevent a task from opening, in "write" mode, any /proc/*/mem
file that operates on the task's mm.
A process could use it to overwrite read-only memory, bypassing
S.A.R.A. restrictions.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 security/sara/include/sara_data.h | 18 ++++++++++++++++-
 security/sara/sara_data.c         |  8 ++++++++
 security/sara/wxprot.c            | 41 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/security/sara/include/sara_data.h b/security/sara/include/sara_data.h
index 9216c47..ee95f74 100644
--- a/security/sara/include/sara_data.h
+++ b/security/sara/include/sara_data.h
@@ -15,6 +15,7 @@
 #define __SARA_DATA_H
 
 #include <linux/cred.h>
+#include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/lsm_hooks.h>
 #include <linux/spinlock.h>
@@ -40,6 +41,10 @@ struct sara_shm_data {
 	spinlock_t	lock;
 };
 
+struct sara_inode_data {
+	struct task_struct *task;
+};
+
 
 static inline struct sara_data *get_sara_data(const struct cred *cred)
 {
@@ -79,6 +84,17 @@ static inline struct sara_shm_data *get_sara_shm_data(
 #define lock_sara_shm(X) (spin_lock(&get_sara_shm_data((X))->lock))
 #define unlock_sara_shm(X) (spin_unlock(&get_sara_shm_data((X))->lock))
 
-#endif
+
+static inline struct sara_inode_data *get_sara_inode_data(
+						const struct inode *inode)
+{
+	if (unlikely(!inode->i_security))
+		return NULL;
+	return inode->i_security + sara_blob_sizes.lbs_inode;
+}
+
+#define get_sara_inode_task(X) (get_sara_inode_data((X))->task)
+
+#endif /* CONFIG_SECURITY_SARA_WXPROT */
 
 #endif /* __SARA_H */
diff --git a/security/sara/sara_data.c b/security/sara/sara_data.c
index 9afca37..e875cf0 100644
--- a/security/sara/sara_data.c
+++ b/security/sara/sara_data.c
@@ -17,6 +17,7 @@
 #include <linux/cred.h>
 #include <linux/lsm_hooks.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 
 static int sara_cred_prepare(struct cred *new, const struct cred *old,
@@ -40,15 +41,22 @@ static int sara_shm_alloc_security(struct kern_ipc_perm *shp)
 	return 0;
 }
 
+static void sara_task_to_inode(struct task_struct *t, struct inode *i)
+{
+	get_sara_inode_task(i) = t;
+}
+
 static struct security_hook_list data_hooks[] __lsm_ro_after_init = {
 	LSM_HOOK_INIT(cred_prepare, sara_cred_prepare),
 	LSM_HOOK_INIT(cred_transfer, sara_cred_transfer),
 	LSM_HOOK_INIT(shm_alloc_security, sara_shm_alloc_security),
+	LSM_HOOK_INIT(task_to_inode, sara_task_to_inode),
 };
 
 struct lsm_blob_sizes sara_blob_sizes __lsm_ro_after_init = {
 	.lbs_cred = sizeof(struct sara_data),
 	.lbs_ipc = sizeof(struct sara_shm_data),
+	.lbs_inode = sizeof(struct sara_inode_data),
 };
 
 int __init sara_data_init(void)
diff --git a/security/sara/wxprot.c b/security/sara/wxprot.c
index 773d1fd..1a8d132 100644
--- a/security/sara/wxprot.c
+++ b/security/sara/wxprot.c
@@ -22,8 +22,11 @@
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/module.h>
+#include <linux/mount.h>
 #include <linux/printk.h>
 #include <linux/ratelimit.h>
+#include <linux/sched/mm.h>
+#include <linux/sched/task.h>
 #include <linux/spinlock.h>
 #include <linux/xattr.h>
 
@@ -615,6 +618,43 @@ static int sara_file_mprotect(struct vm_area_struct *vma,
 	return 0;
 }
 
+static int sara_file_open(struct file *file)
+{
+	struct task_struct *t;
+	struct mm_struct *mm;
+	u16 sara_wxp_flags = get_current_sara_wxp_flags();
+
+	/*
+	 * Prevent write access to /proc/.../mem
+	 * if it operates on the mm_struct of the
+	 * current process: it could be used to
+	 * bypass W^X.
+	 */
+
+	if (!sara_enabled ||
+	    !wxprot_enabled ||
+	    !(sara_wxp_flags & SARA_WXP_WXORX) ||
+	    !(file->f_mode & FMODE_WRITE))
+		return 0;
+
+	t = get_sara_inode_task(file_inode(file));
+	if (unlikely(t != NULL &&
+		     strcmp(file->f_path.dentry->d_name.name,
+			    "mem") == 0)) {
+		get_task_struct(t);
+		mm = get_task_mm(t);
+		put_task_struct(t);
+		if (unlikely(mm == current->mm))
+			sara_warn_or_goto(error,
+					  "write access to /proc/*/mem");
+		mmput(mm);
+	}
+	return 0;
+error:
+	mmput(mm);
+	return -EACCES;
+}
+
 #ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
 static int sara_pagefault_handler(struct pt_regs *regs,
 				  unsigned long error_code,
@@ -778,6 +818,7 @@ static int sara_setprocattr(const char *name, void *value, size_t size)
 	LSM_HOOK_INIT(check_vmflags, sara_check_vmflags),
 	LSM_HOOK_INIT(shm_shmat, sara_shm_shmat),
 	LSM_HOOK_INIT(file_mprotect, sara_file_mprotect),
+	LSM_HOOK_INIT(file_open, sara_file_open),
 #ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
 	LSM_HOOK_INIT(pagefault_handler, sara_pagefault_handler),
 #endif
-- 
1.9.1


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

* [PATCH v5 12/12] MAINTAINERS: take maintainership for S.A.R.A.
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
                   ` (10 preceding siblings ...)
  2019-07-06 10:54 ` [PATCH v5 11/12] S.A.R.A.: /proc/*/mem write limitation Salvatore Mesoraca
@ 2019-07-06 10:54 ` Salvatore Mesoraca
  2019-07-06 14:33 ` [PATCH v5 00/12] S.A.R.A. a new stacked LSM Jordan Glover
  2019-07-07  1:16 ` James Morris
  13 siblings, 0 replies; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 10:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Salvatore Mesoraca, Serge E. Hallyn, Thomas Gleixner

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index f16e5d0..de6dab1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13925,6 +13925,15 @@ F:	drivers/phy/samsung/phy-s5pv210-usb2.c
 F:	drivers/phy/samsung/phy-samsung-usb2.c
 F:	drivers/phy/samsung/phy-samsung-usb2.h
 
+SARA SECURITY MODULE
+M:	Salvatore Mesoraca <s.mesoraca16@gmail.com>
+T:	git git://github.com/smeso/sara.git lsm/sara/master
+W:	https://sara.smeso.it
+S:	Maintained
+F:	security/sara/
+F:	arch/x86/security/sara/
+F:	Documentation/admin-guide/LSM/SARA.rst
+
 SC1200 WDT DRIVER
 M:	Zwane Mwaikambo <zwanem@gmail.com>
 S:	Maintained
-- 
1.9.1


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

* Re: [PATCH v5 00/12] S.A.R.A. a new stacked LSM
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
                   ` (11 preceding siblings ...)
  2019-07-06 10:54 ` [PATCH v5 12/12] MAINTAINERS: take maintainership for S.A.R.A Salvatore Mesoraca
@ 2019-07-06 14:33 ` Jordan Glover
  2019-07-06 15:02   ` Salvatore Mesoraca
  2019-07-07  1:16 ` James Morris
  13 siblings, 1 reply; 35+ messages in thread
From: Jordan Glover @ 2019-07-06 14:33 UTC (permalink / raw)
  To: Salvatore Mesoraca
  Cc: linux-kernel, kernel-hardening, linux-mm, linux-security-module,
	Brad Spengler, Casey Schaufler, Christoph Hellwig, James Morris,
	Jann Horn, Kees Cook, PaX Team, Serge E. Hallyn, Thomas Gleixner

On Saturday, July 6, 2019 10:54 AM, Salvatore Mesoraca <s.mesoraca16@gmail.com> wrote:

> S.A.R.A. is meant to be stacked but it needs cred blobs and the procattr
> interface, so I temporarily implemented those parts in a way that won't
> be acceptable for upstream, but it works for now. I know that there
> is some ongoing work to make cred blobs and procattr stackable, as soon
> as the new interfaces will be available I'll reimplement the involved
> parts.

I thought all stacking pieces for minor LSM were merged in Linux 5.1.
Is there still something missing or is this comment out-fo-date?

Jordan

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

* Re: [PATCH v5 00/12] S.A.R.A. a new stacked LSM
  2019-07-06 14:33 ` [PATCH v5 00/12] S.A.R.A. a new stacked LSM Jordan Glover
@ 2019-07-06 15:02   ` Salvatore Mesoraca
  0 siblings, 0 replies; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 15:02 UTC (permalink / raw)
  To: Jordan Glover
  Cc: linux-kernel, kernel-hardening, linux-mm, linux-security-module,
	Brad Spengler, Casey Schaufler, Christoph Hellwig, James Morris,
	Jann Horn, Kees Cook, PaX Team, Serge E. Hallyn, Thomas Gleixner

You are right. I just forgot to remove that paragraph from the cover letter.
My bad.
Thank you for noticing that :)

Il giorno sab 6 lug 2019 alle ore 16:33 Jordan Glover
<Golden_Miller83@protonmail.ch> ha scritto:
>
> On Saturday, July 6, 2019 10:54 AM, Salvatore Mesoraca <s.mesoraca16@gmail.com> wrote:
>
> > S.A.R.A. is meant to be stacked but it needs cred blobs and the procattr
> > interface, so I temporarily implemented those parts in a way that won't
> > be acceptable for upstream, but it works for now. I know that there
> > is some ongoing work to make cred blobs and procattr stackable, as soon
> > as the new interfaces will be available I'll reimplement the involved
> > parts.
>
> I thought all stacking pieces for minor LSM were merged in Linux 5.1.
> Is there still something missing or is this comment out-fo-date?
>
> Jordan

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

* Re: [PATCH v5 02/12] S.A.R.A.: create framework
  2019-07-06 10:54 ` [PATCH v5 02/12] S.A.R.A.: create framework Salvatore Mesoraca
@ 2019-07-06 15:29   ` Randy Dunlap
  0 siblings, 0 replies; 35+ messages in thread
From: Randy Dunlap @ 2019-07-06 15:29 UTC (permalink / raw)
  To: Salvatore Mesoraca, linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Serge E. Hallyn, Thomas Gleixner

Hi,

On 7/6/19 3:54 AM, Salvatore Mesoraca wrote:
> diff --git a/security/sara/Kconfig b/security/sara/Kconfig
> new file mode 100644
> index 0000000..0456220
> --- /dev/null
> +++ b/security/sara/Kconfig
> @@ -0,0 +1,40 @@
> +menuconfig SECURITY_SARA
> +	bool "S.A.R.A."
> +	depends on SECURITY
> +	select SECURITYFS
> +	default n

No need for "default n".  Drop it, please.

> +	help
> +	  This selects S.A.R.A. LSM which aims to collect heterogeneous
> +	  security measures providing a common interface to manage them.
> +	  This LSM will always be stacked with the selected primary LSM and
> +	  other stacked LSMs.
> +	  Further information can be found in
> +	  Documentation/admin-guide/LSM/SARA.rst.
> +
> +	  If unsure, answer N.
> +
> +config SECURITY_SARA_DEFAULT_DISABLED
> +	bool "S.A.R.A. will be disabled at boot."
> +	depends on SECURITY_SARA
> +	default n
> +	help
> +	  If you say Y here, S.A.R.A. will not be enabled at startup. You can
> +	  override this option at boot time via "sara.enabled=[1|0]" kernel
> +	  parameter or via user-space utilities.
> +	  This option is useful for distro kernels.
> +
> +	  If unsure, answer N.
> +
> +config SECURITY_SARA_NO_RUNTIME_ENABLE
> +	bool "S.A.R.A. can be turn on only at boot time."

	               can be turned on

> +	depends on SECURITY_SARA_DEFAULT_DISABLED
> +	default y
> +	help
> +	  By enabling this option it won't be possible to turn on S.A.R.A.
> +	  at runtime via user-space utilities. However it can still be
> +	  turned on at boot time via the "sara.enabled=1" kernel parameter.
> +	  This option is functionally equivalent to "sara.enabled=0" kernel
> +	  parameter. This option is useful for distro kernels.
> +
> +	  If unsure, answer Y.
> +


-- 
~Randy

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

* Re: [PATCH v5 08/12] S.A.R.A.: trampoline emulation
  2019-07-06 10:54 ` [PATCH v5 08/12] S.A.R.A.: trampoline emulation Salvatore Mesoraca
@ 2019-07-06 15:31   ` Randy Dunlap
  0 siblings, 0 replies; 35+ messages in thread
From: Randy Dunlap @ 2019-07-06 15:31 UTC (permalink / raw)
  To: Salvatore Mesoraca, linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Serge E. Hallyn, Thomas Gleixner

On 7/6/19 3:54 AM, Salvatore Mesoraca wrote:
> diff --git a/security/sara/Kconfig b/security/sara/Kconfig
> index 54a96e0..458e0e8 100644
> --- a/security/sara/Kconfig
> +++ b/security/sara/Kconfig
> @@ -117,6 +117,24 @@ choice
>  		  Documentation/admin-guide/LSM/SARA.rst.
>  endchoice
>  
> +config SECURITY_SARA_WXPROT_EMUTRAMP
> +	bool "Enable emulation for some types of trampolines"
> +	depends on SECURITY_SARA_WXPROT
> +	depends on ARCH_HAS_LSM_PAGEFAULT
> +	depends on X86
> +	default y
> +	help
> +	  Some programs and libraries need to execute special small code
> +	  snippets from non-executable memory pages.
> +	  Most notable examples are the GCC and libffi trampolines.
> +	  This features make it possible to execute those trampolines even

	  This feature makes it possible

> +	  if they reside in non-executable memory pages.
> +	  This features need to be enabled on a per-executable basis

	  This feature needs to be

> +	  via user-space utilities.
> +	  See Documentation/admin-guide/LSM/SARA.rst. for further information.
> +
> +	  If unsure, answer y.
> +
>  config SECURITY_SARA_WXPROT_DISABLED
>  	bool "WX protection will be disabled at boot."
>  	depends on SECURITY_SARA_WXPROT


-- 
~Randy

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

* Re: [PATCH v5 06/12] S.A.R.A.: WX protection
  2019-07-06 10:54 ` [PATCH v5 06/12] S.A.R.A.: WX protection Salvatore Mesoraca
@ 2019-07-06 15:38   ` Randy Dunlap
  2019-07-06 19:28   ` Al Viro
  2019-07-08 12:42   ` David Laight
  2 siblings, 0 replies; 35+ messages in thread
From: Randy Dunlap @ 2019-07-06 15:38 UTC (permalink / raw)
  To: Salvatore Mesoraca, linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Serge E. Hallyn, Thomas Gleixner

On 7/6/19 3:54 AM, Salvatore Mesoraca wrote:
> diff --git a/security/sara/Kconfig b/security/sara/Kconfig
> index b98cf27..54a96e0 100644
> --- a/security/sara/Kconfig
> +++ b/security/sara/Kconfig
> @@ -60,3 +60,77 @@ config SECURITY_SARA_NO_RUNTIME_ENABLE
>  
>  	  If unsure, answer Y.
>  
> +config SECURITY_SARA_WXPROT
> +	bool "WX Protection: W^X and W!->X protections"
> +	depends on SECURITY_SARA
> +	default y
> +	help
> +	  WX Protection aims to improve user-space programs security by applying:
> +	    - W^X memory restriction
> +	    - W!->X (once writable never executable) mprotect restriction
> +	    - Executable MMAP prevention
> +	  See Documentation/admin-guide/LSM/SARA.rst. for further information.

	                                        .rst for further information.

> +
> +	  If unsure, answer Y.
> +
> +choice
> +	prompt "Default action for W^X and W!->X protections"
> +	depends on SECURITY_SARA
> +	depends on SECURITY_SARA_WXPROT
> +	default SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_COMPLAIN_VERBOSE
> +
> +        help

Use tab instead of spaces for indentation above.

> +	  Choose the default behaviour of WX Protection when no config
> +	  rule matches or no rule is loaded.
> +	  For further information on available flags and their meaning
> +	  see Documentation/admin-guide/LSM/SARA.rst.
> +
> +	config SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_COMPLAIN_VERBOSE
> +		bool "Protections enabled but not enforced."
> +		help
> +		  All features enabled except "Executable MMAP prevention",
> +		  verbose reporting, but no actual enforce: it just complains.
> +		  Its numeric value is 0x3f, for more information see
> +		  Documentation/admin-guide/LSM/SARA.rst.
> +
> +        config SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_ENFORCE_VERBOSE
> +		bool "Full protection, verbose."
> +		help
> +		  All features enabled except "Executable MMAP prevention".
> +		  The enabled features will be enforced with verbose reporting.
> +		  Its numeric value is 0x2f, for more information see
> +		  Documentation/admin-guide/LSM/SARA.rst.
> +
> +        config SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_ENFORCE
> +		bool "Full protection, quiet."
> +		help
> +		  All features enabled except "Executable MMAP prevention".
> +		  The enabled features will be enforced quietly.
> +		  Its numeric value is 0xf, for more information see
> +		  Documentation/admin-guide/LSM/SARA.rst.
> +
> +	config SECURITY_SARA_WXPROT_DEFAULT_FLAGS_NONE
> +		bool "No protection at all."
> +		help
> +		  All features disabled.
> +		  Its numeric value is 0, for more information see
> +		  Documentation/admin-guide/LSM/SARA.rst.
> +endchoice
> +
> +config SECURITY_SARA_WXPROT_DISABLED
> +	bool "WX protection will be disabled at boot."
> +	depends on SECURITY_SARA_WXPROT
> +	default n

Omit "default n" please.

> +	help
> +	  If you say Y here WX protection won't be enabled at startup. You can
> +	  override this option via user-space utilities or at boot time via
> +	  "sara.wxprot_enabled=[0|1]" kernel parameter.
> +
> +	  If unsure, answer N.
> +
> +config SECURITY_SARA_WXPROT_DEFAULT_FLAGS
> +	hex
> +	default "0x3f" if SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_COMPLAIN_VERBOSE
> +	default "0x2f" if SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_ENFORCE_VERBOSE
> +	default "0xf" if SECURITY_SARA_WXPROT_DEFAULT_FLAGS_ALL_ENFORCE
> +	default "0" if SECURITY_SARA_WXPROT_DEFAULT_FLAGS_NONE


-- 
~Randy

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

* Re: [PATCH v5 01/12] S.A.R.A.: add documentation
  2019-07-06 10:54 ` [PATCH v5 01/12] S.A.R.A.: add documentation Salvatore Mesoraca
@ 2019-07-06 17:14   ` Randy Dunlap
  2019-07-06 17:32     ` Salvatore Mesoraca
  2019-07-13  0:14   ` James Morris
  1 sibling, 1 reply; 35+ messages in thread
From: Randy Dunlap @ 2019-07-06 17:14 UTC (permalink / raw)
  To: Salvatore Mesoraca, linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Serge E. Hallyn, Thomas Gleixner

Hi,

Just a few typo fixes (inline).

On 7/6/19 3:54 AM, Salvatore Mesoraca wrote:
> Adding documentation for S.A.R.A. LSM.
> 
> Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
> ---
>  Documentation/admin-guide/LSM/SARA.rst          | 177 ++++++++++++++++++++++++
>  Documentation/admin-guide/LSM/index.rst         |   1 +
>  Documentation/admin-guide/kernel-parameters.txt |  24 ++++
>  3 files changed, 202 insertions(+)
>  create mode 100644 Documentation/admin-guide/LSM/SARA.rst
> 
> diff --git a/Documentation/admin-guide/LSM/SARA.rst b/Documentation/admin-guide/LSM/SARA.rst
> new file mode 100644
> index 0000000..fdde04c
> --- /dev/null
> +++ b/Documentation/admin-guide/LSM/SARA.rst
> @@ -0,0 +1,177 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +========
> +S.A.R.A.
> +========
> +
> +S.A.R.A. (S.A.R.A. is Another Recursive Acronym) is a stacked Linux Security
> +Module that aims to collect heterogeneous security measures, providing a common
> +interface to manage them.
> +As of today it consists of one submodule:
> +
> +- WX Protection
> +
> +
> +The kernel-space part is complemented by its user-space counterpart: `saractl`
> +[2]_.
> +A test suite for WX Protection, called `sara-test` [4]_, is also available.
> +More information about where to find these tools and the full S.A.R.A.
> +documentation are in the `External Links and Documentation`_ section.
> +
> +-------------------------------------------------------------------------------
> +
> +S.A.R.A.'s Submodules
> +=====================
> +
> +WX Protection
> +-------------
> +WX Protection aims to improve user-space programs security by applying:
> +
> +- `W^X enforcement`_
> +- `W!->X (once writable never executable) mprotect restriction`_
> +- `Executable MMAP prevention`_
> +
> +All of the above features can be enabled or disabled both system wide
> +or on a per executable basis through the use of configuration files managed by
> +`saractl` [2]_.
> +
> +It is important to note that some programs may have issues working with
> +WX Protection. In particular:
> +
> +- **W^X enforcement** will cause problems to any programs that needs
> +  memory pages mapped both as writable and executable at the same time e.g.
> +  programs with executable stack markings in the *PT_GNU_STACK* segment.
> +- **W!->X mprotect restriction** will cause problems to any program that
> +  needs to generate executable code at run time or to modify executable
> +  pages e.g. programs with a *JIT* compiler built-in or linked against a
> +  *non-PIC* library.
> +- **Executable MMAP prevention** can work only with programs that have at least
> +  partial *RELRO* support. It's disabled automatically for programs that
> +  lack this feature. It will cause problems to any program that uses *dlopen*
> +  or tries to do an executable mmap. Unfortunately this feature is the one
> +  that could create most problems and should be enabled only after careful
> +  evaluation.
> +
> +To extend the scope of the above features, despite the issues that they may
> +cause, they are complemented by **/proc/PID/attr/sara/wxprot** interface
> +and **trampoline emulation**.
> +
> +At the moment, WX Protection (unless specified otherwise) should work on
> +any architecture supporting the NX bit, including, but not limited to:
> +`x86_64`, `x86_32` (with PAE), `ARM` and `ARM64`.
> +
> +Parts of WX Protection are inspired by some of the features available in PaX.
> +
> +For further information about configuration file format and user-space
> +utilities please take a look at the full documentation [1]_.
> +
> +W^X enforcement
> +^^^^^^^^^^^^^^^
> +W^X means that a program can't have a page of memory that is marked, at the
> +same time, writable and executable. This also allow to detect many bad

                                                 allows

> +behaviours that make life much more easy for attackers. Programs running with
> +this feature enabled will be more difficult to exploit in the case they are
> +affected by some vulnerabilities, because the attacker will be forced
> +to make more steps in order to exploit them.
> +This feature also blocks accesses to /proc/*/mem files that would allow to
> +write the current process read-only memory, bypassing any protection.
> +
> +W!->X (once writable never executable) mprotect restriction
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +"Once writable never executable" means that any page that could have been
> +marked as writable in the past won't ever be allowed to be marked (e.g. via
> +an mprotect syscall) as executable.
> +This goes on the same track as W^X, but is much stricter and prevents
> +the runtime creation of new executable code in memory.
> +Obviously, this feature does not prevent a program from creating a new file and
> +*mmapping* it as executable, however, it will be way more difficult for
> +attackers to exploit vulnerabilities if this feature is enabled.
> +
> +Executable MMAP prevention
> +^^^^^^^^^^^^^^^^^^^^^^^^^^
> +This feature prevents the creation of new executable mmaps after the dynamic
> +libraries have been loaded. When used in combination with **W!->X mprotect
> +restriction** this feature will completely prevent the creation of new
> +executable code from the current thread.
> +Obviously, this feature does not prevent cases in which an attacker uses an
> +*execve* to start a completely new program. This kind of restriction, if
> +needed, can be applied using one of the other LSM that focuses on MAC.

                                                 LSMs

> +Please be aware that this feature can break many programs and so it should be
> +enabled after careful evaluation.
> +
> +/proc/PID/attr/sara/wxprot interface
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +The `procattr` interface can be used by a thread to discover which
> +WX Protection features are enabled and/or to tighten them: protection
> +can't be softened via procattr.
> +The interface is simple: it's a text file with an hexadecimal

                                             with a

> +number in it representing enabled features (more information can be
> +found in the `Flags values`_ section). Via this interface it is also
> +possible to perform a complete memory scan to remove the write permission
> +from pages that are both writable and executable, please note that this
> +change will also affect other threads of the same process.

[snip]

cheers.
-- 
~Randy

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

* Re: [PATCH v5 01/12] S.A.R.A.: add documentation
  2019-07-06 17:14   ` Randy Dunlap
@ 2019-07-06 17:32     ` Salvatore Mesoraca
  0 siblings, 0 replies; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-06 17:32 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: linux-kernel, Kernel Hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Serge E. Hallyn, Thomas Gleixner

Randy Dunlap <rdunlap@infradead.org> wrote:
>
> Hi,
>
> Just a few typo fixes (inline).

Hi Randy,
thank you for your help!
I'll address these and the other fixes in the next version of the patchset.

Best,

Salvatore

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

* Re: [PATCH v5 11/12] S.A.R.A.: /proc/*/mem write limitation
  2019-07-06 10:54 ` [PATCH v5 11/12] S.A.R.A.: /proc/*/mem write limitation Salvatore Mesoraca
@ 2019-07-06 18:20   ` Jann Horn
  2019-07-07 16:15     ` Salvatore Mesoraca
  0 siblings, 1 reply; 35+ messages in thread
From: Jann Horn @ 2019-07-06 18:20 UTC (permalink / raw)
  To: Salvatore Mesoraca
  Cc: kernel list, Kernel Hardening, Linux-MM, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Kees Cook, PaX Team,
	Serge E. Hallyn, Thomas Gleixner

On Sat, Jul 6, 2019 at 12:55 PM Salvatore Mesoraca
<s.mesoraca16@gmail.com> wrote:
> Prevent a task from opening, in "write" mode, any /proc/*/mem
> file that operates on the task's mm.
> A process could use it to overwrite read-only memory, bypassing
> S.A.R.A. restrictions.
[...]
> +static void sara_task_to_inode(struct task_struct *t, struct inode *i)
> +{
> +       get_sara_inode_task(i) = t;

This looks bogus. Nothing is actually holding a reference to `t` here, right?

> +}
> +
>  static struct security_hook_list data_hooks[] __lsm_ro_after_init = {
>         LSM_HOOK_INIT(cred_prepare, sara_cred_prepare),
>         LSM_HOOK_INIT(cred_transfer, sara_cred_transfer),
>         LSM_HOOK_INIT(shm_alloc_security, sara_shm_alloc_security),
> +       LSM_HOOK_INIT(task_to_inode, sara_task_to_inode),
>  };
[...]
> +static int sara_file_open(struct file *file)
> +{
> +       struct task_struct *t;
> +       struct mm_struct *mm;
> +       u16 sara_wxp_flags = get_current_sara_wxp_flags();
> +
> +       /*
> +        * Prevent write access to /proc/.../mem
> +        * if it operates on the mm_struct of the
> +        * current process: it could be used to
> +        * bypass W^X.
> +        */
> +
> +       if (!sara_enabled ||
> +           !wxprot_enabled ||
> +           !(sara_wxp_flags & SARA_WXP_WXORX) ||
> +           !(file->f_mode & FMODE_WRITE))
> +               return 0;
> +
> +       t = get_sara_inode_task(file_inode(file));
> +       if (unlikely(t != NULL &&
> +                    strcmp(file->f_path.dentry->d_name.name,
> +                           "mem") == 0)) {

This should probably at least have a READ_ONCE() somewhere in case the
file concurrently gets renamed?

> +               get_task_struct(t);
> +               mm = get_task_mm(t);
> +               put_task_struct(t);

Getting and dropping a reference to the task_struct here is completely
useless. Either you have a reference, in which case you don't need to
take another one, or you don't have a reference, in which case you
also can't take one.

> +               if (unlikely(mm == current->mm))
> +                       sara_warn_or_goto(error,
> +                                         "write access to /proc/*/mem");

Why is the current process so special that it must be protected more
than other processes? Is the idea here to rely on other protections to
protect all other tasks? This should probably come with a comment that
explains this choice.

> +               mmput(mm);
> +       }
> +       return 0;
> +error:
> +       mmput(mm);
> +       return -EACCES;
> +}

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

* Re: [PATCH v5 04/12] S.A.R.A.: generic DFA for string matching
  2019-07-06 10:54 ` [PATCH v5 04/12] S.A.R.A.: generic DFA for string matching Salvatore Mesoraca
@ 2019-07-06 18:32   ` Jann Horn
  2019-07-07 16:01     ` Salvatore Mesoraca
  0 siblings, 1 reply; 35+ messages in thread
From: Jann Horn @ 2019-07-06 18:32 UTC (permalink / raw)
  To: Salvatore Mesoraca
  Cc: kernel list, Kernel Hardening, Linux-MM, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Kees Cook, PaX Team,
	Serge E. Hallyn, Thomas Gleixner

On Sat, Jul 6, 2019 at 12:55 PM Salvatore Mesoraca
<s.mesoraca16@gmail.com> wrote:
> Creation of a generic Discrete Finite Automata implementation
> for string matching. The transition tables have to be produced
> in user-space.
> This allows us to possibly support advanced string matching
> patterns like regular expressions, but they need to be supported
> by user-space tools.

AppArmor already has a DFA implementation that takes a DFA machine
from userspace and runs it against file paths; see e.g.
aa_dfa_match(). Did you look into whether you could move their DFA to
some place like lib/ and reuse it instead of adding yet another
generic rule interface to the kernel?

[...]
> +++ b/security/sara/dfa.c
> @@ -0,0 +1,335 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * S.A.R.A. Linux Security Module
> + *
> + * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2, as
> + * published by the Free Software Foundation.

Throughout the series, you are adding files that both add an SPDX
identifier and have a description of the license in the comment block
at the top. The SPDX identifier already identifies the license.

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

* Re: [PATCH v5 06/12] S.A.R.A.: WX protection
  2019-07-06 10:54 ` [PATCH v5 06/12] S.A.R.A.: WX protection Salvatore Mesoraca
  2019-07-06 15:38   ` Randy Dunlap
@ 2019-07-06 19:28   ` Al Viro
  2019-07-07 15:49     ` Salvatore Mesoraca
  2019-07-08 12:42   ` David Laight
  2 siblings, 1 reply; 35+ messages in thread
From: Al Viro @ 2019-07-06 19:28 UTC (permalink / raw)
  To: Salvatore Mesoraca
  Cc: linux-kernel, kernel-hardening, linux-mm, linux-security-module,
	Brad Spengler, Casey Schaufler, Christoph Hellwig, James Morris,
	Jann Horn, Kees Cook, PaX Team, Serge E. Hallyn, Thomas Gleixner

On Sat, Jul 06, 2019 at 12:54:47PM +0200, Salvatore Mesoraca wrote:

> +#define sara_warn_or_return(err, msg) do {		\
> +	if ((sara_wxp_flags & SARA_WXP_VERBOSE))	\
> +		pr_wxp(msg);				\
> +	if (!(sara_wxp_flags & SARA_WXP_COMPLAIN))	\
> +		return -err;				\
> +} while (0)
> +
> +#define sara_warn_or_goto(label, msg) do {		\
> +	if ((sara_wxp_flags & SARA_WXP_VERBOSE))	\
> +		pr_wxp(msg);				\
> +	if (!(sara_wxp_flags & SARA_WXP_COMPLAIN))	\
> +		goto label;				\
> +} while (0)

No.  This kind of "style" has no place in the kernel.

Don't hide control flow.  It's nasty enough to reviewers,
but it's pure hell on anyone who strays into your code while
chasing a bug or doing general code audit.  In effect, you
are creating your oh-so-private C dialect and assuming that
everyone who ever looks at your code will start with learning
that *AND* incorporating it into their mental C parser.
I'm sorry, but you are not that important.

If it looks like a function call, a casual reader will assume
that this is exactly what it is.  And when one is scanning
through a function (e.g. to tell if handling of some kind
of refcounts is correct, with twentieth grep through the
tree having brought something in your code into the view),
the last thing one wants is to switch between the area-specific
C dialects.  Simply because looking at yours is sandwiched
between digging through some crap in drivers/target/ and that
weird thing in kernel/tracing/, hopefully staying limited
to 20 seconds of glancing through several functions in your
code.

Don't Do That.  Really.

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

* Re: [PATCH v5 00/12] S.A.R.A. a new stacked LSM
  2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
                   ` (12 preceding siblings ...)
  2019-07-06 14:33 ` [PATCH v5 00/12] S.A.R.A. a new stacked LSM Jordan Glover
@ 2019-07-07  1:16 ` James Morris
  2019-07-07 15:40   ` Salvatore Mesoraca
  13 siblings, 1 reply; 35+ messages in thread
From: James Morris @ 2019-07-07  1:16 UTC (permalink / raw)
  To: Salvatore Mesoraca
  Cc: linux-kernel, kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, Jann Horn, Kees Cook, PaX Team,
	Serge E. Hallyn, Thomas Gleixner

On Sat, 6 Jul 2019, Salvatore Mesoraca wrote:

> S.A.R.A. (S.A.R.A. is Another Recursive Acronym) is a stacked Linux

Please make this just SARA. Nobody wants to read or type S.A.R.A.



-- 
James Morris
<jmorris@namei.org>


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

* Re: [PATCH v5 00/12] S.A.R.A. a new stacked LSM
  2019-07-07  1:16 ` James Morris
@ 2019-07-07 15:40   ` Salvatore Mesoraca
  0 siblings, 0 replies; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-07 15:40 UTC (permalink / raw)
  To: James Morris
  Cc: linux-kernel, Kernel Hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, Jann Horn, Kees Cook, PaX Team,
	Serge E. Hallyn, Thomas Gleixner

James Morris <jmorris@namei.org> wrote:
>
> On Sat, 6 Jul 2019, Salvatore Mesoraca wrote:
>
> > S.A.R.A. (S.A.R.A. is Another Recursive Acronym) is a stacked Linux
>
> Please make this just SARA. Nobody wants to read or type S.A.R.A.

Agreed.
Thank you for your suggestion.

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

* Re: [PATCH v5 06/12] S.A.R.A.: WX protection
  2019-07-06 19:28   ` Al Viro
@ 2019-07-07 15:49     ` Salvatore Mesoraca
  2019-07-09  4:51       ` Kees Cook
  0 siblings, 1 reply; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-07 15:49 UTC (permalink / raw)
  To: Al Viro
  Cc: linux-kernel, Kernel Hardening, linux-mm, linux-security-module,
	Brad Spengler, Casey Schaufler, Christoph Hellwig, Jann Horn,
	Kees Cook, PaX Team, Serge E. Hallyn, Thomas Gleixner,
	James Morris

Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> On Sat, Jul 06, 2019 at 12:54:47PM +0200, Salvatore Mesoraca wrote:
>
> > +#define sara_warn_or_return(err, msg) do {           \
> > +     if ((sara_wxp_flags & SARA_WXP_VERBOSE))        \
> > +             pr_wxp(msg);                            \
> > +     if (!(sara_wxp_flags & SARA_WXP_COMPLAIN))      \
> > +             return -err;                            \
> > +} while (0)
> > +
> > +#define sara_warn_or_goto(label, msg) do {           \
> > +     if ((sara_wxp_flags & SARA_WXP_VERBOSE))        \
> > +             pr_wxp(msg);                            \
> > +     if (!(sara_wxp_flags & SARA_WXP_COMPLAIN))      \
> > +             goto label;                             \
> > +} while (0)
>
> No.  This kind of "style" has no place in the kernel.
>
> Don't hide control flow.  It's nasty enough to reviewers,
> but it's pure hell on anyone who strays into your code while
> chasing a bug or doing general code audit.  In effect, you
> are creating your oh-so-private C dialect and assuming that
> everyone who ever looks at your code will start with learning
> that *AND* incorporating it into their mental C parser.
> I'm sorry, but you are not that important.
>
> If it looks like a function call, a casual reader will assume
> that this is exactly what it is.  And when one is scanning
> through a function (e.g. to tell if handling of some kind
> of refcounts is correct, with twentieth grep through the
> tree having brought something in your code into the view),
> the last thing one wants is to switch between the area-specific
> C dialects.  Simply because looking at yours is sandwiched
> between digging through some crap in drivers/target/ and that
> weird thing in kernel/tracing/, hopefully staying limited
> to 20 seconds of glancing through several functions in your
> code.
>
> Don't Do That.  Really.

I understand your concerns.
The first version of SARA didn't use these macros,
they were added because I was asked[1] to do so.

I have absolutely no problems in reverting this change.
I just want to make sure that there is agreement on this matter.
Maybe Kees can clarify his stance.

Thank you for your suggestions.

[1] https://lkml.kernel.org/r/CAGXu5jJuQx2qOt_aDqDQDcqGOZ5kmr5rQ9Zjv=MRRCJ65ERfGw@mail.gmail.com

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

* Re: [PATCH v5 04/12] S.A.R.A.: generic DFA for string matching
  2019-07-06 18:32   ` Jann Horn
@ 2019-07-07 16:01     ` Salvatore Mesoraca
  2019-07-08 17:37       ` Jann Horn
  2019-10-06 16:49       ` Salvatore Mesoraca
  0 siblings, 2 replies; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-07 16:01 UTC (permalink / raw)
  To: Jann Horn
  Cc: kernel list, Kernel Hardening, Linux-MM, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, Kees Cook, PaX Team, Serge E. Hallyn,
	Thomas Gleixner, James Morris, John Johansen

Jann Horn <jannh@google.com> wrote:
>
> On Sat, Jul 6, 2019 at 12:55 PM Salvatore Mesoraca
> <s.mesoraca16@gmail.com> wrote:
> > Creation of a generic Discrete Finite Automata implementation
> > for string matching. The transition tables have to be produced
> > in user-space.
> > This allows us to possibly support advanced string matching
> > patterns like regular expressions, but they need to be supported
> > by user-space tools.
>
> AppArmor already has a DFA implementation that takes a DFA machine
> from userspace and runs it against file paths; see e.g.
> aa_dfa_match(). Did you look into whether you could move their DFA to
> some place like lib/ and reuse it instead of adding yet another
> generic rule interface to the kernel?

Yes, using AppArmor DFA cloud be a possibility.
Though, I didn't know how AppArmor's maintainers feel about this.
I thought that was easier to just implement my own.
Anyway I understand that re-using that code would be the optimal solution.
I'm adding in CC AppArmor's maintainers, let's see what they think about this.

> > +++ b/security/sara/dfa.c
> > @@ -0,0 +1,335 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +/*
> > + * S.A.R.A. Linux Security Module
> > + *
> > + * Copyright (C) 2017 Salvatore Mesoraca <s.mesoraca16@gmail.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2, as
> > + * published by the Free Software Foundation.
>
> Throughout the series, you are adding files that both add an SPDX
> identifier and have a description of the license in the comment block
> at the top. The SPDX identifier already identifies the license.

I added the license description because I thought it was required anyway.
IANAL, if you tell me that SPDX it's enough I'll remove the description.

Thank you for your comments.

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

* Re: [PATCH v5 11/12] S.A.R.A.: /proc/*/mem write limitation
  2019-07-06 18:20   ` Jann Horn
@ 2019-07-07 16:15     ` Salvatore Mesoraca
  0 siblings, 0 replies; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-07-07 16:15 UTC (permalink / raw)
  To: Jann Horn
  Cc: kernel list, Kernel Hardening, Linux-MM, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, Kees Cook, PaX Team, Serge E. Hallyn,
	Thomas Gleixner, James Morris

Jann Horn <jannh@google.com> wrote:
>
> On Sat, Jul 6, 2019 at 12:55 PM Salvatore Mesoraca
> <s.mesoraca16@gmail.com> wrote:
> > Prevent a task from opening, in "write" mode, any /proc/*/mem
> > file that operates on the task's mm.
> > A process could use it to overwrite read-only memory, bypassing
> > S.A.R.A. restrictions.
> [...]
> > +static void sara_task_to_inode(struct task_struct *t, struct inode *i)
> > +{
> > +       get_sara_inode_task(i) = t;
>
> This looks bogus. Nothing is actually holding a reference to `t` here, right?

I think you are right, I should probably store the PID here.

> > +}
> > +
> >  static struct security_hook_list data_hooks[] __lsm_ro_after_init = {
> >         LSM_HOOK_INIT(cred_prepare, sara_cred_prepare),
> >         LSM_HOOK_INIT(cred_transfer, sara_cred_transfer),
> >         LSM_HOOK_INIT(shm_alloc_security, sara_shm_alloc_security),
> > +       LSM_HOOK_INIT(task_to_inode, sara_task_to_inode),
> >  };
> [...]
> > +static int sara_file_open(struct file *file)
> > +{
> > +       struct task_struct *t;
> > +       struct mm_struct *mm;
> > +       u16 sara_wxp_flags = get_current_sara_wxp_flags();
> > +
> > +       /*
> > +        * Prevent write access to /proc/.../mem
> > +        * if it operates on the mm_struct of the
> > +        * current process: it could be used to
> > +        * bypass W^X.
> > +        */
> > +
> > +       if (!sara_enabled ||
> > +           !wxprot_enabled ||
> > +           !(sara_wxp_flags & SARA_WXP_WXORX) ||
> > +           !(file->f_mode & FMODE_WRITE))
> > +               return 0;
> > +
> > +       t = get_sara_inode_task(file_inode(file));
> > +       if (unlikely(t != NULL &&
> > +                    strcmp(file->f_path.dentry->d_name.name,
> > +                           "mem") == 0)) {
>
> This should probably at least have a READ_ONCE() somewhere in case the
> file concurrently gets renamed?

My understanding here is that /proc/$pid/mem files cannot be renamed.
t != NULL implies we are in procfs.
Under these assumptions I think that that code is fine.
Am I wrong?

> > +               get_task_struct(t);
> > +               mm = get_task_mm(t);
> > +               put_task_struct(t);
>
> Getting and dropping a reference to the task_struct here is completely
> useless. Either you have a reference, in which case you don't need to
> take another one, or you don't have a reference, in which case you
> also can't take one.

Absolutely agree.

> > +               if (unlikely(mm == current->mm))
> > +                       sara_warn_or_goto(error,
> > +                                         "write access to /proc/*/mem");
>
> Why is the current process so special that it must be protected more
> than other processes? Is the idea here to rely on other protections to
> protect all other tasks? This should probably come with a comment that
> explains this choice.

Yes, I should have spent some more words here.
Access to /proc/$pid/mem from other processes is already regulated by
security_ptrace_access_check (i.e. Yama).
Unfortunately, that hook is ignored when "mm == current->mm".
It seems that there is some user-space software that relies on /proc/self/mem
being writable (cfr. commit f511c0b17b08).

Thank you for your suggestions.

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

* RE: [PATCH v5 06/12] S.A.R.A.: WX protection
  2019-07-06 10:54 ` [PATCH v5 06/12] S.A.R.A.: WX protection Salvatore Mesoraca
  2019-07-06 15:38   ` Randy Dunlap
  2019-07-06 19:28   ` Al Viro
@ 2019-07-08 12:42   ` David Laight
  2 siblings, 0 replies; 35+ messages in thread
From: David Laight @ 2019-07-08 12:42 UTC (permalink / raw)
  To: Salvatore Mesoraca, linux-kernel
  Cc: kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, James Morris, Jann Horn, Kees Cook, PaX Team,
	Serge E. Hallyn, Thomas Gleixner

From: Salvatore Mesoraca
> Sent: 06 July 2019 11:55
...
> Executable MMAP prevention works by preventing any new executable
> allocation after the dynamic libraries have been loaded. It works under the
> assumption that, when the dynamic libraries have been finished loading, the
> RELRO section will be marked read only.

What about writing to the file of a dynamic library after it is loaded
but before it is faulted it (or after evicting it from the I$).

...
> +#define find_relro_section(ELFH, ELFP, FILE, RELRO, FOUND) do {		\
> +	unsigned long i;						\
> +	int _tmp;							\
> +	loff_t _pos = 0;						\
> +	if (ELFH.e_type == ET_DYN || ELFH.e_type == ET_EXEC) {		\
> +		for (i = 0; i < ELFH.e_phnum; ++i) {			\
> +			_pos = ELFH.e_phoff + i*sizeof(ELFP);		\
> +			_tmp = kernel_read(FILE, &ELFP, sizeof(ELFP),	\
> +					   &_pos);			\
> +			if (_tmp != sizeof(ELFP))			\
> +				break;					\
> +			if (ELFP.p_type == PT_GNU_RELRO) {		\
> +				RELRO = ELFP.p_offset >> PAGE_SHIFT;	\
> +				FOUND = true;				\
> +				break;					\
> +			}						\
> +		}							\
> +	}								\
> +} while (0)

This is big for a #define.
Since it contains kernel_read() it can't really matter if it is
a real function.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)


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

* Re: [PATCH v5 04/12] S.A.R.A.: generic DFA for string matching
  2019-07-07 16:01     ` Salvatore Mesoraca
@ 2019-07-08 17:37       ` Jann Horn
  2019-10-06 16:49       ` Salvatore Mesoraca
  1 sibling, 0 replies; 35+ messages in thread
From: Jann Horn @ 2019-07-08 17:37 UTC (permalink / raw)
  To: Salvatore Mesoraca
  Cc: kernel list, Kernel Hardening, Linux-MM, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, Kees Cook, PaX Team, Serge E. Hallyn,
	Thomas Gleixner, James Morris, John Johansen

On Sun, Jul 7, 2019 at 6:01 PM Salvatore Mesoraca
<s.mesoraca16@gmail.com> wrote:
> Jann Horn <jannh@google.com> wrote:
> > Throughout the series, you are adding files that both add an SPDX
> > identifier and have a description of the license in the comment block
> > at the top. The SPDX identifier already identifies the license.
>
> I added the license description because I thought it was required anyway.
> IANAL, if you tell me that SPDX it's enough I'll remove the description.

IANAL too, but Documentation/process/license-rules.rst says:

====
The common way of expressing the license of a source file is to add the
matching boilerplate text into the top comment of the file.  Due to
formatting, typos etc. these "boilerplates" are hard to validate for
tools which are used in the context of license compliance.

An alternative to boilerplate text is the use of Software Package Data
Exchange (SPDX) license identifiers in each source file.  SPDX license
identifiers are machine parsable and precise shorthands for the license
under which the content of the file is contributed.  SPDX license
identifiers are managed by the SPDX Workgroup at the Linux Foundation and
have been agreed on by partners throughout the industry, tool vendors, and
legal teams.  For further information see https://spdx.org/

The Linux kernel requires the precise SPDX identifier in all source files.
The valid identifiers used in the kernel are explained in the section
`License identifiers`_ and have been retrieved from the official SPDX
license list at https://spdx.org/licenses/ along with the license texts.
====

and there have been lots of conversion patches to replace license
boilerplate headers with SPDX identifiers, see e.g. all the "treewide:
Replace GPLv2 boilerplate/reference with SPDX" patches.

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

* Re: [PATCH v5 06/12] S.A.R.A.: WX protection
  2019-07-07 15:49     ` Salvatore Mesoraca
@ 2019-07-09  4:51       ` Kees Cook
  0 siblings, 0 replies; 35+ messages in thread
From: Kees Cook @ 2019-07-09  4:51 UTC (permalink / raw)
  To: Salvatore Mesoraca
  Cc: Al Viro, linux-kernel, Kernel Hardening, linux-mm,
	linux-security-module, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, Jann Horn, PaX Team, Serge E. Hallyn,
	Thomas Gleixner, James Morris

On Sun, Jul 07, 2019 at 05:49:35PM +0200, Salvatore Mesoraca wrote:
> Al Viro <viro@zeniv.linux.org.uk> wrote:
> >
> > On Sat, Jul 06, 2019 at 12:54:47PM +0200, Salvatore Mesoraca wrote:
> >
> > > +#define sara_warn_or_return(err, msg) do {           \
> > > +     if ((sara_wxp_flags & SARA_WXP_VERBOSE))        \
> > > +             pr_wxp(msg);                            \
> > > +     if (!(sara_wxp_flags & SARA_WXP_COMPLAIN))      \
> > > +             return -err;                            \
> > > +} while (0)
> > > +
> > > +#define sara_warn_or_goto(label, msg) do {           \
> > > +     if ((sara_wxp_flags & SARA_WXP_VERBOSE))        \
> > > +             pr_wxp(msg);                            \
> > > +     if (!(sara_wxp_flags & SARA_WXP_COMPLAIN))      \
> > > +             goto label;                             \
> > > +} while (0)
> >
> > No.  This kind of "style" has no place in the kernel.
> >
> > Don't hide control flow.  It's nasty enough to reviewers,
> > but it's pure hell on anyone who strays into your code while
> > chasing a bug or doing general code audit.  In effect, you
> > are creating your oh-so-private C dialect and assuming that
> > everyone who ever looks at your code will start with learning
> > that *AND* incorporating it into their mental C parser.
> > I'm sorry, but you are not that important.
> >
> > If it looks like a function call, a casual reader will assume
> > that this is exactly what it is.  And when one is scanning
> > through a function (e.g. to tell if handling of some kind
> > of refcounts is correct, with twentieth grep through the
> > tree having brought something in your code into the view),
> > the last thing one wants is to switch between the area-specific
> > C dialects.  Simply because looking at yours is sandwiched
> > between digging through some crap in drivers/target/ and that
> > weird thing in kernel/tracing/, hopefully staying limited
> > to 20 seconds of glancing through several functions in your
> > code.
> >
> > Don't Do That.  Really.
> 
> I understand your concerns.
> The first version of SARA didn't use these macros,
> they were added because I was asked[1] to do so.
> 
> I have absolutely no problems in reverting this change.
> I just want to make sure that there is agreement on this matter.
> Maybe Kees can clarify his stance.
> 
> Thank you for your suggestions.
> 
> [1] https://lkml.kernel.org/r/CAGXu5jJuQx2qOt_aDqDQDcqGOZ5kmr5rQ9Zjv=MRRCJ65ERfGw@mail.gmail.com

I just didn't like how difficult it was to review the repeated checking.
I thought then (and still think now) it's worth the unusual style to
improve the immediate readability. Obviously Al disagrees. I'm not
against dropping my suggestion; it's just a pain to review it and it
seems like an area that would be highly prone to subtle typos. Perhaps
some middle ground:

#define sara_warn(msg)	({				\
		if ((sara_wxp_flags & SARA_WXP_VERBOSE))	\
			pr_wxp(msg);				\
		!(sara_wxp_flags & SARA_WXP_COMPLAIN);		\
	})

...

	if (unlikely(sara_wxp_flags & SARA_WXP_WXORX &&
		     vm_flags & VM_WRITE &&
		     vm_flags & VM_EXEC &&
		     sara_warn("W^X")))
		return -EPERM;

that way the copy/pasting isn't present but the control flow is visible?

-- 
Kees Cook

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

* Re: [PATCH v5 03/12] S.A.R.A.: cred blob management
  2019-07-06 10:54 ` [PATCH v5 03/12] S.A.R.A.: cred blob management Salvatore Mesoraca
@ 2019-07-12 23:35   ` James Morris
  0 siblings, 0 replies; 35+ messages in thread
From: James Morris @ 2019-07-12 23:35 UTC (permalink / raw)
  To: Salvatore Mesoraca
  Cc: linux-kernel, kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, Jann Horn, Kees Cook, PaX Team,
	Serge E. Hallyn, Thomas Gleixner

On Sat, 6 Jul 2019, Salvatore Mesoraca wrote:

> Creation of the S.A.R.A. cred blob management "API".
> In order to allow S.A.R.A. to be stackable with other LSMs, it doesn't use
> the "security" field of struct cred, instead it uses an ad hoc field named
> security_sara.
> This solution is probably not acceptable for upstream, so this part will
> be modified as soon as the LSM stackable cred blob management will be
> available.

This description is out of date wrt cred blob sharing.

> +	if (sara_data_init()) {
> +		pr_crit("impossible to initialize creds.\n");
> +		goto error;
> +	}
> +

> +int __init sara_data_init(void)
> +{
> +	security_add_hooks(data_hooks, ARRAY_SIZE(data_hooks), "sara");
> +	return 0;
> +}

This can't fail so make it return void and simplify the caller.



-- 
James Morris
<jmorris@namei.org>


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

* Re: [PATCH v5 01/12] S.A.R.A.: add documentation
  2019-07-06 10:54 ` [PATCH v5 01/12] S.A.R.A.: add documentation Salvatore Mesoraca
  2019-07-06 17:14   ` Randy Dunlap
@ 2019-07-13  0:14   ` James Morris
  1 sibling, 0 replies; 35+ messages in thread
From: James Morris @ 2019-07-13  0:14 UTC (permalink / raw)
  To: Salvatore Mesoraca
  Cc: linux-kernel, kernel-hardening, linux-mm, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, Jann Horn, Kees Cook, PaX Team,
	Serge E. Hallyn, Thomas Gleixner

On Sat, 6 Jul 2019, Salvatore Mesoraca wrote:

> Adding documentation for S.A.R.A. LSM.

It would be good if you could add an operational overview to help people 
understand how it works in practice, e.g. setting policies for binaries 
via sara-xattr and global config via saractl (IIUC). It's difficult to 
understand if you have to visit several links to piece things together.

> +S.A.R.A.'s Submodules
> +=====================
> +
> +WX Protection
> +-------------
> +WX Protection aims to improve user-space programs security by applying:
> +
> +- `W^X enforcement`_
> +- `W!->X (once writable never executable) mprotect restriction`_
> +- `Executable MMAP prevention`_
> +
> +All of the above features can be enabled or disabled both system wide
> +or on a per executable basis through the use of configuration files managed by
> +`saractl` [2]_.

How complete is the WX protection provided by this module? How does it 
compare with other implementations (such as PaX's restricted mprotect).

> +Parts of WX Protection are inspired by some of the features available in PaX.

Some critical aspects are copied (e.g. trampoline emulation), so it's 
more than just inspired. Could you include more information in the 
description about what's been ported from PaX to SARA?
	

-- 
James Morris
<jmorris@namei.org>


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

* Re: [PATCH v5 04/12] S.A.R.A.: generic DFA for string matching
  2019-07-07 16:01     ` Salvatore Mesoraca
  2019-07-08 17:37       ` Jann Horn
@ 2019-10-06 16:49       ` Salvatore Mesoraca
  2019-10-07 12:40         ` Jann Horn
  1 sibling, 1 reply; 35+ messages in thread
From: Salvatore Mesoraca @ 2019-10-06 16:49 UTC (permalink / raw)
  To: Jann Horn
  Cc: kernel list, Kernel Hardening, Linux-MM, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, Kees Cook, PaX Team, Serge E. Hallyn,
	Thomas Gleixner, James Morris, John Johansen

Salvatore Mesoraca <s.mesoraca16@gmail.com> wrote:
>
> Jann Horn <jannh@google.com> wrote:
> >
> > On Sat, Jul 6, 2019 at 12:55 PM Salvatore Mesoraca
> > <s.mesoraca16@gmail.com> wrote:
> > > Creation of a generic Discrete Finite Automata implementation
> > > for string matching. The transition tables have to be produced
> > > in user-space.
> > > This allows us to possibly support advanced string matching
> > > patterns like regular expressions, but they need to be supported
> > > by user-space tools.
> >
> > AppArmor already has a DFA implementation that takes a DFA machine
> > from userspace and runs it against file paths; see e.g.
> > aa_dfa_match(). Did you look into whether you could move their DFA to
> > some place like lib/ and reuse it instead of adding yet another
> > generic rule interface to the kernel?
>
> Yes, using AppArmor DFA cloud be a possibility.
> Though, I didn't know how AppArmor's maintainers feel about this.
> I thought that was easier to just implement my own.
> Anyway I understand that re-using that code would be the optimal solution.
> I'm adding in CC AppArmor's maintainers, let's see what they think about this.

I don't want this to prevent SARA from being up-streamed.
Do you think that having another DFA here could be acceptable anyway?
Would it be better if I just drop the DFA an go back to simple string
matching to speed up things?

Thank you,

Salvatore

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

* Re: [PATCH v5 04/12] S.A.R.A.: generic DFA for string matching
  2019-10-06 16:49       ` Salvatore Mesoraca
@ 2019-10-07 12:40         ` Jann Horn
  0 siblings, 0 replies; 35+ messages in thread
From: Jann Horn @ 2019-10-07 12:40 UTC (permalink / raw)
  To: Salvatore Mesoraca
  Cc: kernel list, Kernel Hardening, Linux-MM, linux-security-module,
	Alexander Viro, Brad Spengler, Casey Schaufler,
	Christoph Hellwig, Kees Cook, PaX Team, Serge E. Hallyn,
	Thomas Gleixner, James Morris, John Johansen

On Sun, Oct 6, 2019 at 6:49 PM Salvatore Mesoraca
<s.mesoraca16@gmail.com> wrote:
> Salvatore Mesoraca <s.mesoraca16@gmail.com> wrote:
> > Jann Horn <jannh@google.com> wrote:
> > > On Sat, Jul 6, 2019 at 12:55 PM Salvatore Mesoraca
> > > <s.mesoraca16@gmail.com> wrote:
> > > > Creation of a generic Discrete Finite Automata implementation
> > > > for string matching. The transition tables have to be produced
> > > > in user-space.
> > > > This allows us to possibly support advanced string matching
> > > > patterns like regular expressions, but they need to be supported
> > > > by user-space tools.
> > >
> > > AppArmor already has a DFA implementation that takes a DFA machine
> > > from userspace and runs it against file paths; see e.g.
> > > aa_dfa_match(). Did you look into whether you could move their DFA to
> > > some place like lib/ and reuse it instead of adding yet another
> > > generic rule interface to the kernel?
> >
> > Yes, using AppArmor DFA cloud be a possibility.
> > Though, I didn't know how AppArmor's maintainers feel about this.
> > I thought that was easier to just implement my own.
> > Anyway I understand that re-using that code would be the optimal solution.
> > I'm adding in CC AppArmor's maintainers, let's see what they think about this.
>
> I don't want this to prevent SARA from being up-streamed.
> Do you think that having another DFA here could be acceptable anyway?
> Would it be better if I just drop the DFA an go back to simple string
> matching to speed up things?

While I think that it would be nicer not to have yet another
implementation of the same thing, I don't feel strongly about it.

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

end of thread, back to index

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-06 10:54 [PATCH v5 00/12] S.A.R.A. a new stacked LSM Salvatore Mesoraca
2019-07-06 10:54 ` [PATCH v5 01/12] S.A.R.A.: add documentation Salvatore Mesoraca
2019-07-06 17:14   ` Randy Dunlap
2019-07-06 17:32     ` Salvatore Mesoraca
2019-07-13  0:14   ` James Morris
2019-07-06 10:54 ` [PATCH v5 02/12] S.A.R.A.: create framework Salvatore Mesoraca
2019-07-06 15:29   ` Randy Dunlap
2019-07-06 10:54 ` [PATCH v5 03/12] S.A.R.A.: cred blob management Salvatore Mesoraca
2019-07-12 23:35   ` James Morris
2019-07-06 10:54 ` [PATCH v5 04/12] S.A.R.A.: generic DFA for string matching Salvatore Mesoraca
2019-07-06 18:32   ` Jann Horn
2019-07-07 16:01     ` Salvatore Mesoraca
2019-07-08 17:37       ` Jann Horn
2019-10-06 16:49       ` Salvatore Mesoraca
2019-10-07 12:40         ` Jann Horn
2019-07-06 10:54 ` [PATCH v5 05/12] LSM: creation of "check_vmflags" LSM hook Salvatore Mesoraca
2019-07-06 10:54 ` [PATCH v5 06/12] S.A.R.A.: WX protection Salvatore Mesoraca
2019-07-06 15:38   ` Randy Dunlap
2019-07-06 19:28   ` Al Viro
2019-07-07 15:49     ` Salvatore Mesoraca
2019-07-09  4:51       ` Kees Cook
2019-07-08 12:42   ` David Laight
2019-07-06 10:54 ` [PATCH v5 07/12] LSM: creation of "pagefault_handler" LSM hook Salvatore Mesoraca
2019-07-06 10:54 ` [PATCH v5 08/12] S.A.R.A.: trampoline emulation Salvatore Mesoraca
2019-07-06 15:31   ` Randy Dunlap
2019-07-06 10:54 ` [PATCH v5 09/12] S.A.R.A.: WX protection procattr interface Salvatore Mesoraca
2019-07-06 10:54 ` [PATCH v5 10/12] S.A.R.A.: XATTRs support Salvatore Mesoraca
2019-07-06 10:54 ` [PATCH v5 11/12] S.A.R.A.: /proc/*/mem write limitation Salvatore Mesoraca
2019-07-06 18:20   ` Jann Horn
2019-07-07 16:15     ` Salvatore Mesoraca
2019-07-06 10:54 ` [PATCH v5 12/12] MAINTAINERS: take maintainership for S.A.R.A Salvatore Mesoraca
2019-07-06 14:33 ` [PATCH v5 00/12] S.A.R.A. a new stacked LSM Jordan Glover
2019-07-06 15:02   ` Salvatore Mesoraca
2019-07-07  1:16 ` James Morris
2019-07-07 15:40   ` Salvatore Mesoraca

Linux-Security-Module Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-security-module/0 linux-security-module/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-security-module linux-security-module/ https://lore.kernel.org/linux-security-module \
		linux-security-module@vger.kernel.org
	public-inbox-index linux-security-module

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-security-module


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git