Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1663977 > unrolled thread

[PATCH 00/11] S.A.R.A. a new stacked LSM

Started bySalvatore Mesoraca <s.mesoraca16@gmail.com>
First post2017-06-12 19:00 +0200
Last post2017-06-12 19:10 +0200
Articles 20 on this page of 25 — 7 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 00/11] S.A.R.A. a new stacked LSM Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-12 19:00 +0200
    [PATCH 08/11] Creation of "pagefault_handler_x86" LSM hook Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-12 19:00 +0200
      Re: [PATCH 08/11] Creation of "pagefault_handler_x86" LSM hook Thomas Gleixner <tglx@linutronix.de> - 2017-06-12 19:40 +0200
        Re: [PATCH 08/11] Creation of "pagefault_handler_x86" LSM hook Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-13 09:50 +0200
    [PATCH 10/11] Allowing for stacking procattr support in S.A.R.A. Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-12 19:00 +0200
    [PATCH 01/11] S.A.R.A. Documentation Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-12 19:00 +0200
      Re: [kernel-hardening] [PATCH 01/11] S.A.R.A. Documentation Jann Horn <jannh@google.com> - 2017-06-12 19:50 +0200
        Re: [kernel-hardening] [PATCH 01/11] S.A.R.A. Documentation Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-13 09:50 +0200
    [PATCH 09/11] Trampoline emulation Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-12 19:00 +0200
    [PATCH 04/11] S.A.R.A. USB Filtering Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-12 19:00 +0200
    [PATCH 05/11] Creation of "check_vmflags" LSM hook Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-12 19:00 +0200
      Re: [PATCH 05/11] Creation of "check_vmflags" LSM hook Casey Schaufler <casey@schaufler-ca.com> - 2017-06-12 23:40 +0200
        Re: [PATCH 05/11] Creation of "check_vmflags" LSM hook Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-13 10:00 +0200
      Re: [PATCH 05/11] Creation of "check_vmflags" LSM hook Christoph Hellwig <hch@infradead.org> - 2017-06-13 08:40 +0200
        Re: [PATCH 05/11] Creation of "check_vmflags" LSM hook Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-13 10:00 +0200
    [PATCH 02/11] S.A.R.A. framework creation Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-12 19:00 +0200
    [PATCH 03/11] Creation of "usb_device_auth" LSM hook Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-12 19:00 +0200
      Re: [PATCH 03/11] Creation of "usb_device_auth" LSM hook Krzysztof Opasiak <k.opasiak@samsung.com> - 2017-06-12 19:40 +0200
        Re: [PATCH 03/11] Creation of "usb_device_auth" LSM hook Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-13 09:50 +0200
      Re: [PATCH 03/11] Creation of "usb_device_auth" LSM hook Greg Kroah-Hartman <gregkh@linuxfoundation.org> - 2017-06-12 21:40 +0200
        Re: [PATCH 03/11] Creation of "usb_device_auth" LSM hook Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-13 10:00 +0200
      Re: [PATCH 03/11] Creation of "usb_device_auth" LSM hook Casey Schaufler <casey@schaufler-ca.com> - 2017-06-12 23:40 +0200
        Re: [PATCH 03/11] Creation of "usb_device_auth" LSM hook Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-13 10:00 +0200
    [PATCH 07/11] S.A.R.A. WX Protection Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-12 19:00 +0200
    [PATCH 06/11] S.A.R.A. cred blob management Salvatore Mesoraca <s.mesoraca16@gmail.com> - 2017-06-12 19:10 +0200

Page 1 of 2  [1] 2  Next page →


#1663977 — [PATCH 00/11] S.A.R.A. a new stacked LSM

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-12 19:00 +0200
Subject[PATCH 00/11] S.A.R.A. a new stacked LSM
Message-ID<tRAR3-4Dh-3@gated-at.bofh.it>
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.

S.A.R.A. submodules introduced in this patchset are: USB Filtering and
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.

USB Filtering aims to provide a mechanism to decide which USB devices
should be authorized to connect to the system and which shouldn't. The main
goal is to narrow the attack surface for custom USB devices designed to
exploit vulnerabilities found in some USB device drivers.
Via configuration it's possible to allow or to deny authorization, based
on one or more of: Vendor ID, Product ID, bus name and port number. There
is also limited support for wildcards.
Depending on the configuration, it can work both as a white list or as a
black list.
With the help of "saractl" it's also possible to completely disable new
USB devices when the screen is "locked".
The original idea is inspired by the Grsecurity "Deny USB" feature.

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.

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

[1] https://github.com/smeso/saractl
[2] https://github.com/smeso/sara-test

Salvatore Mesoraca (11):
  S.A.R.A. Documentation
  S.A.R.A. framework creation
  Creation of "usb_device_auth" LSM hook
  S.A.R.A. USB Filtering
  Creation of "check_vmflags" LSM hook
  S.A.R.A. cred blob management
  S.A.R.A. WX Protection
  Creation of "pagefault_handler_x86" LSM hook
  Trampoline emulation
  Allowing for stacking procattr support in S.A.R.A.
  S.A.R.A. WX Protection procattr interface

 Documentation/admin-guide/kernel-parameters.txt |  40 ++
 Documentation/security/00-INDEX                 |   2 +
 Documentation/security/SARA.rst                 | 192 +++++
 arch/x86/mm/fault.c                             |   6 +
 drivers/usb/core/hub.c                          |   4 +
 drivers/usb/core/sysfs.c                        |   6 +-
 fs/proc/base.c                                  |  38 +
 include/linux/cred.h                            |   3 +
 include/linux/lsm_hooks.h                       |  26 +
 include/linux/security.h                        |  24 +
 mm/mmap.c                                       |   9 +
 security/Kconfig                                |   1 +
 security/Makefile                               |   2 +
 security/sara/Kconfig                           | 175 +++++
 security/sara/Makefile                          |   5 +
 security/sara/include/sara.h                    |  29 +
 security/sara/include/sara_data.h               |  47 ++
 security/sara/include/securityfs.h              |  59 ++
 security/sara/include/trampolines.h             | 171 +++++
 security/sara/include/usb_filtering.h           |  27 +
 security/sara/include/utils.h                   |  69 ++
 security/sara/include/wxprot.h                  |  27 +
 security/sara/main.c                            | 113 +++
 security/sara/sara_data.c                       |  79 +++
 security/sara/securityfs.c                      | 558 +++++++++++++++
 security/sara/usb_filtering.c                   | 410 +++++++++++
 security/sara/utils.c                           | 151 ++++
 security/sara/wxprot.c                          | 902 ++++++++++++++++++++++++
 security/security.c                             |  42 +-
 29 files changed, 3214 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/security/SARA.rst
 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/sara_data.h
 create mode 100644 security/sara/include/securityfs.h
 create mode 100644 security/sara/include/trampolines.h
 create mode 100644 security/sara/include/usb_filtering.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/usb_filtering.c
 create mode 100644 security/sara/utils.c
 create mode 100644 security/sara/wxprot.c

-- 
1.9.1

[toc] | [next] | [standalone]


#1663980 — [PATCH 08/11] Creation of "pagefault_handler_x86" LSM hook

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-12 19:00 +0200
Subject[PATCH 08/11] Creation of "pagefault_handler_x86" LSM hook
Message-ID<tRAR3-4Dh-11@gated-at.bofh.it>
In reply to#1663977
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.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
Cc: x86@kernel.org
Cc: Ingo Molnar <mingo@redhat.com>
---
 arch/x86/mm/fault.c       |  6 ++++++
 include/linux/lsm_hooks.h |  9 +++++++++
 include/linux/security.h  | 11 +++++++++++
 security/security.c       | 11 +++++++++++
 4 files changed, 37 insertions(+)

diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 8ad91a0..b75b81a 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -15,6 +15,7 @@
 #include <linux/prefetch.h>		/* prefetchw			*/
 #include <linux/context_tracking.h>	/* exception_enter(), ...	*/
 #include <linux/uaccess.h>		/* faulthandler_disabled()	*/
+#include <linux/security.h>		/* security_pagefault_handler	*/
 
 #include <asm/cpufeature.h>		/* boot_cpu_has, ...		*/
 #include <asm/traps.h>			/* dotraplinkage, ...		*/
@@ -1358,6 +1359,11 @@ static inline bool smap_violation(int error_code, struct pt_regs *regs)
 			local_irq_enable();
 	}
 
+	if (unlikely(security_pagefault_handler_x86(regs,
+						    error_code,
+						    address)))
+		return;
+
 	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
 
 	if (error_code & PF_WRITE)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 6934cc5..a42c2f8 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -487,6 +487,11 @@
  *	Check if the requested @vmflags are allowed.
  *	@vmflags contains requested the vmflags.
  *	Return 0 if the operation is allowed to continue.
+ * @pagefault_handler_x86:
+ *	Handle pagefaults on x86.
+ *	@regs contains process' registers.
+ *	@error_code contains error code for the pagefault.
+ *	@address contains the address that caused the pagefault.
  * @file_lock:
  *	Check permission before performing file locking operations.
  *	Note: this hook mediates both flock and fcntl style locks.
@@ -1487,6 +1492,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_x86)(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);
@@ -1759,6 +1767,7 @@ struct security_hook_heads {
 	struct list_head mmap_file;
 	struct list_head file_mprotect;
 	struct list_head check_vmflags;
+	struct list_head pagefault_handler_x86;
 	struct list_head file_lock;
 	struct list_head file_fcntl;
 	struct list_head file_set_fowner;
diff --git a/include/linux/security.h b/include/linux/security.h
index 67e33b6..bc38c83 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -303,6 +303,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_x86(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);
@@ -836,6 +839,14 @@ static inline int security_check_vmflags(vm_flags_t vmflags)
 	return 0;
 }
 
+static inline int __maybe_unused security_pagefault_handler_x86(
+						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 25d58f0..cf15686 100644
--- a/security/security.c
+++ b/security/security.c
@@ -910,6 +910,17 @@ int security_check_vmflags(vm_flags_t vmflags)
 	return call_int_hook(check_vmflags, 0, vmflags);
 }
 
+int __maybe_unused security_pagefault_handler_x86(struct pt_regs *regs,
+						  unsigned long error_code,
+						  unsigned long address)
+{
+	return call_int_hook(pagefault_handler_x86,
+			     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

[toc] | [prev] | [next] | [standalone]


#1664126 — Re: [PATCH 08/11] Creation of "pagefault_handler_x86" LSM hook

FromThomas Gleixner <tglx@linutronix.de>
Date2017-06-12 19:40 +0200
SubjectRe: [PATCH 08/11] Creation of "pagefault_handler_x86" LSM hook
Message-ID<tRBtN-56r-39@gated-at.bofh.it>
In reply to#1663980
On Mon, 12 Jun 2017, Salvatore Mesoraca wrote:
> 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.

That explains, what you could do with it, but it completely lacks any
rationale WHY this is desired and good behaviour and how that is a security
feature.

Thanks,

	tglx

[toc] | [prev] | [next] | [standalone]


#1664564 — Re: [PATCH 08/11] Creation of "pagefault_handler_x86" LSM hook

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-13 09:50 +0200
SubjectRe: [PATCH 08/11] Creation of "pagefault_handler_x86" LSM hook
Message-ID<tROKm-59U-15@gated-at.bofh.it>
In reply to#1664126
2017-06-12 19:32 GMT+02:00 Thomas Gleixner <tglx@linutronix.de>:
> That explains, what you could do with it, but it completely lacks any
> rationale WHY this is desired and good behaviour and how that is a security
> feature.

You are right, I could have been more descriptive.
This is not a security feature "per se", it's a way to soften some
unwanted side-effects of restrictive security features.
In particular I'm trying to introduce a feature that will prevent
the runtime creation of executable code in user-space programs:
it's something like the PaX's MPROTECT feature.
This hook is used to implement what PaX call "trampoline
emulation" that, in practice, allow 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 "memory restriction" features to stay on even
  when they should be turned off. And, even if this emulation
  makes the feature less effective, it's still better than having
  it 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, the "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.

Thank your for taking the time to review this.

[toc] | [prev] | [next] | [standalone]


#1663982 — [PATCH 10/11] Allowing for stacking procattr support in S.A.R.A.

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-12 19:00 +0200
Subject[PATCH 10/11] Allowing for stacking procattr support in S.A.R.A.
Message-ID<tRAR4-4Dh-17@gated-at.bofh.it>
In reply to#1663977
This allow S.A.R.A. to use the procattr interface without interfering
with other LSMs.
This part should be reimplemented as soon as upstream procattr stacking
support is available.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 fs/proc/base.c      | 38 ++++++++++++++++++++++++++++++++++++++
 security/security.c | 20 ++++++++++++++++++--
 2 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index f1e1927..6d0fd1c 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2515,6 +2515,40 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
 	.llseek		= generic_file_llseek,
 };
 
+#ifdef CONFIG_SECURITY_SARA
+static const struct pid_entry sara_attr_dir_stuff[] = {
+	REG("wxprot", 0666, proc_pid_attr_operations),
+};
+
+static int proc_sara_attr_dir_readdir(struct file *file,
+				      struct dir_context *ctx)
+{
+	return proc_pident_readdir(file, ctx,
+				   sara_attr_dir_stuff,
+				   ARRAY_SIZE(sara_attr_dir_stuff));
+}
+
+static const struct file_operations proc_sara_attr_dir_ops = {
+	.read		= generic_read_dir,
+	.iterate_shared	= proc_sara_attr_dir_readdir,
+	.llseek		= generic_file_llseek,
+};
+
+static struct dentry *proc_sara_attr_dir_lookup(struct inode *dir,
+				struct dentry *dentry, unsigned int flags)
+{
+	return proc_pident_lookup(dir, dentry,
+				  sara_attr_dir_stuff,
+				  ARRAY_SIZE(sara_attr_dir_stuff));
+};
+
+static const struct inode_operations proc_sara_attr_dir_inode_ops = {
+	.lookup		= proc_sara_attr_dir_lookup,
+	.getattr	= pid_getattr,
+	.setattr	= proc_setattr,
+};
+#endif /* CONFIG_SECURITY_SARA */
+
 static const struct pid_entry attr_dir_stuff[] = {
 	REG("current",    S_IRUGO|S_IWUGO, proc_pid_attr_operations),
 	REG("prev",       S_IRUGO,	   proc_pid_attr_operations),
@@ -2522,6 +2556,10 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
 	REG("fscreate",   S_IRUGO|S_IWUGO, proc_pid_attr_operations),
 	REG("keycreate",  S_IRUGO|S_IWUGO, proc_pid_attr_operations),
 	REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
+#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/security.c b/security/security.c
index cf15686..6ca93c6 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1244,12 +1244,28 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
 
 int security_getprocattr(struct task_struct *p, char *name, char **value)
 {
-	return call_int_hook(getprocattr, -EINVAL, p, name, value);
+	struct security_hook_list *hp;
+	int rc;
+
+	list_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
+		rc = hp->hook.getprocattr(p, name, value);
+		if (rc != -EINVAL)
+			return rc;
+	}
+	return -EINVAL;
 }
 
 int security_setprocattr(const char *name, void *value, size_t size)
 {
-	return call_int_hook(setprocattr, -EINVAL, name, value, size);
+	struct security_hook_list *hp;
+	int rc;
+
+	list_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
+		rc = hp->hook.setprocattr(name, value, size);
+		if (rc != -EINVAL)
+			return rc;
+	}
+	return -EINVAL;
 }
 
 int security_netlink_send(struct sock *sk, struct sk_buff *skb)
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1663990 — [PATCH 01/11] S.A.R.A. Documentation

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-12 19:00 +0200
Subject[PATCH 01/11] S.A.R.A. Documentation
Message-ID<tRAR4-4Dh-35@gated-at.bofh.it>
In reply to#1663977
Adding documentation for S.A.R.A. LSM.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 Documentation/admin-guide/kernel-parameters.txt |  40 +++++
 Documentation/security/00-INDEX                 |   2 +
 Documentation/security/SARA.rst                 | 192 ++++++++++++++++++++++++
 3 files changed, 234 insertions(+)
 create mode 100644 Documentation/security/SARA.rst

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 0f5c3b4..f3ee12d 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -3702,6 +3702,46 @@
 			1 -- enable.
 			Default value is set via kernel config option.
 
+	sara=		[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_usb_filtering= [SARA]
+			Disable or enable S.A.R.A. USB Filtering at boot
+			time.
+			Format: { "0" | "1" }
+			See security/sara/Kconfig help text
+			0 -- disable.
+			1 -- enable.
+			Default value is 1.
+
+	sara_usb_filtering_default= [SARA]
+			Set S.A.R.A. USB Filtering default action.
+			Format: { "a" | "d" }
+			See security/sara/Kconfig help text
+			a -- allow.
+			d -- deny.
+			Default value is set via kernel config option.
+
+	sara_wxprot=	[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 1.
+
+	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]
diff --git a/Documentation/security/00-INDEX b/Documentation/security/00-INDEX
index 45c82fd..fe3583c 100644
--- a/Documentation/security/00-INDEX
+++ b/Documentation/security/00-INDEX
@@ -10,6 +10,8 @@ Yama.txt
 	- documentation on the Yama Linux Security Module.
 apparmor.txt
 	- documentation on the AppArmor security extension.
+SARA.rst
+	- documentation on the S.A.R.A. Linux Security Module.
 credentials.txt
 	- documentation about credentials in Linux.
 keys-ecryptfs.txt
diff --git a/Documentation/security/SARA.rst b/Documentation/security/SARA.rst
new file mode 100644
index 0000000..a1523033
--- /dev/null
+++ b/Documentation/security/SARA.rst
@@ -0,0 +1,192 @@
+========
+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 two main submodules:
+
+- USB Filtering
+- 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
+=====================
+
+USB Filtering
+-------------
+USB Filtering aims to provide a mechanism to decide which USB devices should
+be authorized to connect to the system and which shouldn't. The main goal
+is to narrow the attack surface for custom USB devices designed to exploit
+vulnerabilities found in some USB device drivers.
+
+Via configuration it's possible to allow or to deny authorization, based
+on one or more of: Vendor ID, Product ID, bus name and port number. There
+is also limited support for wildcards.
+Depending on the configuration, it can work both as a white list or as a black
+list.
+With the help of `saractl` [2]_ it's also possible to completely disable new
+USB devices when the screen is "locked".
+The original idea is inspired by the Grsecurity "Deny USB" feature.
+For further information on configuration file format and user-space utilities
+please look at the full documentation [1]_.
+
+
+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) runs on `x86_64` and
+`x86_32` (with PAE).
+
+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.
+
+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 in the current program.
+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 program 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.
+
+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.
+Given that it's possible to segregate the part that runs untrusted
+code from the rest through a fork, 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 `saralib` [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 `saralib` 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://github.com/smeso/sara-doc>`_
+.. [2] `saractl		<https://github.com/smeso/saractl>`_
+.. [3] `saralib		<https://github.com/smeso/saralib>`_
+.. [4] `sara-test	<https://github.com/smeso/sara-test>`_
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1664134 — Re: [kernel-hardening] [PATCH 01/11] S.A.R.A. Documentation

FromJann Horn <jannh@google.com>
Date2017-06-12 19:50 +0200
SubjectRe: [kernel-hardening] [PATCH 01/11] S.A.R.A. Documentation
Message-ID<tRBDr-5i1-1@gated-at.bofh.it>
In reply to#1663990
On Mon, Jun 12, 2017 at 6:56 PM, Salvatore Mesoraca
<s.mesoraca16@gmail.com> wrote:
> Adding documentation for S.A.R.A. LSM.
>
> Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
[...]
> +/proc/PID/attr/sara/wxprot interface
> +------------------------------------
> +The `procattr` interface can be used by a program 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.
> +
> +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.
> +Given that it's possible to segregate the part that runs untrusted
> +code from the rest through a fork, this feature can be use to run the JIT
> +compiler with few restrictions while enforcing full WX Protection in the
> +rest of the program.

As far as I can tell, the wxprot interface in procfs, when used as
/proc/PID/attr/sara/wxprot, actually only sets restrictions on one of the
threads.
The documentation doesn't seem to mention this.


> +.. [3] `saralib                <https://github.com/smeso/saralib>`_

This link is broken.

[toc] | [prev] | [next] | [standalone]


#1664561 — Re: [kernel-hardening] [PATCH 01/11] S.A.R.A. Documentation

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-13 09:50 +0200
SubjectRe: [kernel-hardening] [PATCH 01/11] S.A.R.A. Documentation
Message-ID<tROKl-59U-5@gated-at.bofh.it>
In reply to#1664134
2017-06-12 19:49 GMT+02:00 Jann Horn <jannh@google.com>:
> On Mon, Jun 12, 2017 at 6:56 PM, Salvatore Mesoraca
> As far as I can tell, the wxprot interface in procfs, when used as
> /proc/PID/attr/sara/wxprot, actually only sets restrictions on one of the
> threads.
> The documentation doesn't seem to mention this.

Yes, you are right. I'll change it.

>> +.. [3] `saralib                <https://github.com/smeso/saralib>`_
>
> This link is broken.

Oops, the correct link is https://github.com/smeso/libsara

Thank you very much for your time.

[toc] | [prev] | [next] | [standalone]


#1663992 — [PATCH 09/11] Trampoline emulation

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-12 19:00 +0200
Subject[PATCH 09/11] Trampoline emulation
Message-ID<tRAR4-4Dh-33@gated-at.bofh.it>
In reply to#1663977
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.
The assembly sequences used here were originally obtained from PaX source
code.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 security/sara/Kconfig               |  17 ++++
 security/sara/include/trampolines.h | 171 ++++++++++++++++++++++++++++++++++++
 security/sara/wxprot.c              | 137 +++++++++++++++++++++++++++++
 3 files changed, 325 insertions(+)
 create mode 100644 security/sara/include/trampolines.h

diff --git a/security/sara/Kconfig b/security/sara/Kconfig
index cb49f20..e91c147 100644
--- a/security/sara/Kconfig
+++ b/security/sara/Kconfig
@@ -137,6 +137,23 @@ choice
 		  Documentation/security/SARA.rst.
 endchoice
 
+config SECURITY_SARA_WXPROT_EMUTRAMP
+	bool "Enable emulation for some types of trampolines"
+	depends on SECURITY_SARA_WXPROT
+	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/security/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/trampolines.h b/security/sara/include/trampolines.h
new file mode 100644
index 0000000..eab0a85
--- /dev/null
+++ b/security/sara/include/trampolines.h
@@ -0,0 +1,171 @@
+/*
+ * 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>
+ *
+ */
+
+#ifndef __SARA_TRAMPOLINES_H
+#define __SARA_TRAMPOLINES_H
+#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
+
+
+/* x86_32 */
+
+
+struct libffi_trampoline_x86_32 {
+	unsigned char mov;
+	unsigned int addr1;
+	unsigned char jmp;
+	unsigned int addr2;
+} __packed;
+
+struct gcc_trampoline_x86_32_type1 {
+	unsigned char mov1;
+	unsigned int addr1;
+	unsigned char mov2;
+	unsigned int addr2;
+	unsigned short jmp;
+} __packed;
+
+struct gcc_trampoline_x86_32_type2 {
+	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_type1 g1;
+	struct gcc_trampoline_x86_32_type2 g2;
+};
+
+#define is_valid_libffi_trampoline_x86_32(UNION)	\
+	(UNION.lf.mov == 0xB8 &&			\
+	UNION.lf.jmp == 0xE9)
+
+#define emulate_libffi_trampoline_x86_32(UNION, REGS) do {	\
+	(REGS)->ax = UNION.lf.addr1;				\
+	(REGS)->ip = (unsigned int) ((REGS)->ip +		\
+				     UNION.lf.addr2 +		\
+				     sizeof(UNION.lf));		\
+} while (0)
+
+#define is_valid_gcc_trampoline_x86_32_type1(UNION, REGS)	\
+	(UNION.g1.mov1 == 0xB9 &&				\
+	UNION.g1.mov2 == 0xB8 &&				\
+	UNION.g1.jmp == 0xE0FF &&				\
+	REGS->ip > REGS->sp)
+
+#define emulate_gcc_trampoline_x86_32_type1(UNION, REGS) do {	\
+	(REGS)->cx = UNION.g1.addr1;				\
+	(REGS)->ax = UNION.g1.addr2;				\
+	(REGS)->ip = UNION.g1.addr2;				\
+} while (0)
+
+#define is_valid_gcc_trampoline_x86_32_type2(UNION, REGS)	\
+	(UNION.g2.mov == 0xB9 &&				\
+	UNION.g2.jmp == 0xE9 &&					\
+	REGS->ip > REGS->sp)
+
+#define emulate_gcc_trampoline_x86_32_type2(UNION, REGS) do {	\
+	(REGS)->cx = UNION.g2.addr1;				\
+	(REGS)->ip = (unsigned int) ((REGS)->ip +		\
+				     UNION.g2.addr2 +		\
+				     sizeof(UNION.g2));		\
+} while (0)
+
+
+
+#ifdef CONFIG_X86_64
+
+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;
+};
+
+#define is_valid_libffi_trampoline_x86_64(UNION)	\
+	(UNION.lf.mov1 == 0xBB49 &&			\
+	UNION.lf.mov2 == 0xBA49 &&			\
+	(UNION.lf.stcclc == 0xF8 ||			\
+	 UNION.lf.stcclc == 0xF9) &&			\
+	UNION.lf.jmp1 == 0xFF49 &&			\
+	UNION.lf.jmp2 == 0xE3)
+
+#define emulate_libffi_trampoline_x86_64(UNION, REGS) do {	\
+	(REGS)->r11 = UNION.lf.addr1;				\
+	(REGS)->r10 = UNION.lf.addr2;				\
+	(REGS)->ip = UNION.lf.addr1;				\
+	if (UNION.lf.stcclc == 0xF8)				\
+		(REGS)->flags &= ~X86_EFLAGS_CF;		\
+	else							\
+		(REGS)->flags |= X86_EFLAGS_CF;			\
+} while (0)
+
+#define is_valid_gcc_trampoline_x86_64_type1(UNION, REGS)	\
+	(UNION.g1.mov1 == 0xBB49 &&				\
+	UNION.g1.mov2 == 0xBA49 &&				\
+	UNION.g1.jmp1 == 0xFF49 &&				\
+	UNION.g1.jmp2 == 0xE3 &&				\
+	REGS->ip > REGS->sp)
+
+#define emulate_gcc_trampoline_x86_64_type1(UNION, REGS) do {	\
+	(REGS)->r11 = UNION.g1.addr1;				\
+	(REGS)->r10 = UNION.g1.addr2;				\
+	(REGS)->ip = UNION.g1.addr1;				\
+} while (0)
+
+#define is_valid_gcc_trampoline_x86_64_type2(UNION, REGS)	\
+	(UNION.g2.mov1 == 0xBB41 &&				\
+	UNION.g2.mov2 == 0xBA49 &&				\
+	UNION.g2.jmp1 == 0xFF49 &&				\
+	UNION.g2.jmp2 == 0xE3 &&				\
+	REGS->ip > REGS->sp)
+
+#define emulate_gcc_trampoline_x86_64_type2(UNION, REGS) do {	\
+	(REGS)->r11 = UNION.g2.addr1;				\
+	(REGS)->r10 = UNION.g2.addr2;				\
+	(REGS)->ip = UNION.g2.addr1;				\
+} while (0)
+
+#endif /* CONFIG_X86_64 */
+
+#endif /* CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP */
+#endif /* __SARA_TRAMPOLINES_H */
diff --git a/security/sara/wxprot.c b/security/sara/wxprot.c
index cbeedd3..44e42be 100644
--- a/security/sara/wxprot.c
+++ b/security/sara/wxprot.c
@@ -20,6 +20,11 @@
 #include <linux/elf.h>
 #include <linux/spinlock.h>
 
+#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
+#include <linux/uaccess.h>
+#include "include/trampolines.h"
+#endif
+
 #include "include/sara.h"
 #include "include/sara_data.h"
 #include "include/utils.h"
@@ -35,6 +40,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	| \
@@ -45,7 +51,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_rule {
 	char *path;
@@ -70,7 +81,11 @@ struct wxprot_config_container {
 static u16 default_flags __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
 
 #define pr_wxp(MESSAGE) do {					\
 	char *BUF, *PATH;					\
@@ -93,6 +108,9 @@ static bool are_flags_valid(u16 flags)
 				SARA_WXP_WXORX |
 				SARA_WXP_MMAP))))
 		return false;
+	if (unlikely(flags & SARA_WXP_EMUTRAMP &&
+		     ((flags & SARA_WXP_MPROTECT) != SARA_WXP_MPROTECT)))
+		return false;
 	return true;
 }
 
@@ -362,10 +380,129 @@ static int sara_file_mprotect(struct vm_area_struct *vma,
 	return 0;
 }
 
+#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
+#define PF_PROT		(1 << 0)
+#define PF_USER		(1 << 2)
+#define PF_INSTR	(1 << 4)
+static int sara_pagefault_handler_x86_32(struct pt_regs *regs);
+static int sara_pagefault_handler_x86_64(struct pt_regs *regs);
+static int sara_pagefault_handler_x86(struct pt_regs *regs,
+					unsigned long error_code,
+					unsigned long address)
+{
+	int ret = 0;
+
+	if (!sara_enabled || !wxprot_enabled ||
+	    !(error_code & PF_USER) ||
+	    !(error_code & PF_INSTR) ||
+	    !(error_code & PF_PROT) ||
+	    !(get_current_sara_wxp_flags() & SARA_WXP_EMUTRAMP))
+		return 0;
+
+	local_irq_enable();
+	might_sleep();
+	might_fault();
+
+	if (IS_ENABLED(CONFIG_X86_32) ||
+	    regs->cs == __USER32_CS ||
+	    (regs->cs & (1<<2))) {
+		if (!(address >> 32))	/* K8 erratum #100 */
+			ret = sara_pagefault_handler_x86_32(regs);
+	} else
+		ret = sara_pagefault_handler_x86_64(regs);
+
+	return ret;
+}
+
+static int sara_pagefault_handler_x86_32(struct pt_regs *regs)
+{
+	int ret;
+	void __user *ip = (void __user *) regs->ip;
+	union trampolines_x86_32 t;
+
+	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_valid_gcc_trampoline_x86_32_type1(t, regs)) {
+		pr_debug("Trampoline: gcc1 x86_32.\n");
+		emulate_gcc_trampoline_x86_32_type1(t, regs);
+		return 1;
+	} else if (is_valid_libffi_trampoline_x86_32(t)) {
+		pr_debug("Trampoline: libffi x86_32.\n");
+		emulate_libffi_trampoline_x86_32(t, regs);
+		return 1;
+	} else if (is_valid_gcc_trampoline_x86_32_type2(t, regs)) {
+		pr_debug("Trampoline: gcc2 x86_32.\n");
+		emulate_gcc_trampoline_x86_32_type2(t, regs);
+		return 1;
+	}
+
+	pr_debug("Not a trampoline (x86_32).\n");
+
+	return 0;
+}
+
+#ifdef CONFIG_X86_64
+static int sara_pagefault_handler_x86_64(struct pt_regs *regs)
+{
+	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));
+
+	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_valid_libffi_trampoline_x86_64(t)) {
+		pr_debug("Trampoline: libffi x86_64.\n");
+		emulate_libffi_trampoline_x86_64(t, regs);
+		return 1;
+	} else if (is_valid_gcc_trampoline_x86_64_type1(t, regs)) {
+		pr_debug("Trampoline: gcc1 x86_64.\n");
+		emulate_gcc_trampoline_x86_64_type1(t, regs);
+		return 1;
+	} else if (is_valid_gcc_trampoline_x86_64_type2(t, regs)) {
+		pr_debug("Trampoline: gcc2 x86_64.\n");
+		emulate_gcc_trampoline_x86_64_type2(t, regs);
+		return 1;
+	}
+
+	pr_debug("Not a trampoline (x86_64).\n");
+
+	return 0;
+
+}
+#else /* CONFIG_X86_64 */
+static inline int sara_pagefault_handler_x86_64(struct pt_regs *regs)
+{
+	return 0;
+}
+#endif /* CONFIG_X86_64 */
+
+#endif /* CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP */
+
 static struct security_hook_list wxprot_hooks[] __ro_after_init = {
 	LSM_HOOK_INIT(bprm_set_creds, sara_bprm_set_creds),
 	LSM_HOOK_INIT(check_vmflags, sara_check_vmflags),
 	LSM_HOOK_INIT(file_mprotect, sara_file_mprotect),
+#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
+	LSM_HOOK_INIT(pagefault_handler_x86, sara_pagefault_handler_x86),
+#endif
 };
 
 struct binary_config_header {
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1663998 — [PATCH 04/11] S.A.R.A. USB Filtering

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-12 19:00 +0200
Subject[PATCH 04/11] S.A.R.A. USB Filtering
Message-ID<tRAR5-4Dh-45@gated-at.bofh.it>
In reply to#1663977
Introduction of S.A.R.A. USB Filtering.
It uses the "usb_device_auth" LSM hook to provide a mechanism to decide
which USB devices should be authorized to connect to the system and
which shouldn't.
The main goal is to narrow the attack surface for custom USB devices
designed to exploit vulnerabilities found in some USB device drivers.
Via configuration it's possible to allow or to deny authorization, based
on one or more of: Vendor ID, Product ID, bus name and port number. There
is also support for "trailing wildcards".
Depending on the configuration, it can work both as a white list or as a
black list.
The original idea is inspired by the Grsecurity "Deny USB" feature.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
---
 security/sara/Kconfig                 |  41 ++++
 security/sara/Makefile                |   1 +
 security/sara/include/usb_filtering.h |  27 +++
 security/sara/main.c                  |   6 +
 security/sara/usb_filtering.c         | 410 ++++++++++++++++++++++++++++++++++
 5 files changed, 485 insertions(+)
 create mode 100644 security/sara/include/usb_filtering.h
 create mode 100644 security/sara/usb_filtering.c

diff --git a/security/sara/Kconfig b/security/sara/Kconfig
index 5b61020..01ff246 100644
--- a/security/sara/Kconfig
+++ b/security/sara/Kconfig
@@ -39,4 +39,45 @@ config SECURITY_SARA_NO_RUNTIME_ENABLE
 
 	  If unsure, answer Y.
 
+config SECURITY_SARA_USB_FILTERING
+	bool "USB Filtering"
+	depends on SECURITY_SARA && USB_SUPPORT
+	default y
+	help
+	  Enable S.A.R.A. USB filtering capability. To prevent the connection
+	  of unwanted USB devices, e.g. custom USB devices designed to
+	  exploit vulnerabilities found in device drivers.
+	  User-space utilities can be used to manage the configuration file.
+	  Further information can be found in Documentation/security/SARA.rst.
+
+	  If unsure, answer Y.
+
+config SECURITY_SARA_USB_FILTERING_DENY
+	bool "Default action for new USB devices is DENY"
+	depends on SECURITY_SARA_USB_FILTERING
+	default n
+	help
+	  If you say Y here any device that is not explicitly allowed via the
+	  configuration will be blocked. If you don't enable this option
+	  any USB device connected at boot will be allowed, regardless of
+	  your settings. However, if you enable this and you don't
+	  set your user-space utilities adequately your machine could become
+	  unusable (e.g. your USB keyboard will be disabled).
+	  This option can be overridden at boot time via
+	  "sara_usb_filtering_default=[d|a]" kernel parameter.
+
+	  If unsure, answer N.
+
+config SECURITY_SARA_USB_FILTERING_DISABLED
+	bool "USB filtering will be disabled at boot."
+	depends on SECURITY_SARA_USB_FILTERING
+	default n
+	help
+	  If you say Y here USB filtering won't be enabled at startup. You can
+	  override this option via user-space utilities or at boot time via
+	  "sara_usb_filtering=[0|1]" kernel parameter.
+	  This option is useful for distro kernels.
+
+	  If unsure, answer N.
+
 endmenu
diff --git a/security/sara/Makefile b/security/sara/Makefile
index 8acd291..8acf8a9 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-$(CONFIG_SECURITY_SARA_USB_FILTERING) += usb_filtering.o
diff --git a/security/sara/include/usb_filtering.h b/security/sara/include/usb_filtering.h
new file mode 100644
index 0000000..5645e0f
--- /dev/null
+++ b/security/sara/include/usb_filtering.h
@@ -0,0 +1,27 @@
+/*
+ * 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_USB_FILTERING_H
+#define __SARA_USB_FILTERING_H
+
+#ifdef CONFIG_SECURITY_SARA_USB_FILTERING
+
+#include <linux/init.h>
+int sara_usb_filtering_init(void) __init;
+
+#else /* CONFIG_SECURITY_SARA_USB_FILTERING */
+inline int sara_usb_filtering_init(void)
+{
+	return 0;
+}
+#endif /* CONFIG_SECURITY_SARA_USB_FILTERING */
+
+#endif /* __SARA_USB_FILTERING_H */
diff --git a/security/sara/main.c b/security/sara/main.c
index 2007735..8783c3c 100644
--- a/security/sara/main.c
+++ b/security/sara/main.c
@@ -15,6 +15,7 @@
 
 #include "include/sara.h"
 #include "include/securityfs.h"
+#include "include/usb_filtering.h"
 
 static const int sara_version = SARA_VERSION;
 
@@ -80,6 +81,11 @@ void __init sara_init(void)
 		goto error;
 	}
 
+	if (sara_usb_filtering_init()) {
+		pr_crit("impossible to initialize usb filtering.\n");
+		goto error;
+	}
+
 	pr_debug("initialized.\n");
 
 	if (sara_enabled)
diff --git a/security/sara/usb_filtering.c b/security/sara/usb_filtering.c
new file mode 100644
index 0000000..270f110
--- /dev/null
+++ b/security/sara/usb_filtering.c
@@ -0,0 +1,410 @@
+/*
+ * 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_USB_FILTERING
+
+#include <linux/kref.h>
+#include <linux/lsm_hooks.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+
+#include "include/sara.h"
+#include "include/utils.h"
+#include "include/securityfs.h"
+#include "include/usb_filtering.h"
+
+#define SARA_USB_FILTERING_CONFIG_VERSION 0
+
+#define SARA_USB_FILTERING_ALLOW 0
+#define SARA_USB_FILTERING_DENY 1
+
+struct usb_filtering_rule {
+	u16 product_id;
+	u16 vendor_id;
+	u8 product_id_shift;
+	u8 vendor_id_shift;
+	char *bus_name;
+	bool exact_bus_name;
+	u8 port;
+	u8 action;
+};
+
+struct usb_config_container {
+	u32 rules_size;
+	struct usb_filtering_rule *rules;
+	size_t buf_len;
+	struct kref refcount;
+	char hash[SARA_CONFIG_HASH_LEN];
+};
+
+static struct usb_config_container __rcu *usb_filtering_config;
+
+static const int usb_filtering_version =
+				SARA_USB_FILTERING_CONFIG_VERSION;
+static bool usb_filtering_enabled __read_mostly = true;
+static DEFINE_SPINLOCK(usb_config_lock);
+
+#ifdef CONFIG_SECURITY_SARA_USB_FILTERING_DENY
+static int default_action __ro_after_init = SARA_USB_FILTERING_DENY;
+#else
+static int default_action __ro_after_init = SARA_USB_FILTERING_ALLOW;
+#endif
+
+static int __init sara_usb_filtering_enabled_setup(char *str)
+{
+	if (str[0] == '1' && str[1] == '\0')
+		usb_filtering_enabled = true;
+	else
+		usb_filtering_enabled = false;
+	return 1;
+}
+__setup("sara_usb_filtering=", sara_usb_filtering_enabled_setup);
+
+static int __init sara_usb_filtering_default_setup(char *str)
+{
+	if (str[0] == 'd' && str[1] == '\0')
+		default_action = SARA_USB_FILTERING_DENY;
+	else
+		default_action = SARA_USB_FILTERING_ALLOW;
+	return 1;
+}
+__setup("sara_usb_filtering_default=", sara_usb_filtering_default_setup);
+
+static int sara_usb_device_auth(const struct usb_device *udev)
+{
+	int i;
+	int ret;
+	u16 vid = le16_to_cpu(udev->descriptor.idVendor);
+	u16 pid = le16_to_cpu(udev->descriptor.idProduct);
+	const char *bus_name = udev->bus->bus_name;
+	struct usb_config_container *c;
+
+	if (!sara_enabled || !usb_filtering_enabled)
+		return SARA_USB_FILTERING_ALLOW;
+
+	pr_debug("USB filtering: new usb device found \"%04x:%04x\" on \"%s\" port \"%d\".\n",
+		 vid, pid, bus_name, udev->portnum);
+
+	SARA_CONFIG_GET_RCU(c, usb_filtering_config);
+	for (i = 0; i < c->rules_size; ++i) {
+		if ((vid >> c->rules[i].vendor_id_shift) ==
+		    c->rules[i].vendor_id &&
+		    (pid >> c->rules[i].product_id_shift) ==
+		    c->rules[i].product_id) {
+			if (!c->rules[i].port ||
+			    c->rules[i].port == udev->portnum) {
+				if (c->rules[i].exact_bus_name) {
+					if (strcmp(bus_name,
+						   c->rules[i].bus_name) == 0)
+						goto match;
+				} else if (strncmp(bus_name,
+						c->rules[i].bus_name,
+						strlen(c->rules[i].bus_name))
+						== 0)
+					goto match;
+			}
+		}
+	}
+	SARA_CONFIG_PUT_RCU(c);
+
+	ret = default_action;
+	if (ret == SARA_USB_FILTERING_ALLOW)
+		pr_info("USB filtering: no match found for \"%04x:%04x\" on \"%s\" port \"%d\". Default action is ALLOW.\n",
+			vid, pid, bus_name, udev->portnum);
+	else
+		pr_info("USB filtering: no match found for \"%04x:%04x\" on \"%s\" port \"%d\". Default action is DENY.\n",
+			vid, pid, bus_name, udev->portnum);
+	goto out;
+
+match:
+	ret = c->rules[i].action;
+	SARA_CONFIG_PUT_RCU(c);
+	if (ret == SARA_USB_FILTERING_ALLOW)
+		pr_info("USB filtering: match found for \"%04x:%04x\" on \"%s\" port \"%d\". Action is ALLOW.\n",
+			vid, pid, bus_name, udev->portnum);
+	else
+		pr_notice("USB filtering: match found for \"%04x:%04x\" on \"%s\" port \"%d\". Action is DENY.\n",
+			  vid, pid, bus_name, udev->portnum);
+out:
+	return ret;
+}
+
+static struct security_hook_list usb_hooks[] __ro_after_init  = {
+	LSM_HOOK_INIT(usb_device_auth, sara_usb_device_auth),
+};
+
+struct binary_config_header {
+	char magic[8];
+	__le32 version;
+	__le32 rules_size;
+	char hash[SARA_CONFIG_HASH_LEN];
+} __packed;
+
+struct binary_config_rule {
+	__le16 product_id;
+	__le16 vendor_id;
+	u8 product_id_shift;
+	u8 vendor_id_shift;
+	u8 exact_bus_name;
+	u8 action;
+	u8 port;
+	u8 bus_name_len;
+} __packed;
+
+static void config_free(struct usb_config_container *data)
+{
+	int i;
+
+	for (i = 0; i < data->rules_size; ++i)
+		kfree(data->rules[i].bus_name);
+	kvfree(data->rules);
+	kfree(data);
+}
+
+static int config_load(const char *buf, size_t buf_len)
+{
+	int ret;
+	int i;
+	size_t inc;
+	const char *pos;
+	struct usb_config_container *new;
+	struct binary_config_header *h;
+	struct binary_config_rule *r;
+
+	ret = -EINVAL;
+	if (unlikely(buf_len < sizeof(*h)))
+		goto out;
+
+	h = (struct binary_config_header *) buf;
+	pos = buf + sizeof(*h);
+
+	ret = -EINVAL;
+	if (unlikely(memcmp(h->magic, "SARAUSBF", 8) != 0))
+		goto out;
+	if (unlikely(le32_to_cpu(h->version) != usb_filtering_version))
+		goto out;
+
+	ret = -ENOMEM;
+	new = kmalloc(sizeof(*new), GFP_KERNEL);
+	if (unlikely(new == NULL))
+		goto out;
+	kref_init(&new->refcount);
+	new->rules_size = le32_to_cpu(h->rules_size);
+	BUILD_BUG_ON(sizeof(new->hash) != sizeof(h->hash));
+	memcpy(new->hash, h->hash, sizeof(new->hash));
+	if (unlikely(new->rules_size == 0)) {
+		new->rules = NULL;
+		goto replace;
+	}
+
+	ret = -ENOMEM;
+	new->rules = sara_kvcalloc(new->rules_size,
+				   sizeof(*new->rules));
+	if (unlikely(new->rules == NULL))
+		goto out_new;
+	for (i = 0; i < new->rules_size; ++i) {
+		r = (struct binary_config_rule *) pos;
+		pos += sizeof(*r);
+		inc = pos-buf;
+
+		ret = -EINVAL;
+		if (unlikely(inc + r->bus_name_len > buf_len))
+			goto out_rules;
+
+		new->rules[i].product_id = le16_to_cpu(r->product_id);
+		new->rules[i].vendor_id = le16_to_cpu(r->vendor_id);
+		new->rules[i].product_id_shift = r->product_id_shift;
+		new->rules[i].vendor_id_shift = r->vendor_id_shift;
+		new->rules[i].exact_bus_name = r->exact_bus_name;
+		new->rules[i].action = r->action;
+		new->rules[i].port = r->port;
+
+		if (unlikely(new->rules[i].product_id_shift > 16))
+			goto out_rules;
+		if (unlikely(new->rules[i].vendor_id_shift > 16))
+			goto out_rules;
+		if (unlikely((int) new->rules[i].exact_bus_name != 0 &&
+			     (int) new->rules[i].exact_bus_name != 1))
+			goto out_rules;
+		if (unlikely(new->rules[i].action != 0 &&
+			     new->rules[i].action != 1))
+			goto out_rules;
+
+		ret = -ENOMEM;
+		new->rules[i].bus_name = kmalloc(r->bus_name_len+1, GFP_KERNEL);
+		if (unlikely(new->rules[i].bus_name == NULL))
+			goto out_rules;
+
+		memcpy(new->rules[i].bus_name, pos, r->bus_name_len);
+		new->rules[i].bus_name[r->bus_name_len] = '\0';
+		pos += r->bus_name_len;
+	}
+	new->buf_len = (size_t) (pos-buf);
+
+replace:
+	SARA_CONFIG_REPLACE(usb_filtering_config,
+			    new,
+			    config_free,
+			    &usb_config_lock);
+	pr_notice("USB filtering: new rules loaded.\n");
+	return 0;
+
+out_rules:
+	for (i = 0; i < new->rules_size; ++i)
+		kfree(new->rules[i].bus_name);
+	kvfree(new->rules);
+out_new:
+	kfree(new);
+out:
+	pr_warn("USB filtering: failed to load rules.\n");
+	return ret;
+}
+
+static ssize_t config_dump(char **buf)
+{
+	int i;
+	ssize_t ret;
+	size_t buf_len;
+	char *pos;
+	char *mybuf;
+	int rulen;
+	struct usb_config_container *c;
+	struct usb_filtering_rule *rc;
+	struct binary_config_header *h;
+	struct binary_config_rule *r;
+
+	ret = -ENOMEM;
+	SARA_CONFIG_GET(c, usb_filtering_config);
+	buf_len = c->buf_len;
+	mybuf = sara_kvmalloc(buf_len);
+	if (unlikely(mybuf == NULL))
+		goto out;
+	rulen = c->rules_size;
+	h = (struct binary_config_header *) mybuf;
+	memcpy(h->magic, "SARAUSBF", 8);
+	h->version = cpu_to_le32(SARA_USB_FILTERING_CONFIG_VERSION);
+	h->rules_size = cpu_to_le32(rulen);
+	BUILD_BUG_ON(sizeof(c->hash) != sizeof(h->hash));
+	memcpy(h->hash, c->hash, sizeof(h->hash));
+	pos = mybuf + sizeof(*h);
+	for (i = 0; i < rulen; ++i) {
+		r = (struct binary_config_rule *) pos;
+		pos += sizeof(*r);
+		if (buf_len < (pos - mybuf))
+			goto out;
+		rc = &c->rules[i];
+		r->product_id = cpu_to_le16(rc->product_id);
+		r->vendor_id = cpu_to_le16(rc->vendor_id);
+		r->product_id_shift = rc->product_id_shift;
+		r->vendor_id_shift = rc->vendor_id_shift;
+		r->exact_bus_name = (u8) rc->exact_bus_name;
+		r->action = rc->action;
+		r->port = rc->port;
+		r->bus_name_len = strlen(rc->bus_name);
+		if (buf_len < ((pos - mybuf) + r->bus_name_len))
+			goto out;
+		memcpy(pos, rc->bus_name, r->bus_name_len);
+		pos += r->bus_name_len;
+	}
+	ret = (ssize_t) (pos - mybuf);
+	*buf = mybuf;
+out:
+	SARA_CONFIG_PUT(c, config_free);
+	return ret;
+}
+
+static int config_hash(char **buf)
+{
+	int ret;
+	struct usb_config_container *config;
+
+	ret = -ENOMEM;
+	*buf = kzalloc(sizeof(config->hash), GFP_KERNEL);
+	if (unlikely(*buf == NULL))
+		goto out;
+
+	SARA_CONFIG_GET_RCU(config, usb_filtering_config);
+	memcpy(*buf, config->hash, sizeof(config->hash));
+	SARA_CONFIG_PUT_RCU(config);
+
+	ret = 0;
+out:
+	return ret;
+}
+
+static DEFINE_SARA_SECFS_BOOL_FLAG(usb_filtering_enabled_data,
+				   usb_filtering_enabled);
+
+static struct sara_secfs_fptrs fptrs __ro_after_init = {
+	.load = config_load,
+	.dump = config_dump,
+	.hash = config_hash,
+};
+
+static const struct sara_secfs_node usb_filtering_fs[] __initconst = {
+	{
+		.name = "enabled",
+		.type = SARA_SECFS_BOOL,
+		.data = (void *) &usb_filtering_enabled_data,
+	},
+	{
+		.name = "version",
+		.type = SARA_SECFS_READONLY_INT,
+		.data = (int *) &usb_filtering_version,
+	},
+	{
+		.name = "default_action",
+		.type = SARA_SECFS_READONLY_INT,
+		.data = &default_action,
+	},
+	{
+		.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_usb_filtering_init(void)
+{
+	int ret;
+	struct usb_config_container *tmpc;
+
+	ret = -ENOMEM;
+	tmpc = kzalloc(sizeof(*tmpc), GFP_KERNEL);
+	if (unlikely(tmpc == NULL))
+		goto out_fail;
+	tmpc->buf_len = sizeof(struct binary_config_header);
+	kref_init(&tmpc->refcount);
+	usb_filtering_config = (struct usb_config_container __rcu *) tmpc;
+	ret = sara_secfs_subtree_register("usb_filtering",
+					  usb_filtering_fs,
+					  ARRAY_SIZE(usb_filtering_fs));
+	if (unlikely(ret))
+		goto out_fail;
+	security_add_hooks(usb_hooks, ARRAY_SIZE(usb_hooks), "sara");
+	return 0;
+
+out_fail:
+	kfree(tmpc);
+	return ret;
+}
+
+#endif /* CONFIG_SECURITY_SARA_USB_FILTERING */
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1664003 — [PATCH 05/11] Creation of "check_vmflags" LSM hook

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-12 19:00 +0200
Subject[PATCH 05/11] Creation of "check_vmflags" LSM hook
Message-ID<tRAR5-4Dh-63@gated-at.bofh.it>
In reply to#1663977
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" and "__install_special_mapping".

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
Cc: linux-mm@kvack.org
---
 include/linux/lsm_hooks.h | 6 ++++++
 include/linux/security.h  | 6 ++++++
 mm/mmap.c                 | 9 +++++++++
 security/security.c       | 5 +++++
 4 files changed, 26 insertions(+)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index cc0937e..6934cc5 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -483,6 +483,10 @@
  *	@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 requested the vmflags.
+ *	Return 0 if the operation is allowed to continue.
  * @file_lock:
  *	Check permission before performing file locking operations.
  *	Note: this hook mediates both flock and fcntl style locks.
@@ -1482,6 +1486,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);
@@ -1753,6 +1758,7 @@ struct security_hook_heads {
 	struct list_head mmap_addr;
 	struct list_head mmap_file;
 	struct list_head file_mprotect;
+	struct list_head check_vmflags;
 	struct list_head file_lock;
 	struct list_head file_fcntl;
 	struct list_head file_set_fowner;
diff --git a/include/linux/security.h b/include/linux/security.h
index 19bc364..67e33b6 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -302,6 +302,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);
@@ -830,6 +831,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 f82741e..e19f04e 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1363,6 +1363,9 @@ 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;
 
+	if (security_check_vmflags(vm_flags))
+		return -EPERM;
+
 	if (flags & MAP_LOCKED)
 		if (!can_do_mlock())
 			return -EPERM;
@@ -2833,6 +2836,9 @@ static int do_brk_flags(unsigned long addr, unsigned long request, unsigned long
 		return -EINVAL;
 	flags |= VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
 
+	if (security_check_vmflags(flags))
+		return -EPERM;
+
 	error = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED);
 	if (offset_in_page(error))
 		return error;
@@ -3208,6 +3214,9 @@ static struct vm_area_struct *__install_special_mapping(
 	int ret;
 	struct vm_area_struct *vma;
 
+	if (security_check_vmflags(vm_flags))
+		return ERR_PTR(-EPERM);
+
 	vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
 	if (unlikely(vma == NULL))
 		return ERR_PTR(-ENOMEM);
diff --git a/security/security.c b/security/security.c
index e390f99..25d58f0 100644
--- a/security/security.c
+++ b/security/security.c
@@ -905,6 +905,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

[toc] | [prev] | [next] | [standalone]


#1664253 — Re: [PATCH 05/11] Creation of "check_vmflags" LSM hook

FromCasey Schaufler <casey@schaufler-ca.com>
Date2017-06-12 23:40 +0200
SubjectRe: [PATCH 05/11] Creation of "check_vmflags" LSM hook
Message-ID<tRFe2-7zG-17@gated-at.bofh.it>
In reply to#1664003
On 6/12/2017 9:56 AM, Salvatore Mesoraca wrote:
> 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" and "__install_special_mapping".
>
> Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
> Cc: linux-mm@kvack.org
> ---
>  include/linux/lsm_hooks.h | 6 ++++++
>  include/linux/security.h  | 6 ++++++
>  mm/mmap.c                 | 9 +++++++++
>  security/security.c       | 5 +++++
>  4 files changed, 26 insertions(+)
>
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index cc0937e..6934cc5 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -483,6 +483,10 @@
>   *	@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 requested the vmflags.
> + *	Return 0 if the operation is allowed to continue.
>   * @file_lock:
>   *	Check permission before performing file locking operations.
>   *	Note: this hook mediates both flock and fcntl style locks.
> @@ -1482,6 +1486,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);
> @@ -1753,6 +1758,7 @@ struct security_hook_heads {
>  	struct list_head mmap_addr;
>  	struct list_head mmap_file;
>  	struct list_head file_mprotect;
> +	struct list_head check_vmflags;
>  	struct list_head file_lock;
>  	struct list_head file_fcntl;
>  	struct list_head file_set_fowner;
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 19bc364..67e33b6 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -302,6 +302,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);
> @@ -830,6 +831,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 f82741e..e19f04e 100644
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -1363,6 +1363,9 @@ 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;
>  
> +	if (security_check_vmflags(vm_flags))
> +		return -EPERM;
> +

Have the hook return a value and return that rather
than -EPERM. That way a security module can choose an
error that it determines is appropriate. It is possible
that a module might want to deny the access for a reason
other than lack of privilege. 

>  	if (flags & MAP_LOCKED)
>  		if (!can_do_mlock())
>  			return -EPERM;
> @@ -2833,6 +2836,9 @@ static int do_brk_flags(unsigned long addr, unsigned long request, unsigned long
>  		return -EINVAL;
>  	flags |= VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
>  
> +	if (security_check_vmflags(flags))
> +		return -EPERM;
> +

Same here

>  	error = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED);
>  	if (offset_in_page(error))
>  		return error;
> @@ -3208,6 +3214,9 @@ static struct vm_area_struct *__install_special_mapping(
>  	int ret;
>  	struct vm_area_struct *vma;
>  
> +	if (security_check_vmflags(vm_flags))
> +		return ERR_PTR(-EPERM);
> +

And here.

>  	vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
>  	if (unlikely(vma == NULL))
>  		return ERR_PTR(-ENOMEM);
> diff --git a/security/security.c b/security/security.c
> index e390f99..25d58f0 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -905,6 +905,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);

[toc] | [prev] | [next] | [standalone]


#1664577 — Re: [PATCH 05/11] Creation of "check_vmflags" LSM hook

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-13 10:00 +0200
SubjectRe: [PATCH 05/11] Creation of "check_vmflags" LSM hook
Message-ID<tROU3-5d9-27@gated-at.bofh.it>
In reply to#1664253
2017-06-12 23:31 GMT+02:00 Casey Schaufler <casey@schaufler-ca.com>:
> Have the hook return a value and return that rather
> than -EPERM. That way a security module can choose an
> error that it determines is appropriate. It is possible
> that a module might want to deny the access for a reason
> other than lack of privilege.
> [...]
>
> Same here
>
> [...]
>
> And here.

Yes, I think you are right. I'll fix it in the next version.
Thank you very much for taking the time to review my patch.

[toc] | [prev] | [next] | [standalone]


#1664491 — Re: [PATCH 05/11] Creation of "check_vmflags" LSM hook

FromChristoph Hellwig <hch@infradead.org>
Date2017-06-13 08:40 +0200
SubjectRe: [PATCH 05/11] Creation of "check_vmflags" LSM hook
Message-ID<tRNEC-4v8-5@gated-at.bofh.it>
In reply to#1664003
On Mon, Jun 12, 2017 at 06:56:54PM +0200, Salvatore Mesoraca wrote:
> 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" and "__install_special_mapping".

Please always post the whole series including the users, thanks.

[toc] | [prev] | [next] | [standalone]


#1664576 — Re: [PATCH 05/11] Creation of "check_vmflags" LSM hook

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-13 10:00 +0200
SubjectRe: [PATCH 05/11] Creation of "check_vmflags" LSM hook
Message-ID<tROU2-5d9-17@gated-at.bofh.it>
In reply to#1664491
2017-06-13 8:34 GMT+02:00 Christoph Hellwig <hch@infradead.org>:
> Please always post the whole series including the users, thanks.

I'm sorry for the inconvenience, it won't happen again.
Thank you for your comment.

[toc] | [prev] | [next] | [standalone]


#1664005 — [PATCH 02/11] S.A.R.A. framework creation

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-12 19:00 +0200
Subject[PATCH 02/11] S.A.R.A. framework creation
Message-ID<tRAR5-4Dh-65@gated-at.bofh.it>
In reply to#1663977
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>
---
 include/linux/lsm_hooks.h          |   5 +
 security/Kconfig                   |   1 +
 security/Makefile                  |   2 +
 security/sara/Kconfig              |  42 +++
 security/sara/Makefile             |   3 +
 security/sara/include/sara.h       |  29 ++
 security/sara/include/securityfs.h |  59 ++++
 security/sara/include/utils.h      |  69 +++++
 security/sara/main.c               |  95 +++++++
 security/sara/securityfs.c         | 558 +++++++++++++++++++++++++++++++++++++
 security/sara/utils.c              | 151 ++++++++++
 security/security.c                |   1 +
 12 files changed, 1015 insertions(+)
 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/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 080f34e..bd274db 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1946,5 +1946,10 @@ static inline void __init yama_add_hooks(void) { }
 #else
 static inline void loadpin_add_hooks(void) { };
 #endif
+#ifdef CONFIG_SECURITY_SARA
+void __init sara_init(void);
+#else
+static inline void __init sara_init(void) { };
+#endif
 
 #endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/security/Kconfig b/security/Kconfig
index 93027fd..1c13545 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -195,6 +195,7 @@ source security/tomoyo/Kconfig
 source security/apparmor/Kconfig
 source security/loadpin/Kconfig
 source security/yama/Kconfig
+source security/sara/Kconfig
 
 source security/integrity/Kconfig
 
diff --git a/security/Makefile b/security/Makefile
index f2d71cd..5d3578e 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -9,6 +9,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
 subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
 subdir-$(CONFIG_SECURITY_YAMA)		+= yama
 subdir-$(CONFIG_SECURITY_LOADPIN)	+= loadpin
+subdir-$(CONFIG_SECURITY_SARA)		+= sara
 
 # always enable default capabilities
 obj-y					+= commoncap.o
@@ -24,6 +25,7 @@ obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/
 obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/
 obj-$(CONFIG_SECURITY_YAMA)		+= yama/
 obj-$(CONFIG_SECURITY_LOADPIN)		+= loadpin/
+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..5b61020
--- /dev/null
+++ b/security/sara/Kconfig
@@ -0,0 +1,42 @@
+menu S.A.R.A.
+
+config SECURITY_SARA
+	bool "Enable 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/security/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=[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=1" kernel parameter.
+	  This option is functionally equivalent to "sara=0" kernel parameter.
+	  This option is useful for distro kernels.
+
+	  If unsure, answer Y.
+
+endmenu
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..1001a8a
--- /dev/null
+++ b/security/sara/include/sara.h
@@ -0,0 +1,29 @@
+/*
+ * 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 bool sara_config_locked __read_mostly;
+extern bool sara_enabled __read_mostly;
+
+void sara_init(void) __init;
+
+#endif /* __SARA_H */
diff --git a/security/sara/include/securityfs.h b/security/sara/include/securityfs.h
new file mode 100644
index 0000000..57e6306
--- /dev/null
+++ b/security/sara/include/securityfs.h
@@ -0,0 +1,59 @@
+/*
+ * 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];
+	bool *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..166b9ed
--- /dev/null
+++ b/security/sara/include/utils.h
@@ -0,0 +1,69 @@
+/*
+ * 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);
+void *sara_kvmalloc(size_t size) __attribute__((malloc));
+void *sara_kvcalloc(size_t n, size_t size) __attribute__((malloc));
+
+static inline void release_entry(struct kref *ref)
+{
+	/* All work is done after the return from kref_put(). */
+}
+
+#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..2007735
--- /dev/null
+++ b/security/sara/main.c
@@ -0,0 +1,95 @@
+/*
+ * 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/printk.h>
+
+#include "include/sara.h"
+#include "include/securityfs.h"
+
+static const int sara_version = SARA_VERSION;
+
+#ifdef CONFIG_SECURITY_SARA_NO_RUNTIME_ENABLE
+bool sara_config_locked __read_mostly = true;
+#else
+bool sara_config_locked __read_mostly;
+#endif
+
+#ifdef CONFIG_SECURITY_SARA_DEFAULT_DISABLED
+bool sara_enabled __read_mostly;
+#else
+bool 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 __init sara_enabled_setup(char *str)
+{
+	if (str[0] == '1' && str[1] == '\0') {
+		sara_enabled = true;
+		sara_config_locked = false;
+	} else {
+		sara_enabled = false;
+		sara_config_locked = true;
+	}
+	return 1;
+}
+__setup("sara=", sara_enabled_setup);
+
+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,
+	},
+};
+
+void __init sara_init(void)
+{
+	if (!sara_enabled && sara_config_locked) {
+		pr_notice("permanently disabled.\n");
+		return;
+	}
+
+	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;
+
+error:
+	sara_enabled = false;
+	sara_config_locked = true;
+	pr_crit("permanently disabled.\n");
+}
diff --git a/security/sara/securityfs.c b/security/sara/securityfs.c
new file mode 100644
index 0000000..4dca504
--- /dev/null
+++ b/security/sara/securityfs.c
@@ -0,0 +1,558 @@
+/*
+ * 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/ctype.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/security.h>
+
+#include "include/sara.h"
+#include "include/utils.h"
+#include "include/securityfs.h"
+
+#define STR_HELPER(x) #x
+#define STR(x) STR_HELPER(x)
+
+static struct dentry *fs_root;
+
+static inline bool check_config_write_access(void)
+{
+	if (unlikely(sara_config_locked && !capable(CAP_MAC_ADMIN))) {
+		pr_warn("config write access blocked.\n");
+		return false;
+	}
+	return true;
+}
+
+static bool check_config_access(const struct file *file)
+{
+	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)
+{
+	bool *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'};
+	bool 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 = sara_kvmalloc(buf_size);
+	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, "%" 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 0;
+}
+
+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 0;
+}
+
+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 0;
+}
+
+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 0;
+}
+
+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 0;
+}
+
+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->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..9250b7b
--- /dev/null
+++ b/security/sara/utils.c
@@ -0,0 +1,151 @@
+/*
+ * 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 = sara_kvmalloc(size);
+		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(sizeof(current->comm), GFP_KERNEL);
+		get_task_comm(*buf, current);
+		path = *buf;
+	}
+	return path;
+}
+
+/**
+ * sara_kvmalloc - do allocation preferring kmalloc but falling back to vmalloc
+ * @size: how many bytes of memory are required
+ *
+ * Return: allocated buffer or NULL if failed
+ *
+ * It is possible that ruleset being loaded from the user is larger than
+ * what can be allocated by kmalloc, in those cases fall back to vmalloc.
+ *
+ * Nearly identical copy of AppArmor's __aa_kvmalloc.
+ */
+void *__attribute__((malloc)) sara_kvmalloc(size_t size)
+{
+	void *buffer = NULL;
+
+	__might_sleep(__FILE__, __LINE__, 0);
+
+	if (size == 0)
+		return NULL;
+
+	/* do not attempt kmalloc if we need more than 16 pages at once */
+	if (size <= (16*PAGE_SIZE))
+		buffer = kmalloc(size, GFP_KERNEL | __GFP_NORETRY |
+				 __GFP_NOWARN);
+	if (!buffer)
+		buffer = vmalloc(size);
+
+	return buffer;
+}
+
+/**
+ * sara_kvcalloc - do allocation preferring kcalloc but falling back to vmalloc
+ * @size: number of object to allocate
+ * @size: how many bytes of memory are required per each object
+ *
+ * Return: allocated buffer or NULL if failed
+ *
+ * It is possible that ruleset being loaded from the user is larger than
+ * what can be allocated by kcalloc, in those cases fall back to vmalloc.
+ *
+ * Nearly identical copy of AppArmor's __aa_kvmalloc.
+ */
+void *__attribute__((malloc)) sara_kvcalloc(size_t n, size_t size)
+{
+	void *buffer = NULL;
+
+	__might_sleep(__FILE__, __LINE__, 0);
+
+	if (size == 0)
+		return NULL;
+
+	/* do not attempt kmalloc if we need more than 16 pages at once */
+	if (size <= (16*PAGE_SIZE))
+		buffer = kcalloc(n, size, GFP_KERNEL | __GFP_NORETRY |
+				 __GFP_NOWARN);
+	if (!buffer)
+		buffer = vzalloc(n*size);
+
+	return buffer;
+}
diff --git a/security/security.c b/security/security.c
index b9fea39..42c8028 100644
--- a/security/security.c
+++ b/security/security.c
@@ -69,6 +69,7 @@ int __init security_init(void)
 	capability_add_hooks();
 	yama_add_hooks();
 	loadpin_add_hooks();
+	sara_init();
 
 	/*
 	 * Load all the remaining security modules.
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1664006 — [PATCH 03/11] Creation of "usb_device_auth" LSM hook

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-12 19:00 +0200
Subject[PATCH 03/11] Creation of "usb_device_auth" LSM hook
Message-ID<tRAR5-4Dh-61@gated-at.bofh.it>
In reply to#1663977
Creation of a new LSM hook that can be used to authorize or deauthorize
new USB devices via the usb authorization interface.
The same hook can also prevent the authorization of a USB device via
"/sys/bus/usb/devices/DEVICE/authorized".
Using this hook an LSM could provide an higher level of granularity
than the current authorization interface.

Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
Cc: linux-usb@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/usb/core/hub.c    | 4 ++++
 drivers/usb/core/sysfs.c  | 6 +++++-
 include/linux/lsm_hooks.h | 6 ++++++
 include/linux/security.h  | 7 +++++++
 security/security.c       | 5 +++++
 5 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b8bb20d..58be4f0 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -28,6 +28,7 @@
 #include <linux/mutex.h>
 #include <linux/random.h>
 #include <linux/pm_qos.h>
+#include <linux/security.h>
 
 #include <linux/uaccess.h>
 #include <asm/byteorder.h>
@@ -4831,6 +4832,9 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
 		if (udev->quirks & USB_QUIRK_DELAY_INIT)
 			msleep(1000);
 
+		if (security_usb_device_auth(udev))
+			usb_deauthorize_device(udev);
+
 		/* consecutive bus-powered hubs aren't reliable; they can
 		 * violate the voltage drop budget.  if the new child has
 		 * a "powered" LED, users should notice we didn't enable it
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index dfc68ed..fce9d39 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -17,6 +17,7 @@
 #include <linux/usb.h>
 #include <linux/usb/quirks.h>
 #include <linux/of.h>
+#include <linux/security.h>
 #include "usb.h"
 
 /* Active configuration fields */
@@ -742,8 +743,11 @@ static ssize_t authorized_store(struct device *dev,
 		result = -EINVAL;
 	else if (val == 0)
 		result = usb_deauthorize_device(usb_dev);
-	else
+	else {
+		if (security_usb_device_auth(usb_dev))
+			return -EPERM;
 		result = usb_authorize_device(usb_dev);
+	}
 	return result < 0 ? result : size;
 }
 static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, S_IRUGO | S_IWUSR,
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index bd274db..cc0937e 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1189,6 +1189,10 @@
  *	to the @parent process for tracing.
  *	@parent contains the task_struct structure for debugger process.
  *	Return 0 if permission is granted.
+ * @usb_device_auth:
+ *	Check if @udev device should be authorized or not.
+ *	@udev contains the usb_device structure for the USB device.
+ *	Return 0 if the device is allowed.
  * @capget:
  *	Get the @effective, @inheritable, and @permitted capability sets for
  *	the @target process.  The hook may also perform permission checking to
@@ -1352,6 +1356,7 @@
 	int (*ptrace_access_check)(struct task_struct *child,
 					unsigned int mode);
 	int (*ptrace_traceme)(struct task_struct *parent);
+	int (*usb_device_auth)(const struct usb_device *udev);
 	int (*capget)(struct task_struct *target, kernel_cap_t *effective,
 			kernel_cap_t *inheritable, kernel_cap_t *permitted);
 	int (*capset)(struct cred *new, const struct cred *old,
@@ -1670,6 +1675,7 @@ struct security_hook_heads {
 	struct list_head binder_transfer_file;
 	struct list_head ptrace_access_check;
 	struct list_head ptrace_traceme;
+	struct list_head usb_device_auth;
 	struct list_head capget;
 	struct list_head capset;
 	struct list_head capable;
diff --git a/include/linux/security.h b/include/linux/security.h
index af675b5..19bc364 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -30,6 +30,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
+#include <linux/usb.h>
 
 struct linux_binprm;
 struct cred;
@@ -196,6 +197,7 @@ int security_binder_transfer_file(struct task_struct *from,
 				  struct task_struct *to, struct file *file);
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
 int security_ptrace_traceme(struct task_struct *parent);
+int security_usb_device_auth(const struct usb_device *udev);
 int security_capget(struct task_struct *target,
 		    kernel_cap_t *effective,
 		    kernel_cap_t *inheritable,
@@ -434,6 +436,11 @@ static inline int security_ptrace_traceme(struct task_struct *parent)
 	return cap_ptrace_traceme(parent);
 }
 
+static inline int security_usb_device_auth(const struct usb_device *udev)
+{
+	return 0;
+}
+
 static inline int security_capget(struct task_struct *target,
 				   kernel_cap_t *effective,
 				   kernel_cap_t *inheritable,
diff --git a/security/security.c b/security/security.c
index 42c8028..e390f99 100644
--- a/security/security.c
+++ b/security/security.c
@@ -214,6 +214,11 @@ int security_ptrace_traceme(struct task_struct *parent)
 	return call_int_hook(ptrace_traceme, 0, parent);
 }
 
+int security_usb_device_auth(const struct usb_device *udev)
+{
+	return call_int_hook(usb_device_auth, 0, udev);
+}
+
 int security_capget(struct task_struct *target,
 		     kernel_cap_t *effective,
 		     kernel_cap_t *inheritable,
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1664123 — Re: [PATCH 03/11] Creation of "usb_device_auth" LSM hook

FromKrzysztof Opasiak <k.opasiak@samsung.com>
Date2017-06-12 19:40 +0200
SubjectRe: [PATCH 03/11] Creation of "usb_device_auth" LSM hook
Message-ID<tRBtN-56r-31@gated-at.bofh.it>
In reply to#1664006
Hi,

On 06/12/2017 06:56 PM, Salvatore Mesoraca wrote:
> Creation of a new LSM hook that can be used to authorize or deauthorize
> new USB devices via the usb authorization interface.
> The same hook can also prevent the authorization of a USB device via
> "/sys/bus/usb/devices/DEVICE/authorized".
> Using this hook an LSM could provide an higher level of granularity
> than the current authorization interface.
>

Could you please explain me why we need LSM for this?

There are tools like usbguard[1] and as far as I can tell it looks like 
they can do everything for you...
Without kernel modification...
without matching and storing rules inside kernel..
just pure userspace which uses device/interface authorization

Footnote:
1 - https://dkopecek.github.io/usbguard/

Best regards,
-- 
Krzysztof Opasiak
Samsung R&D Institute Poland
Samsung Electronics

[toc] | [prev] | [next] | [standalone]


#1664560 — Re: [PATCH 03/11] Creation of "usb_device_auth" LSM hook

FromSalvatore Mesoraca <s.mesoraca16@gmail.com>
Date2017-06-13 09:50 +0200
SubjectRe: [PATCH 03/11] Creation of "usb_device_auth" LSM hook
Message-ID<tROKl-59U-9@gated-at.bofh.it>
In reply to#1664123
2017-06-12 19:35 GMT+02:00 Krzysztof Opasiak <k.opasiak@samsung.com>:
> Could you please explain me why we need LSM for this?
>
> There are tools like usbguard[1] and as far as I can tell it looks like they
> can do everything for you...

I have to admit that this is the first time I read about usbguard and it made
me realize that this feature can be implemented in userspace, so no need
to modify the kernel. :)
You are right.

Thank you very much for taking the time to answer me.

[toc] | [prev] | [next] | [standalone]


#1664194 — Re: [PATCH 03/11] Creation of "usb_device_auth" LSM hook

FromGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Date2017-06-12 21:40 +0200
SubjectRe: [PATCH 03/11] Creation of "usb_device_auth" LSM hook
Message-ID<tRDlU-6p8-21@gated-at.bofh.it>
In reply to#1664006
On Mon, Jun 12, 2017 at 06:56:52PM +0200, Salvatore Mesoraca wrote:
> Creation of a new LSM hook that can be used to authorize or deauthorize
> new USB devices via the usb authorization interface.
> The same hook can also prevent the authorization of a USB device via
> "/sys/bus/usb/devices/DEVICE/authorized".
> Using this hook an LSM could provide an higher level of granularity
> than the current authorization interface.
> 
> Signed-off-by: Salvatore Mesoraca <s.mesoraca16@gmail.com>
> Cc: linux-usb@vger.kernel.org
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

No, like Krzysztof said, you can already do this today, just fine, from
userspace.  I think that support has been there for over a decade now,
why are you not taking advantage of this already?

No need to add extra stuff to the kernel at all to do this, sorry you
implemented all of this for no reason :(

greg k-h

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | linux.kernel


csiph-web