Skip to contentSkip to conversation

LSM: Stacking for major security modules - Based on 4.14-rc2

PATCH New Casey Schaufler 6 participants 27 messages Oct 27, 2017 – Dec 5, 2017

Subsystems (23)
lore
Share & tools
lore

Casey Schaufler

author maintainer
#0 lore raw

cover LSM: Stacking for major security modules - Based on 4.14-rc2

Subject: [PATCH 0/9] LSM: Stacking for major security modules - Based on 4.14-rc2

This patch set implements stacking for "major" security modules. A major security module is any that uses security blobs. Management of security blobs is moved from the security modules and into the LSM infrastructure. This has been proposed in the past by Serge Hallyn and David Howells. This implementation owes much to their work.

The use of secids has been changed. Within a security module the meaning is the same as before. At the security module interface the module specific values are mapped into a "token", which is used outside the modules. The "tokens" are translated into individual secids for consumption by the security modules as required. The mechanism for mapping (in security/stacking.c) provided has known issues (To quote Stephen. "-ENOLOCKING") and any and all suggestions on how to do it correctly are solicited.

Subdirectories in /proc/.../attr for each security module that uses the /proc/.../attr interface are provided. This will allow user-space to disambiguate the data coming from "current". Previous versions of this work included a "context" entry, but feedback on that interface is that it is unnecessary.

A new sockopt, SO_LSMSEC, is introduced to allow an application to specify which security module data will be presented by SO_PEERSEC.

Some filesystems, including kernfs, use security context strings to represent the security attributes on a file. To accommodate multiple active modules a security "context" is defined to use a regular format:

	lsmname='lsmvalue'[,lsmname='lsmvalue']...

This format is not exposed outside the kernel.

I have tested these patches in various configurations of Ubuntu and Fedora. Smack and SELinux together pass test suites with some exceptions. There are conflicts with the way the modules treat network configurations. These conflicts are under investigation, and changes to Smack (and possibly SELinux) to reconcile the worst of the issues are in development.

An earlier version of parts of this set are being used in Ubuntu 17.10. Changes made there have not been incorporated here. That's a timing issue, not a judgement on those updates.

This series can be found at:

	git://github.com/cschaufler/smack-next#stacking-4.14-rc2
---
 Documentation/admin-guide/LSM/index.rst |   23 +-
 arch/alpha/include/uapi/asm/socket.h    |    2 +
 arch/frv/include/uapi/asm/socket.h      |    2 +
 arch/ia64/include/uapi/asm/socket.h     |    2 +
 arch/m32r/include/uapi/asm/socket.h     |    2 +
 arch/mips/include/uapi/asm/socket.h     |    2 +
 arch/mn10300/include/uapi/asm/socket.h  |    2 +
 arch/parisc/include/uapi/asm/socket.h   |    2 +
 arch/s390/include/uapi/asm/socket.h     |    2 +
 arch/sparc/include/uapi/asm/socket.h    |    2 +
 arch/xtensa/include/uapi/asm/socket.h   |    2 +
 fs/btrfs/super.c                        |   10 +-
 fs/proc/base.c                          |   92 ++-
 fs/proc/internal.h                      |    1 +
 fs/xattr.c                              |    2 +-
 include/linux/lsm_hooks.h               |   69 +-
 include/linux/security.h                |  103 ++-
 include/net/request_sock.h              |    2 +
 include/net/scm.h                       |    3 +-
 include/uapi/asm-generic/socket.h       |    2 +
 kernel/audit.c                          |   16 +-
 kernel/auditsc.c                        |    4 +-
 kernel/cred.c                           |   15 +-
 net/core/sock.c                         |    4 +
 net/ipv4/ip_sockglue.c                  |    8 +-
 net/netfilter/nf_conntrack_netlink.c    |    9 +-
 net/netfilter/nf_conntrack_standalone.c |    2 +-
 net/netfilter/nfnetlink_queue.c         |    3 +-
 net/netfilter/xt_SECMARK.c              |    2 +-
 net/netlabel/netlabel_unlabeled.c       |   12 +-
 net/netlabel/netlabel_user.c            |    2 +-
 security/Kconfig                        |   67 ++
 security/Makefile                       |    1 +
 security/apparmor/context.c             |    2 -
 security/apparmor/include/context.h     |   24 +-
 security/apparmor/include/file.h        |    2 +-
 security/apparmor/include/net.h         |    6 +
 security/apparmor/lsm.c                 |   91 +--
 security/security.c                     | 1136 +++++++++++++++++++++++++++++--
 security/selinux/hooks.c                |  615 +++++++----------
 security/selinux/include/objsec.h       |   87 ++-
 security/selinux/include/xfrm.h         |    2 +-
 security/selinux/netlabel.c             |   15 +-
 security/selinux/selinuxfs.c            |    5 +-
 security/selinux/ss/services.c          |    3 +-
 security/selinux/xfrm.c                 |   10 +-
 security/smack/smack.h                  |  101 ++-
 security/smack/smack_access.c           |    2 +-
 security/smack/smack_lsm.c              |  608 ++++++-----------
 security/smack/smack_netfilter.c        |   14 +-
 security/smack/smackfs.c                |   18 +-
 security/stacking.c                     |  188 +++++
 security/tomoyo/common.h                |   30 +-
 security/tomoyo/domain.c                |    4 +-
 security/tomoyo/securityfs_if.c         |   13 +-
 security/tomoyo/tomoyo.c                |   52 +-
 56 files changed, 2475 insertions(+), 1025 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#1 lore raw

PATCH 1/9 procfs: add smack subdir to attrs

Subject: [PATCH 1/9] procfs: add smack subdir to attrs

Back in 2007 I made what turned out to be a rather serious mistake in the implementation of the Smack security module. The SELinux module used an interface in /proc to manipulate the security context on processes. Rather than use a similar interface, I used the same interface. The AppArmor team did likewise. Now /proc/.../attr/current will tell you the security "context" of the process, but it will be different depending on the security module you're using.

This patch provides a subdirectory in /proc/.../attr for Smack. Smack user space can use the "current" file in this subdirectory and never have to worry about getting SELinux attributes by mistake. Programs that use the old interface will continue to work (or fail, as the case may be) as before.

The original implementation is by Kees Cook.

---
 Documentation/admin-guide/LSM/index.rst | 13 +++++--
 fs/proc/base.c                          | 63 ++++++++++++++++++++++++++++-----
 fs/proc/internal.h                      |  1 +
 include/linux/security.h                | 15 +++++---
 security/security.c                     | 24 ++++++++++---
 5 files changed, 95 insertions(+), 21 deletions(-)
Documentation/admin-guide/LSM/index.rst +10 -3
index c980dfe9abf1..9842e21afd4a 100644
@@ -17,9 +17,8 @@ MAC extensions, other extensions can be built using the LSM to provide
 specific changes to system operation when these tweaks are not available
 in the core functionality of Linux itself.
 
-Without a specific LSM built into the kernel, the default LSM will be the
-Linux capabilities system. Most LSMs choose to extend the capabilities
-system, building their checks on top of the defined capability hooks.
+The Linux capabilities modules will always be included. This may be
+followed by any number of "minor" modules and at most one "major" module.
 For more details on capabilities, see ``capabilities(7)`` in the Linux
 man-pages project.
 
@@ -30,6 +29,14 @@ order in which checks are made. The capability module will always
 be first, followed by any "minor" modules (e.g. Yama) and then
 the one "major" module (e.g. SELinux) if there is one configured.
 
+Process attributes associated with "major" security modules should
+be accessed and maintained using the special files in ``/proc/.../attr``.
+A security module may maintain a module specific subdirectory there,
+named after the module. ``/proc/.../attr/smack`` is provided by the Smack
+security module and contains all its special files. The files directly
+in ``/proc/.../attr`` remain as legacy interfaces for modules that provide
+subdirectories.
+
 .. toctree::
    :maxdepth: 1
 
fs/proc/base.c +54 -9

90 lines not on this page · raw message

fs/proc/internal.h +1 -0
index a34195e92b20..758e32874444 100644
@@ -58,6 +58,7 @@ union proc_op {
 	int (*proc_show)(struct seq_file *m,
 		struct pid_namespace *ns, struct pid *pid,
 		struct task_struct *task);
+	const char *lsm;
 };
 
 struct proc_inode {
include/linux/security.h +10 -5
index ce6265960d6c..46ec92658ad3 100644
@@ -375,8 +375,10 @@ int security_sem_semctl(struct sem_array *sma, int cmd);
 int security_sem_semop(struct sem_array *sma, struct sembuf *sops,
 			unsigned nsops, int alter);
 void security_d_instantiate(struct dentry *dentry, struct inode *inode);
-int security_getprocattr(struct task_struct *p, char *name, char **value);
-int security_setprocattr(const char *name, void *value, size_t size);
+int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
+			 char **value);
+int security_setprocattr(const char *lsm, const char *name, void *value,
+			 size_t size);
 int security_netlink_send(struct sock *sk, struct sk_buff *skb);
 int security_ismaclabel(const char *name);
 int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
@@ -1128,15 +1130,18 @@ static inline int security_sem_semop(struct sem_array *sma,
 	return 0;
 }
 
-static inline void security_d_instantiate(struct dentry *dentry, struct inode *inode)
+static inline void security_d_instantiate(struct dentry *dentry,
+					  struct inode *inode)
 { }
 
-static inline int security_getprocattr(struct task_struct *p, char *name, char **value)
+static inline int security_getprocattr(struct task_struct *p, const char *lsm,
+				       char *name, char **value)
 {
 	return -EINVAL;
 }
 
-static inline int security_setprocattr(char *name, void *value, size_t size)
+static inline int security_setprocattr(const char *lsm, char *name,
+				       void *value, size_t size)
 {
 	return -EINVAL;
 }
security/security.c +20 -4
index 4bf0f571b4ef..49a069bb76da 100644
@@ -1253,14 +1253,30 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
 }
 EXPORT_SYMBOL(security_d_instantiate);
 
-int security_getprocattr(struct task_struct *p, char *name, char **value)
+int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
+				char **value)
 {
-	return call_int_hook(getprocattr, -EINVAL, p, name, value);
+	struct security_hook_list *hp;
+
+	list_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
+		if (lsm != NULL && strcmp(lsm, hp->lsm))
+			continue;
+		return hp->hook.getprocattr(p, name, value);
+	}
+	return -EINVAL;
 }
 
-int security_setprocattr(const char *name, void *value, size_t size)
+int security_setprocattr(const char *lsm, const char *name, void *value,
+			 size_t size)
 {
-	return call_int_hook(setprocattr, -EINVAL, name, value, size);
+	struct security_hook_list *hp;
+
+	list_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
+		if (lsm != NULL && strcmp(lsm, hp->lsm))
+			continue;
+		return hp->hook.setprocattr(name, value, size);
+	}
+	return -EINVAL;
 }
 
 int security_netlink_send(struct sock *sk, struct sk_buff *skb)
Signature · 7 lines
2.13.0


--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
author maintainer
#2 lore raw

PATCH 2/9 LSM: Manage credential security blobs

In reply to Casey Schaufler

Subject: [PATCH 2/9] LSM: Manage credential security blobs

Move the management of credential security blobs from the individual security modules to the security infrastructure. The security modules using credential blobs have been updated accordingly. Modules are required to identify the space they require at module initialization. In some cases a module no longer needs to supply a blob management hook, in which case the hook has been removed.

---
 include/linux/lsm_hooks.h           |  14 ++++
 kernel/cred.c                       |  13 ----
 security/Kconfig                    |  11 +++
 security/apparmor/context.c         |   2 -
 security/apparmor/include/context.h |   9 ++-
 security/apparmor/lsm.c             |  44 +++++-------
 security/security.c                 |  98 ++++++++++++++++++++++++++-
 security/selinux/hooks.c            | 113 ++++++++++++-------------------
 security/selinux/include/objsec.h   |   9 +++
 security/selinux/selinuxfs.c        |   1 +
 security/selinux/xfrm.c             |   4 +-
 security/smack/smack.h              |  15 ++++-
 security/smack/smack_access.c       |   2 +-
 security/smack/smack_lsm.c          | 130 +++++++++++++++---------------------
 security/smack/smackfs.c            |  18 ++---
 security/tomoyo/common.h            |  20 +++++-
 security/tomoyo/domain.c            |   4 +-
 security/tomoyo/securityfs_if.c     |  13 ++--
 security/tomoyo/tomoyo.c            |  49 +++++++++++---
 19 files changed, 343 insertions(+), 226 deletions(-)
include/linux/lsm_hooks.h +14 -0
index c9258124e417..ee4fcc51fa91 100644
@@ -1915,6 +1915,13 @@ struct security_hook_list {
 } __randomize_layout;
 
 /*
+ * Security blob size or offset data.
+ */
+struct lsm_blob_sizes {
+	int	lbs_cred;
+};
+
+/*
  * Initializing a security_hook_list structure takes
  * up a lot of space in a source file. This macro takes
  * care of the common case and reduces the amount of
@@ -1926,6 +1933,7 @@ struct security_hook_list {
 extern struct security_hook_heads security_hook_heads;
 extern char *lsm_names;
 
+extern void security_add_blobs(struct lsm_blob_sizes *needed);
 extern void security_add_hooks(struct security_hook_list *hooks, int count,
 				char *lsm);
 
@@ -1972,4 +1980,10 @@ void __init loadpin_add_hooks(void);
 static inline void loadpin_add_hooks(void) { };
 #endif
 
+extern int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
+
+#ifdef CONFIG_SECURITY
+void lsm_early_cred(struct cred *cred);
+#endif
+
 #endif /* ! __LINUX_LSM_HOOKS_H */
kernel/cred.c +0 -13
index ecf03657e71c..fa2061ee4955 100644
@@ -704,19 +704,6 @@ bool creds_are_invalid(const struct cred *cred)
 {
 	if (cred->magic != CRED_MAGIC)
 		return true;
-#ifdef CONFIG_SECURITY_SELINUX
-	/*
-	 * cred->security == NULL if security_cred_alloc_blank() or
-	 * security_prepare_creds() returned an error.
-	 */
-	if (selinux_is_enabled() && cred->security) {
-		if ((unsigned long) cred->security < PAGE_SIZE)
-			return true;
-		if ((*(u32 *)cred->security & 0xffffff00) ==
-		    (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))
-			return true;
-	}
-#endif
 	return false;
 }
 EXPORT_SYMBOL(creds_are_invalid);
security/Kconfig +11 -0
index e8e449444e65..f3464fb5a8b0 100644
@@ -36,6 +36,17 @@ config SECURITY_WRITABLE_HOOKS
 	bool
 	default n
 
+config SECURITY_LSM_DEBUG
+	bool "Enable debugging of the LSM infrastructure"
+	depends on SECURITY
+	help
+	  This allows you to choose debug messages related to
+	  security modules configured into your kernel. These
+	  messages may be helpful in determining how a security
+	  module is using security blobs.
+
+	  If you are unsure how to answer this question, answer N.
+
 config SECURITYFS
 	bool "Enable the securityfs filesystem"
 	help
security/apparmor/context.c +0 -2
index c95f1ac6190b..db203ee24db8 100644
@@ -50,8 +50,6 @@ void aa_free_task_context(struct aa_task_ctx *ctx)
 		aa_put_label(ctx->label);
 		aa_put_label(ctx->previous);
 		aa_put_label(ctx->onexec);
-
-		kzfree(ctx);
 	}
 }
 
security/apparmor/include/context.h +7 -2
index 6ae07e9aaa17..301ab3a0dd04 100644
@@ -18,11 +18,12 @@
 #include <linux/cred.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/lsm_hooks.h>
 
 #include "label.h"
 #include "policy_ns.h"
 
-#define cred_ctx(X) ((X)->security)
+#define cred_ctx(X) apparmor_cred(X)
 #define current_ctx() cred_ctx(current_cred())
 
 /**
@@ -54,6 +55,10 @@ int aa_set_current_hat(struct aa_label *label, u64 token);
 int aa_restore_previous_label(u64 cookie);
 struct aa_label *aa_get_task_label(struct task_struct *task);
 
+static inline struct aa_task_ctx *apparmor_cred(const struct cred *cred)
+{
+	return cred->security;
+}
 
 /**
  * aa_cred_raw_label - obtain cred's label
@@ -65,7 +70,7 @@ struct aa_label *aa_get_task_label(struct task_struct *task);
  */
 static inline struct aa_label *aa_cred_raw_label(const struct cred *cred)
 {
-	struct aa_task_ctx *ctx = cred_ctx(cred);
+	struct aa_task_ctx *ctx = apparmor_cred(cred);
 
 	AA_BUG(!ctx || !ctx->label);
 	return ctx->label;
security/apparmor/lsm.c +15 -29

84 lines not on this page · raw message

security/security.c +97 -1

135 lines not on this page · raw message

security/selinux/hooks.c +42 -71

294 lines not on this page · raw message

security/selinux/include/objsec.h +9 -0
index 1649cd18eb0b..c0bdb7232f39 100644
@@ -25,6 +25,9 @@
 #include <linux/binfmts.h>
 #include <linux/in.h>
 #include <linux/spinlock.h>
+#include <linux/lsm_hooks.h>
+#include <linux/msg.h>
+#include <net/sock.h>
 #include <net/net_namespace.h>
 #include "flask.h"
 #include "avc.h"
@@ -151,5 +154,11 @@ struct pkey_security_struct {
 };
 
 extern unsigned int selinux_checkreqprot;
+extern struct lsm_blob_sizes selinux_blob_sizes;
+
+static inline struct task_security_struct *selinux_cred(const struct cred *cred)
+{
+	return cred->security;
+}
 
 #endif /* _SELINUX_OBJSEC_H_ */
security/selinux/selinuxfs.c +1 -0
index 00eed842c491..855a13053a81 100644
@@ -30,6 +30,7 @@
 #include <linux/uaccess.h>
 #include <linux/kobject.h>
 #include <linux/ctype.h>
+#include <linux/lsm_hooks.h>
 
 /* selinuxfs pseudo filesystem for exporting the security policy API.
    Based on the proc code and the fs/nfsd/nfsctl.c code. */
security/selinux/xfrm.c +2 -2
index 56e354fcdfc6..789d07bd900f 100644
@@ -79,7 +79,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
 				   gfp_t gfp)
 {
 	int rc;
-	const struct task_security_struct *tsec = current_security();
+	const struct task_security_struct *tsec = selinux_cred(current_cred());
 	struct xfrm_sec_ctx *ctx = NULL;
 	u32 str_len;
 
@@ -136,7 +136,7 @@ static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx)
  */
 static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
 {
-	const struct task_security_struct *tsec = current_security();
+	const struct task_security_struct *tsec = selinux_cred(current_cred());
 
 	if (!ctx)
 		return 0;
security/smack/smack.h +12 -3
index 6a71fc7831ab..ab1d217800e2 100644
@@ -24,6 +24,7 @@
 #include <linux/list.h>
 #include <linux/rculist.h>
 #include <linux/lsm_audit.h>
+#include <linux/msg.h>
 
 /*
  * Use IPv6 port labeling if IPv6 is enabled and secmarks
@@ -355,6 +356,11 @@ extern struct list_head smack_onlycap_list;
 #define SMACK_HASH_SLOTS 16
 extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
 
+static inline struct task_smack *smack_cred(const struct cred *cred)
+{
+	return cred->security;
+}
+
 /*
  * Is the directory transmuting?
  */
@@ -381,13 +387,16 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp)
 	return tsp->smk_task;
 }
 
-static inline struct smack_known *smk_of_task_struct(const struct task_struct *t)
+static inline struct smack_known *smk_of_task_struct(
+						const struct task_struct *t)
 {
 	struct smack_known *skp;
+	const struct cred *cred;
 
 	rcu_read_lock();
-	skp = smk_of_task(__task_cred(t)->security);
+	cred = __task_cred(t);
 	rcu_read_unlock();
+	skp = smk_of_task(smack_cred(cred));
 	return skp;
 }
 
@@ -404,7 +413,7 @@ static inline struct smack_known *smk_of_forked(const struct task_smack *tsp)
  */
 static inline struct smack_known *smk_of_current(void)
 {
-	return smk_of_task(current_security());
+	return smk_of_task(smack_cred(current_cred()));
 }
 
 /*
security/smack/smack_access.c +1 -1
index 1a3004189447..e1d304c65fe3 100644
@@ -275,7 +275,7 @@ int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known,
 int smk_curacc(struct smack_known *obj_known,
 	       u32 mode, struct smk_audit_info *a)
 {
-	struct task_smack *tsp = current_security();
+	struct task_smack *tsp = smack_cred(current_cred());
 
 	return smk_tskacc(tsp, obj_known, mode, a);
 }
security/smack/smack_lsm.c +53 -77

333 lines not on this page · raw message

security/smack/smackfs.c +9 -9
index f6482e53d55a..9d2dde608298 100644
@@ -2208,14 +2208,14 @@ static const struct file_operations smk_logging_ops = {
 
 static void *load_self_seq_start(struct seq_file *s, loff_t *pos)
 {
-	struct task_smack *tsp = current_security();
+	struct task_smack *tsp = smack_cred(current_cred());
 
 	return smk_seq_start(s, pos, &tsp->smk_rules);
 }
 
 static void *load_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-	struct task_smack *tsp = current_security();
+	struct task_smack *tsp = smack_cred(current_cred());
 
 	return smk_seq_next(s, v, pos, &tsp->smk_rules);
 }
@@ -2262,7 +2262,7 @@ static int smk_open_load_self(struct inode *inode, struct file *file)
 static ssize_t smk_write_load_self(struct file *file, const char __user *buf,
 			      size_t count, loff_t *ppos)
 {
-	struct task_smack *tsp = current_security();
+	struct task_smack *tsp = smack_cred(current_cred());
 
 	return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules,
 				    &tsp->smk_rules_lock, SMK_FIXED24_FMT);
@@ -2414,14 +2414,14 @@ static const struct file_operations smk_load2_ops = {
 
 static void *load_self2_seq_start(struct seq_file *s, loff_t *pos)
 {
-	struct task_smack *tsp = current_security();
+	struct task_smack *tsp = smack_cred(current_cred());
 
 	return smk_seq_start(s, pos, &tsp->smk_rules);
 }
 
 static void *load_self2_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-	struct task_smack *tsp = current_security();
+	struct task_smack *tsp = smack_cred(current_cred());
 
 	return smk_seq_next(s, v, pos, &tsp->smk_rules);
 }
@@ -2467,7 +2467,7 @@ static int smk_open_load_self2(struct inode *inode, struct file *file)
 static ssize_t smk_write_load_self2(struct file *file, const char __user *buf,
 			      size_t count, loff_t *ppos)
 {
-	struct task_smack *tsp = current_security();
+	struct task_smack *tsp = smack_cred(current_cred());
 
 	return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules,
 				    &tsp->smk_rules_lock, SMK_LONG_FMT);
@@ -2681,14 +2681,14 @@ static const struct file_operations smk_syslog_ops = {
 
 static void *relabel_self_seq_start(struct seq_file *s, loff_t *pos)
 {
-	struct task_smack *tsp = current_security();
+	struct task_smack *tsp = smack_cred(current_cred());
 
 	return smk_seq_start(s, pos, &tsp->smk_relabel);
 }
 
 static void *relabel_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-	struct task_smack *tsp = current_security();
+	struct task_smack *tsp = smack_cred(current_cred());
 
 	return smk_seq_next(s, v, pos, &tsp->smk_relabel);
 }
@@ -2736,7 +2736,7 @@ static int smk_open_relabel_self(struct inode *inode, struct file *file)
 static ssize_t smk_write_relabel_self(struct file *file, const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	struct task_smack *tsp = current_security();
+	struct task_smack *tsp = smack_cred(current_cred());
 	char *data;
 	int rc;
 	LIST_HEAD(list_tmp);
security/tomoyo/common.h +18 -2
index 361e7a284699..cbcfccc84784 100644
@@ -28,6 +28,7 @@
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/un.h>
+#include <linux/lsm_hooks.h>
 #include <net/sock.h>
 #include <net/af_unix.h>
 #include <net/ip.h>
@@ -1196,13 +1197,26 @@ static inline void tomoyo_put_group(struct tomoyo_group *group)
 }
 
 /**
+ * tomoyo_cred - Get a pointer to the tomoyo cred security blob
+ * @cred - the relevant cred
+ *
+ * Returns pointer to the tomoyo cred blob.
+ */
+static inline struct tomoyo_domain_info **tomoyo_cred(const struct cred *cred)
+{
+	return cred->security;
+}
+
+/**
  * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread.
  *
  * Returns pointer to "struct tomoyo_domain_info" for current thread.
  */
 static inline struct tomoyo_domain_info *tomoyo_domain(void)
 {
-	return current_cred()->security;
+	struct tomoyo_domain_info **blob = tomoyo_cred(current_cred());
+
+	return *blob;
 }
 
 /**
@@ -1215,7 +1229,9 @@ static inline struct tomoyo_domain_info *tomoyo_domain(void)
 static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
 							    *task)
 {
-	return task_cred_xxx(task, security);
+	struct tomoyo_domain_info **blob = tomoyo_cred(get_task_cred(task));
+
+	return *blob;
 }
 
 /**
security/tomoyo/domain.c +3 -1
index 00d223e9fb37..80ebb422c02b 100644
@@ -677,6 +677,7 @@ static int tomoyo_environ(struct tomoyo_execve *ee)
  */
 int tomoyo_find_next_domain(struct linux_binprm *bprm)
 {
+	struct tomoyo_domain_info **blob;
 	struct tomoyo_domain_info *old_domain = tomoyo_domain();
 	struct tomoyo_domain_info *domain = NULL;
 	const char *original_name = bprm->filename;
@@ -842,7 +843,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
 		domain = old_domain;
 	/* Update reference count on "struct tomoyo_domain_info". */
 	atomic_inc(&domain->users);
-	bprm->cred->security = domain;
+	blob = tomoyo_cred(bprm->cred);
+	*blob = domain;
 	kfree(exename.name);
 	if (!retval) {
 		ee->r.domain = domain;
security/tomoyo/securityfs_if.c +9 -4
index 06ab41b1ff28..9289f2a16036 100644
@@ -70,9 +70,12 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
 				if (!cred) {
 					error = -ENOMEM;
 				} else {
-					struct tomoyo_domain_info *old_domain =
-						cred->security;
-					cred->security = new_domain;
+					struct tomoyo_domain_info **blob;
+					struct tomoyo_domain_info *old_domain;
+
+					blob = tomoyo_cred(cred);
+					old_domain = *blob;
+					*blob = new_domain;
 					atomic_inc(&new_domain->users);
 					atomic_dec(&old_domain->users);
 					commit_creds(cred);
@@ -233,10 +236,12 @@ static void __init tomoyo_create_entry(const char *name, const umode_t mode,
  */
 static int __init tomoyo_initerface_init(void)
 {
+	struct tomoyo_domain_info *domain;
 	struct dentry *tomoyo_dir;
 
+	domain = tomoyo_domain();
 	/* Don't create securityfs entries unless registered. */
-	if (current_cred()->security != &tomoyo_kernel_domain)
+	if (domain != &tomoyo_kernel_domain)
 		return 0;
 
 	tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
security/tomoyo/tomoyo.c +40 -9

109 lines not on this page · raw message

Signature · 7 lines
2.13.0


--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
author maintainer
#3 lore raw

PATCH 3/9 LSM: Manage file security blobs

In reply to Casey Schaufler

Subject: [PATCH 3/9] LSM: Manage file security blobs

Move the management of file security blobs from the individual security modules to the security infrastructure. The security modules using file blobs have been updated accordingly. Modules are required to identify the space they need at module initialization. In some cases a module no longer needs to supply a blob management hook, in which case the hook has been removed.

---
 include/linux/lsm_hooks.h           |  1 +
 security/apparmor/include/context.h |  5 +++++
 security/apparmor/include/file.h    |  2 +-
 security/apparmor/lsm.c             | 19 ++++++++--------
 security/security.c                 | 43 +++++++++++++++++++++++++++++++++++++
 security/selinux/hooks.c            | 41 +++++++++--------------------------
 security/selinux/include/objsec.h   |  5 +++++
 security/smack/smack.h              |  5 +++++
 security/smack/smack_lsm.c          | 26 ++++++++--------------
 9 files changed, 89 insertions(+), 58 deletions(-)
include/linux/lsm_hooks.h +1 -0
index ee4fcc51fa91..e5d0f1e01b81 100644
@@ -1919,6 +1919,7 @@ struct security_hook_list {
  */
 struct lsm_blob_sizes {
 	int	lbs_cred;
+	int	lbs_file;
 };
 
 /*
security/apparmor/include/context.h +5 -0
index 301ab3a0dd04..c6e106a533e8 100644
@@ -87,6 +87,11 @@ static inline struct aa_label *aa_get_newest_cred_label(const struct cred *cred)
 	return aa_get_newest_label(aa_cred_raw_label(cred));
 }
 
+static inline struct aa_file_ctx *apparmor_file(const struct file *file)
+{
+	return file->f_security;
+}
+
 /**
  * __aa_task_raw_label - retrieve another task's label
  * @task: task to query  (NOT NULL)
security/apparmor/include/file.h +1 -1
index 4c2c8ac8842f..b9efe6bc226b 100644
@@ -32,7 +32,7 @@ struct path;
 				 AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
 				 AA_EXEC_MMAP | AA_MAY_LINK)
 
-#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
+#define file_ctx(X) apparmor_file(X)
 
 /* struct aa_file_ctx - the AppArmor context the file was opened in
  * @lock: lock to update the ctx
security/apparmor/lsm.c +10 -9
index d80293bde5bf..f2814ba84481 100644
@@ -402,21 +402,21 @@ static int apparmor_file_open(struct file *file, const struct cred *cred)
 
 static int apparmor_file_alloc_security(struct file *file)
 {
-	int error = 0;
-
-	/* freed by apparmor_file_free_security */
+	struct aa_file_ctx *ctx = file_ctx(file);
 	struct aa_label *label = begin_current_label_crit_section();
-	file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL);
-	if (!file_ctx(file))
-		error = -ENOMEM;
-	end_current_label_crit_section(label);
 
-	return error;
+	spin_lock_init(&ctx->lock);
+	rcu_assign_pointer(ctx->label, aa_get_label(label));
+	end_current_label_crit_section(label);
+	return 0;
 }
 
 static void apparmor_file_free_security(struct file *file)
 {
-	aa_free_file_ctx(file_ctx(file));
+	struct aa_file_ctx *ctx = file_ctx(file);
+
+	if (ctx)
+		aa_put_label(rcu_access_pointer(ctx->label));
 }
 
 static int common_file_perm(const char *op, struct file *file, u32 mask)
@@ -1078,6 +1078,7 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
 
 struct lsm_blob_sizes apparmor_blob_sizes = {
 	.lbs_cred = sizeof(struct aa_task_ctx),
+	.lbs_file = sizeof(struct aa_file_ctx),
 };
 
 static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
security/security.c +43 -0

79 lines not on this page · raw message

security/selinux/hooks.c +10 -31

133 lines not on this page · raw message

security/selinux/include/objsec.h +5 -0
index c0bdb7232f39..504e15ed234f 100644
@@ -161,4 +161,9 @@ static inline struct task_security_struct *selinux_cred(const struct cred *cred)
 	return cred->security;
 }
 
+static inline struct file_security_struct *selinux_file(const struct file *file)
+{
+	return file->f_security;
+}
+
 #endif /* _SELINUX_OBJSEC_H_ */
security/smack/smack.h +5 -0
index ab1d217800e2..d14e8d17eea0 100644
@@ -361,6 +361,11 @@ static inline struct task_smack *smack_cred(const struct cred *cred)
 	return cred->security;
 }
 
+static inline struct smack_known **smack_file(const struct file *file)
+{
+	return file->f_security;
+}
+
 /*
  * Is the directory transmuting?
  */
security/smack/smack_lsm.c +9 -17
index ff4e5c632410..a807624aff9a 100644
@@ -1575,25 +1575,13 @@ static void smack_inode_getsecid(struct inode *inode, u32 *secid)
  */
 static int smack_file_alloc_security(struct file *file)
 {
-	struct smack_known *skp = smk_of_current();
+	struct smack_known **blob = smack_file(file);
 
-	file->f_security = skp;
+	*blob = smk_of_current();
 	return 0;
 }
 
 /**
- * smack_file_free_security - clear a file security blob
- * @file: the object
- *
- * The security blob for a file is a pointer to the master
- * label list, so no memory is freed.
- */
-static void smack_file_free_security(struct file *file)
-{
-	file->f_security = NULL;
-}
-
-/**
  * smack_file_ioctl - Smack check on ioctls
  * @file: the object
  * @cmd: what to do
@@ -1817,7 +1805,9 @@ static int smack_mmap_file(struct file *file,
  */
 static void smack_file_set_fowner(struct file *file)
 {
-	file->f_security = smk_of_current();
+	struct smack_known **blob = smack_file(file);
+
+	*blob = smk_of_current();
 }
 
 /**
@@ -1834,6 +1824,7 @@ static void smack_file_set_fowner(struct file *file)
 static int smack_file_send_sigiotask(struct task_struct *tsk,
 				     struct fown_struct *fown, int signum)
 {
+	struct smack_known **blob;
 	struct smack_known *skp;
 	struct smack_known *tkp = smk_of_task(smack_cred(tsk->cred));
 	struct file *file;
@@ -1846,7 +1837,8 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
 	file = container_of(fown, struct file, f_owner);
 
 	/* we don't log here as rc can be overriden */
-	skp = file->f_security;
+	blob = smack_file(file);
+	skp = *blob;
 	rc = smk_access(skp, tkp, MAY_DELIVER, NULL);
 	rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc);
 	if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
@@ -4578,6 +4570,7 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
 
 struct lsm_blob_sizes smack_blob_sizes = {
 	.lbs_cred = sizeof(struct task_smack),
+	.lbs_file = sizeof(struct smack_known *),
 };
 
 static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
@@ -4615,7 +4608,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
 	LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid),
 
 	LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security),
-	LSM_HOOK_INIT(file_free_security, smack_file_free_security),
 	LSM_HOOK_INIT(file_ioctl, smack_file_ioctl),
 	LSM_HOOK_INIT(file_lock, smack_file_lock),
 	LSM_HOOK_INIT(file_fcntl, smack_file_fcntl),
Signature · 7 lines
2.13.0


--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#4 lore raw

PATCH 3/9 LSM: Manage file security blobs

Quoted 194 lines · Casey Schaufler

Subject: [PATCH 3/9] LSM: Manage file security blobs

Move the management of file security blobs from the individual security modules to the security infrastructure. The security modules using file blobs have been updated accordingly. Modules are required to identify the space they need at module initialization. In some cases a module no longer needs to supply a blob management hook, in which case the hook has been removed.

---

?include/linux/lsm_hooks.h???????????|??1 +
?security/apparmor/include/context.h |??5 +++++
?security/apparmor/include/file.h????|??2 +-
?security/apparmor/lsm.c?????????????| 19 ++++++++--------
?security/security.c?????????????????| 43
+++++++++++++++++++++++++++++++++++++
?security/selinux/hooks.c????????????| 41 +++++++++----------------
----------
?security/selinux/include/objsec.h???|??5 +++++
?security/smack/smack.h??????????????|??5 +++++
?security/smack/smack_lsm.c??????????| 26 ++++++++--------------

?9 files changed, 89 insertions(+), 58 deletions(-)

include/linux/lsm_hooks.h +0 -0
index ee4fcc51fa91..e5d0f1e01b81 100644
@@ -1919,6 +1919,7 @@ struct security_hook_list {

? */
?struct lsm_blob_sizes {
? int lbs_cred;

include/linux/lsm_hooks.h +1 -0
+	int	lbs_file;

?};
?
?/*

security/apparmor/include/context.h +0 -0
index 301ab3a0dd04..c6e106a533e8 100644
@@ -87,6 +87,11 @@ static inline struct aa_label
 *aa_get_newest_cred_label(const struct cred *cred)
 ?	return aa_get_newest_label(aa_cred_raw_label(cred));
 ?}

?
+static inline struct aa_file_ctx *apparmor_file(const struct file *file)

security/apparmor/include/context.h +4 -0
+{
+	return file->f_security;
+}
+

?/**
? * __aa_task_raw_label - retrieve another task's label ? * @task: task to query??(NOT NULL)

security/apparmor/include/file.h +0 -0
index 4c2c8ac8842f..b9efe6bc226b 100644
@@ -32,7 +32,7 @@ struct path;

? ?AA_MAY_CHMOD | AA_MAY_CHOWN |
AA_MAY_LOCK | \
? ?AA_EXEC_MMAP | AA_MAY_LINK)
?

security/apparmor/include/file.h +1 -1
-#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
+#define file_ctx(X) apparmor_file(X)

?
?/* struct aa_file_ctx - the AppArmor context the file was opened in ? * @lock: lock to update the ctx

security/apparmor/lsm.c +0 -0
index d80293bde5bf..f2814ba84481 100644
@@ -402,21 +402,21 @@ static int apparmor_file_open(struct file
 *file, const struct cred *cred)

?
?static int apparmor_file_alloc_security(struct file *file) ?{

security/apparmor/lsm.c +1 -3
-	int error = 0;
-
-	/* freed by apparmor_file_free_security */
+	struct aa_file_ctx *ctx = file_ctx(file);

? struct aa_label *label = begin_current_label_crit_section();

security/apparmor/lsm.c +0 -4
-	file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL);
-	if (!file_ctx(file))
-		error = -ENOMEM;
-	end_current_label_crit_section(label);

?

security/apparmor/lsm.c +4 -1
-	return error;
+	spin_lock_init(&ctx->lock);
+	rcu_assign_pointer(ctx->label, aa_get_label(label));
+	end_current_label_crit_section(label);
+	return 0;

?}
?
?static void apparmor_file_free_security(struct file *file) ?{

security/apparmor/lsm.c +4 -1
-	aa_free_file_ctx(file_ctx(file));
+	struct aa_file_ctx *ctx = file_ctx(file);
+
+	if (ctx)
+		aa_put_label(rcu_access_pointer(ctx->label));

?}
?
?static int common_file_perm(const char *op, struct file *file, u32 mask)

security/apparmor/lsm.c +0 -0
@@ -1078,6 +1078,7 @@ static void apparmor_sock_graft(struct sock
 *sk, struct socket *parent)

?
?struct lsm_blob_sizes apparmor_blob_sizes = {
? .lbs_cred = sizeof(struct aa_task_ctx),

security/apparmor/lsm.c +1 -0
+	.lbs_file = sizeof(struct aa_file_ctx),

?};
?
?static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {

security/security.c +0 -0
index 6fadc3860fb0..4d8e702fa22f 100644
@@ -37,6 +37,8 @@
 ?struct security_hook_heads security_hook_heads __lsm_ro_after_init;
 ?static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);

?

security/security.c +2 -0
+static struct kmem_cache *lsm_file_cache;
+

?char *lsm_names;
?static struct lsm_blob_sizes blob_sizes;
?

security/security.c +0 -0
@@ -83,6 +85,13 @@ int __init security_init(void)
 ?	do_security_initcalls();

?
? /*

security/security.c +5 -0
+	?* Create any kmem_caches needed for blobs
+	?*/
+	if (blob_sizes.lbs_file)
+		lsm_file_cache = kmem_cache_create("lsm_file_cache",
+						???blob_sizes.lbs_fi

le, 0,

security/security.c +1 -0
+						???SLAB_PANIC,

NULL);

security/security.c +1 -0
+	/*

? ?* The second call to a module specific init function
? ?* adds hooks to the hook lists and does any other early
? ?* initializations required.

security/security.c +0 -0
@@ -91,6 +100,7 @@ int __init security_init(void)

?
?#ifdef CONFIG_SECURITY_LSM_DEBUG
? pr_info("LSM: cred blob size???????= %d\n",
blob_sizes.lbs_cred);

security/security.c +1 -0
+	pr_info("LSM: file blob size???????= %d\n",

blob_sizes.lbs_file);
?#endif
?
? return 0;

security/security.c +20 -0
@@ -267,6 +277,26 @@ static void __init lsm_set_size(int *need, int
 *lbs)
 ?void __init security_add_blobs(struct lsm_blob_sizes *needed)
 ?{
 ?	lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+	lsm_set_size(&needed->lbs_file, &blob_sizes.lbs_file);
+}
+
+/**
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
+ *
+ * Allocate the file blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_file_alloc(struct file *file)
+{
+	if (!lsm_file_cache)
+		return 0;
+
+	file->f_security = kmem_cache_zalloc(lsm_file_cache,
 GFP_KERNEL);
+	if (file->f_security == NULL)
+		return -ENOMEM;
+	return 0;
 ?}

?
?/*

security/security.c +0 -0
@@ -952,12 +982,25 @@ int security_file_permission(struct file *file,
 int mask)

?
?int security_file_alloc(struct file *file)
?{

security/security.c +4 -0
+	int rc = lsm_file_alloc(file);
+
+	if (rc)
+		return rc;
Quoted 1 line

? return call_int_hook(file_alloc_security, 0, file);

Suppose that a module's file_alloc_security() hook returns an error. What should happen to the blob allocated by lsm_file_alloc()? In general, callers assumes that security_file_alloc() handles cleanup internally if it returns an error and do not call security_file_free(); this is also true of other similar alloc hooks I believe. ?Further, if we allow the module file_alloc_security() hooks to perform any allocation themselves, then we have a similar problem with regard to cleanup if any one of them fails; to be fully safe, we'd need to call the file_free_security() hook on the ones that had previously returned success. Either we need to handle such errors within security_file_alloc(), or we need to dispense with the ability to allocate and return an error code from the module's file_alloc_security(), i.e. make them return void, and probably rename them to file_init_security() or similar.

Quoted 311 lines

?}
?
?void security_file_free(struct file *file)
?{

security/security.c +5 -0
+	void *blob;
+
+	if (!lsm_file_cache)
+		return;
+

? call_void_hook(file_free_security, file);

security/security.c +4 -0
+
+	blob = file->f_security;
+	file->f_security = NULL;
+	kmem_cache_free(lsm_file_cache, blob);

?}
?
?int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

security/selinux/hooks.c +0 -0
index a4d1ec236d4e..28e641f829b2 100644
@@ -129,7 +129,6 @@ int selinux_enabled = 1;

?#endif
?
?static struct kmem_cache *sel_inode_cache;
-static struct kmem_cache *file_security_cache;
?
?/**
? * selinux_secmark_enabled - Check to see if SECMARK is currently enabled

security/selinux/hooks.c +0 -0
@@ -359,27 +358,15 @@ static void inode_free_security(struct inode
 *inode)

?
?static int file_alloc_security(struct file *file) ?{

security/selinux/hooks.c +1 -1
-	struct file_security_struct *fsec;
+	struct file_security_struct *fsec = selinux_file(file);

? u32 sid = current_sid();
?

security/selinux/hooks.c +0 -4
-	fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
-	if (!fsec)
-		return -ENOMEM;
-

? fsec->sid = sid;
? fsec->fown_sid = sid;

security/selinux/hooks.c +0 -1
-	file->f_security = fsec;

?
? return 0;
?}
?

security/selinux/hooks.c +0 -7
-static void file_free_security(struct file *file)
-{
-	struct file_security_struct *fsec = file->f_security;
-	file->f_security = NULL;
-	kmem_cache_free(file_security_cache, fsec);
-}
-

?static int superblock_alloc_security(struct super_block *sb) ?{
? struct superblock_security_struct *sbsec;

security/selinux/hooks.c +1 -1
@@ -1823,7 +1810,7 @@ static int file_has_perm(const struct cred
 *cred,
 ?			?struct file *file,
 ?			?u32 av)
 ?{
-	struct file_security_struct *fsec = file->f_security;
+	struct file_security_struct *fsec = selinux_file(file);
 ?	struct inode *inode = file_inode(file);
 ?	struct common_audit_data ad;

? u32 sid = cred_sid(cred);

security/selinux/hooks.c +1 -1
@@ -2143,7 +2130,7 @@ static int selinux_binder_transfer_file(struct
 task_struct *from,
 ?					struct file *file)
 ?{
 ?	u32 sid = task_sid(to);
-	struct file_security_struct *fsec = file->f_security;
+	struct file_security_struct *fsec = selinux_file(file);
 ?	struct dentry *dentry = file->f_path.dentry;
 ?	struct inode_security_struct *isec;

? struct common_audit_data ad;

security/selinux/hooks.c +1 -1
@@ -3421,7 +3408,7 @@ static int
 selinux_revalidate_file_permission(struct file *file, int mask)
 ?static int selinux_file_permission(struct file *file, int mask)
 ?{
 ?	struct inode *inode = file_inode(file);
-	struct file_security_struct *fsec = file->f_security;
+	struct file_security_struct *fsec = selinux_file(file);
 ?	struct inode_security_struct *isec;
 ?	u32 sid = current_sid();

?

security/selinux/hooks.c +0 -0
@@ -3443,11 +3430,6 @@ static int selinux_file_alloc_security(struct
 file *file)
 ?	return file_alloc_security(file);
 ?}

?

security/selinux/hooks.c +0 -5
-static void selinux_file_free_security(struct file *file)
-{
-	file_free_security(file);
-}
-

?/*
? * Check whether a task has the ioctl permission and cmd ? * operation to an inode.

security/selinux/hooks.c +1 -1
@@ -3456,7 +3438,7 @@ static int ioctl_has_perm(const struct cred
 *cred, struct file *file,
 ?		u32 requested, u16 cmd)
 ?{
 ?	struct common_audit_data ad;
-	struct file_security_struct *fsec = file->f_security;
+	struct file_security_struct *fsec = selinux_file(file);
 ?	struct inode *inode = file_inode(file);
 ?	struct inode_security_struct *isec;

? struct lsm_ioctlop_audit ioctl;

security/selinux/hooks.c +0 -0
@@ -3702,7 +3684,7 @@ static void selinux_file_set_fowner(struct file
 *file)
 ?{
 ?	struct file_security_struct *fsec;

?

security/selinux/hooks.c +1 -1
-	fsec = file->f_security;
+	fsec = selinux_file(file);

? fsec->fown_sid = current_sid();
?}
?

security/selinux/hooks.c +0 -0
@@ -3717,7 +3699,7 @@ static int selinux_file_send_sigiotask(struct
 task_struct *tsk,

? /* struct fown_struct is never outside the context of a
struct file */
? file = container_of(fown, struct file, f_owner);
?

security/selinux/hooks.c +1 -1
-	fsec = file->f_security;
+	fsec = selinux_file(file);

?
? if (!signum)
? perm = signal_to_av(SIGIO); /* as per
send_sigio_to_task */

security/selinux/hooks.c +0 -0
@@ -3740,7 +3722,7 @@ static int selinux_file_open(struct file *file,
 const struct cred *cred)
 ?	struct file_security_struct *fsec;
 ?	struct inode_security_struct *isec;

?

security/selinux/hooks.c +1 -1
-	fsec = file->f_security;
+	fsec = selinux_file(file);

? isec = inode_security(file_inode(file));
? /*
? ?* Save inode label and policy sequence number

security/selinux/hooks.c +0 -0
@@ -3870,7 +3852,7 @@ static int
 selinux_kernel_module_from_file(struct file *file)
 ?	ad.type = LSM_AUDIT_DATA_FILE;
 ?	ad.u.file = file;

?

security/selinux/hooks.c +1 -1
-	fsec = file->f_security;
+	fsec = selinux_file(file);

? if (sid != fsec->sid) {
? rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD,
FD__USE, &ad);
? if (rc)

security/selinux/hooks.c +0 -0
@@ -6215,6 +6197,7 @@ static void selinux_ib_free_security(void
 *ib_sec)

?
?struct lsm_blob_sizes selinux_blob_sizes = {
? .lbs_cred = sizeof(struct task_security_struct),

security/selinux/hooks.c +1 -0
+	.lbs_file = sizeof(struct file_security_struct),

?};
?
?static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {

security/selinux/hooks.c +0 -0
@@ -6285,7 +6268,6 @@ static struct security_hook_list
 selinux_hooks[] __lsm_ro_after_init = {

?
? LSM_HOOK_INIT(file_permission, selinux_file_permission),
? LSM_HOOK_INIT(file_alloc_security,
selinux_file_alloc_security),

security/selinux/hooks.c +0 -1
-	LSM_HOOK_INIT(file_free_security,

selinux_file_free_security),
? LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
? LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
? LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),

security/selinux/hooks.c +0 -0
@@ -6466,9 +6448,6 @@ static __init int selinux_init(void)

? sel_inode_cache =
kmem_cache_create("selinux_inode_security",
? ????sizeof(struct
inode_security_struct),
? ????0, SLAB_PANIC, NULL);

security/selinux/hooks.c +0 -1
-	file_security_cache =

kmem_cache_create("selinux_file_security",

security/selinux/hooks.c +0 -1
-					????sizeof(struct

file_security_struct),

security/selinux/hooks.c +0 -1
-					????0, SLAB_PANIC, NULL);

? avc_init();
?
? security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks),
"selinux");

security/selinux/include/objsec.h +0 -0
index c0bdb7232f39..504e15ed234f 100644
@@ -161,4 +161,9 @@ static inline struct task_security_struct
 *selinux_cred(const struct cred *cred)
 ?	return cred->security;
 ?}

?
+static inline struct file_security_struct *selinux_file(const struct file *file)

security/selinux/include/objsec.h +4 -0
+{
+	return file->f_security;
+}
+

?#endif /* _SELINUX_OBJSEC_H_ */

security/smack/smack.h +0 -0
index ab1d217800e2..d14e8d17eea0 100644
@@ -361,6 +361,11 @@ static inline struct task_smack
 *smack_cred(const struct cred *cred)
 ?	return cred->security;
 ?}

?
+static inline struct smack_known **smack_file(const struct file *file)

security/smack/smack.h +4 -0
+{
+	return file->f_security;
+}
+

?/*
? * Is the directory transmuting?
? */

security/smack/smack_lsm.c +0 -0
index ff4e5c632410..a807624aff9a 100644
@@ -1575,25 +1575,13 @@ static void smack_inode_getsecid(struct inode
 *inode, u32 *secid)

? */
?static int smack_file_alloc_security(struct file *file) ?{

security/smack/smack_lsm.c +1 -1
-	struct smack_known *skp = smk_of_current();
+	struct smack_known **blob = smack_file(file);

?

security/smack/smack_lsm.c +1 -1
-	file->f_security = skp;
+	*blob = smk_of_current();

? return 0;
?}
?
?/**
- * smack_file_free_security - clear a file security blob
- * @file: the object
- *
- * The security blob for a file is a pointer to the master
- * label list, so no memory is freed.
- */

security/smack/smack_lsm.c +0 -6
-static void smack_file_free_security(struct file *file)
-{
-	file->f_security = NULL;
-}
-
-/**

? * smack_file_ioctl - Smack check on ioctls
? * @file: the object
? * @cmd: what to do

security/smack/smack_lsm.c +0 -0
@@ -1817,7 +1805,9 @@ static int smack_mmap_file(struct file *file,

? */
?static void smack_file_set_fowner(struct file *file) ?{

security/smack/smack_lsm.c +3 -1
-	file->f_security = smk_of_current();
+	struct smack_known **blob = smack_file(file);
+
+	*blob = smk_of_current();

?}
?
?/**

security/smack/smack_lsm.c +0 -0
@@ -1834,6 +1824,7 @@ static void smack_file_set_fowner(struct file
 *file)
 ?static int smack_file_send_sigiotask(struct task_struct *tsk,

? ?????struct fown_struct *fown, int
signum)
?{

security/smack/smack_lsm.c +1 -0
+	struct smack_known **blob;

? struct smack_known *skp;
? struct smack_known *tkp = smk_of_task(smack_cred(tsk-

Quoted 1 line

cred));

? struct file *file;

security/smack/smack_lsm.c +0 -0
@@ -1846,7 +1837,8 @@ static int smack_file_send_sigiotask(struct
 task_struct *tsk,
 ?	file = container_of(fown, struct file, f_owner);

?
? /* we don't log here as rc can be overriden */

security/smack/smack_lsm.c +2 -1
-	skp = file->f_security;
+	blob = smack_file(file);
+	skp = *blob;

? rc = smk_access(skp, tkp, MAY_DELIVER, NULL);
? rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc);
? if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))

security/smack/smack_lsm.c +0 -0
@@ -4578,6 +4570,7 @@ static int smack_inode_getsecctx(struct inode
 *inode, void **ctx, u32 *ctxlen)

?
?struct lsm_blob_sizes smack_blob_sizes = {
? .lbs_cred = sizeof(struct task_smack),

security/smack/smack_lsm.c +1 -0
+	.lbs_file = sizeof(struct smack_known *),

?};
?
?static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {

security/smack/smack_lsm.c +0 -0
@@ -4615,7 +4608,6 @@ static struct security_hook_list smack_hooks[]
 __lsm_ro_after_init = {
 ?	LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid),

?
? LSM_HOOK_INIT(file_alloc_security,
smack_file_alloc_security),

security/smack/smack_lsm.c +0 -1
-	LSM_HOOK_INIT(file_free_security, smack_file_free_security),
Quoted 3 lines

? LSM_HOOK_INIT(file_ioctl, smack_file_ioctl),
? LSM_HOOK_INIT(file_lock, smack_file_lock),
? LSM_HOOK_INIT(file_fcntl, smack_file_fcntl),

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#5 lore raw

PATCH 3/9 LSM: Manage file security blobs

Quoted 202 lines · Stephen Smalley
Quoted 194 lines · Casey Schaufler

Subject: [PATCH 3/9] LSM: Manage file security blobs

Move the management of file security blobs from the individual security modules to the security infrastructure. The security modules using file blobs have been updated accordingly. Modules are required to identify the space they need at module initialization. In some cases a module no longer needs to supply a blob management hook, in which case the hook has been removed.

---

?include/linux/lsm_hooks.h???????????|??1 +
?security/apparmor/include/context.h |??5 +++++
?security/apparmor/include/file.h????|??2 +-
?security/apparmor/lsm.c?????????????| 19 ++++++++--------
?security/security.c?????????????????| 43
+++++++++++++++++++++++++++++++++++++
?security/selinux/hooks.c????????????| 41 +++++++++----------------
----------
?security/selinux/include/objsec.h???|??5 +++++
?security/smack/smack.h??????????????|??5 +++++
?security/smack/smack_lsm.c??????????| 26 ++++++++--------------

?9 files changed, 89 insertions(+), 58 deletions(-)

include/linux/lsm_hooks.h +0 -0
index ee4fcc51fa91..e5d0f1e01b81 100644
@@ -1919,6 +1919,7 @@ struct security_hook_list {

? */
?struct lsm_blob_sizes {
? int lbs_cred;

include/linux/lsm_hooks.h +1 -0
+	int	lbs_file;

?};
?
?/*

security/apparmor/include/context.h +0 -0
index 301ab3a0dd04..c6e106a533e8 100644
@@ -87,6 +87,11 @@ static inline struct aa_label
 *aa_get_newest_cred_label(const struct cred *cred)
 ?	return aa_get_newest_label(aa_cred_raw_label(cred));
 ?}

?
+static inline struct aa_file_ctx *apparmor_file(const struct file *file)

security/apparmor/include/context.h +4 -0
+{
+	return file->f_security;
+}
+

?/**
? * __aa_task_raw_label - retrieve another task's label ? * @task: task to query??(NOT NULL)

security/apparmor/include/file.h +0 -0
index 4c2c8ac8842f..b9efe6bc226b 100644
@@ -32,7 +32,7 @@ struct path;

? ?AA_MAY_CHMOD | AA_MAY_CHOWN |
AA_MAY_LOCK | \
? ?AA_EXEC_MMAP | AA_MAY_LINK)
?

security/apparmor/include/file.h +1 -1
-#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
+#define file_ctx(X) apparmor_file(X)

?
?/* struct aa_file_ctx - the AppArmor context the file was opened in ? * @lock: lock to update the ctx

security/apparmor/lsm.c +0 -0
index d80293bde5bf..f2814ba84481 100644
@@ -402,21 +402,21 @@ static int apparmor_file_open(struct file
 *file, const struct cred *cred)

?
?static int apparmor_file_alloc_security(struct file *file) ?{

security/apparmor/lsm.c +1 -3
-	int error = 0;
-
-	/* freed by apparmor_file_free_security */
+	struct aa_file_ctx *ctx = file_ctx(file);

? struct aa_label *label = begin_current_label_crit_section();

security/apparmor/lsm.c +0 -4
-	file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL);
-	if (!file_ctx(file))
-		error = -ENOMEM;
-	end_current_label_crit_section(label);

?

security/apparmor/lsm.c +4 -1
-	return error;
+	spin_lock_init(&ctx->lock);
+	rcu_assign_pointer(ctx->label, aa_get_label(label));
+	end_current_label_crit_section(label);
+	return 0;

?}
?
?static void apparmor_file_free_security(struct file *file) ?{

security/apparmor/lsm.c +4 -1
-	aa_free_file_ctx(file_ctx(file));
+	struct aa_file_ctx *ctx = file_ctx(file);
+
+	if (ctx)
+		aa_put_label(rcu_access_pointer(ctx->label));

?}
?
?static int common_file_perm(const char *op, struct file *file, u32 mask)

security/apparmor/lsm.c +0 -0
@@ -1078,6 +1078,7 @@ static void apparmor_sock_graft(struct sock
 *sk, struct socket *parent)

?
?struct lsm_blob_sizes apparmor_blob_sizes = {
? .lbs_cred = sizeof(struct aa_task_ctx),

security/apparmor/lsm.c +1 -0
+	.lbs_file = sizeof(struct aa_file_ctx),

?};
?
?static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {

security/security.c +0 -0
index 6fadc3860fb0..4d8e702fa22f 100644
@@ -37,6 +37,8 @@
 ?struct security_hook_heads security_hook_heads __lsm_ro_after_init;
 ?static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);

?

security/security.c +2 -0
+static struct kmem_cache *lsm_file_cache;
+

?char *lsm_names;
?static struct lsm_blob_sizes blob_sizes;
?

security/security.c +0 -0
@@ -83,6 +85,13 @@ int __init security_init(void)
 ?	do_security_initcalls();

?
? /*

security/security.c +5 -0
+	?* Create any kmem_caches needed for blobs
+	?*/
+	if (blob_sizes.lbs_file)
+		lsm_file_cache = kmem_cache_create("lsm_file_cache",
+						???blob_sizes.lbs_fi

le, 0,

security/security.c +1 -0
+						???SLAB_PANIC,

NULL);

security/security.c +1 -0
+	/*

? ?* The second call to a module specific init function
? ?* adds hooks to the hook lists and does any other early
? ?* initializations required.

security/security.c +0 -0
@@ -91,6 +100,7 @@ int __init security_init(void)

?
?#ifdef CONFIG_SECURITY_LSM_DEBUG
? pr_info("LSM: cred blob size???????= %d\n",
blob_sizes.lbs_cred);

security/security.c +1 -0
+	pr_info("LSM: file blob size???????= %d\n",

blob_sizes.lbs_file);
?#endif
?
? return 0;

security/security.c +20 -0
@@ -267,6 +277,26 @@ static void __init lsm_set_size(int *need, int
 *lbs)
 ?void __init security_add_blobs(struct lsm_blob_sizes *needed)
 ?{
 ?	lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+	lsm_set_size(&needed->lbs_file, &blob_sizes.lbs_file);
+}
+
+/**
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
+ *
+ * Allocate the file blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_file_alloc(struct file *file)
+{
+	if (!lsm_file_cache)
+		return 0;
+
+	file->f_security = kmem_cache_zalloc(lsm_file_cache,
 GFP_KERNEL);
+	if (file->f_security == NULL)
+		return -ENOMEM;
+	return 0;
 ?}

?
?/*

security/security.c +0 -0
@@ -952,12 +982,25 @@ int security_file_permission(struct file *file,
 int mask)

?
?int security_file_alloc(struct file *file)
?{

security/security.c +4 -0
+	int rc = lsm_file_alloc(file);
+
+	if (rc)
+		return rc;
Quoted 1 line

? return call_int_hook(file_alloc_security, 0, file);

Suppose that a module's file_alloc_security() hook returns an error. What should happen to the blob allocated by lsm_file_alloc()? In general, callers assumes that security_file_alloc() handles cleanup internally if it returns an error and do not call security_file_free(); this is also true of other similar alloc hooks I believe. ?Further, if we allow the module file_alloc_security() hooks to perform any

Quoted 8 lines

allocation themselves, then we have a similar problem with regard to cleanup if any one of them fails; to be fully safe, we'd need to call the file_free_security() hook on the ones that had previously returned success. Either we need to handle such errors within security_file_alloc(), or we need to dispense with the ability to allocate and return an error code from the module's file_alloc_security(), i.e. make them return void, and probably rename them to file_init_security() or similar.

I like the idea of changing file_alloc_security() to file_init_security() or maybe file_setup_security() and making the hook a void function. If a module wants to allocate space on its own it will need to deal with the fact that it may have been unable to do so. I hesitate to prohibit modules from allocating their own space because someone is going to want to have a list of attributes. Trying to manage memory that you don't know about is a loosing proposition.

Quoted 307 lines
Quoted 307 lines

?}
?
?void security_file_free(struct file *file)
?{

security/security.c +5 -0
+	void *blob;
+
+	if (!lsm_file_cache)
+		return;
+

? call_void_hook(file_free_security, file);

security/security.c +4 -0
+
+	blob = file->f_security;
+	file->f_security = NULL;
+	kmem_cache_free(lsm_file_cache, blob);

?}
?
?int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

security/selinux/hooks.c +0 -0
index a4d1ec236d4e..28e641f829b2 100644
@@ -129,7 +129,6 @@ int selinux_enabled = 1;

?#endif
?
?static struct kmem_cache *sel_inode_cache;
-static struct kmem_cache *file_security_cache;
?
?/**
? * selinux_secmark_enabled - Check to see if SECMARK is currently enabled

security/selinux/hooks.c +0 -0
@@ -359,27 +358,15 @@ static void inode_free_security(struct inode
 *inode)

?
?static int file_alloc_security(struct file *file) ?{

security/selinux/hooks.c +1 -1
-	struct file_security_struct *fsec;
+	struct file_security_struct *fsec = selinux_file(file);

? u32 sid = current_sid();
?

security/selinux/hooks.c +0 -4
-	fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
-	if (!fsec)
-		return -ENOMEM;
-

? fsec->sid = sid;
? fsec->fown_sid = sid;

security/selinux/hooks.c +0 -1
-	file->f_security = fsec;

?
? return 0;
?}
?

security/selinux/hooks.c +0 -7
-static void file_free_security(struct file *file)
-{
-	struct file_security_struct *fsec = file->f_security;
-	file->f_security = NULL;
-	kmem_cache_free(file_security_cache, fsec);
-}
-

?static int superblock_alloc_security(struct super_block *sb) ?{
? struct superblock_security_struct *sbsec;

security/selinux/hooks.c +1 -1
@@ -1823,7 +1810,7 @@ static int file_has_perm(const struct cred
 *cred,
 ?			?struct file *file,
 ?			?u32 av)
 ?{
-	struct file_security_struct *fsec = file->f_security;
+	struct file_security_struct *fsec = selinux_file(file);
 ?	struct inode *inode = file_inode(file);
 ?	struct common_audit_data ad;

? u32 sid = cred_sid(cred);

security/selinux/hooks.c +1 -1
@@ -2143,7 +2130,7 @@ static int selinux_binder_transfer_file(struct
 task_struct *from,
 ?					struct file *file)
 ?{
 ?	u32 sid = task_sid(to);
-	struct file_security_struct *fsec = file->f_security;
+	struct file_security_struct *fsec = selinux_file(file);
 ?	struct dentry *dentry = file->f_path.dentry;
 ?	struct inode_security_struct *isec;

? struct common_audit_data ad;

security/selinux/hooks.c +1 -1
@@ -3421,7 +3408,7 @@ static int
 selinux_revalidate_file_permission(struct file *file, int mask)
 ?static int selinux_file_permission(struct file *file, int mask)
 ?{
 ?	struct inode *inode = file_inode(file);
-	struct file_security_struct *fsec = file->f_security;
+	struct file_security_struct *fsec = selinux_file(file);
 ?	struct inode_security_struct *isec;
 ?	u32 sid = current_sid();

?

security/selinux/hooks.c +0 -0
@@ -3443,11 +3430,6 @@ static int selinux_file_alloc_security(struct
 file *file)
 ?	return file_alloc_security(file);
 ?}

?

security/selinux/hooks.c +0 -5
-static void selinux_file_free_security(struct file *file)
-{
-	file_free_security(file);
-}
-

?/*
? * Check whether a task has the ioctl permission and cmd ? * operation to an inode.

security/selinux/hooks.c +1 -1
@@ -3456,7 +3438,7 @@ static int ioctl_has_perm(const struct cred
 *cred, struct file *file,
 ?		u32 requested, u16 cmd)
 ?{
 ?	struct common_audit_data ad;
-	struct file_security_struct *fsec = file->f_security;
+	struct file_security_struct *fsec = selinux_file(file);
 ?	struct inode *inode = file_inode(file);
 ?	struct inode_security_struct *isec;

? struct lsm_ioctlop_audit ioctl;

security/selinux/hooks.c +0 -0
@@ -3702,7 +3684,7 @@ static void selinux_file_set_fowner(struct file
 *file)
 ?{
 ?	struct file_security_struct *fsec;

?

security/selinux/hooks.c +1 -1
-	fsec = file->f_security;
+	fsec = selinux_file(file);

? fsec->fown_sid = current_sid();
?}
?

security/selinux/hooks.c +0 -0
@@ -3717,7 +3699,7 @@ static int selinux_file_send_sigiotask(struct
 task_struct *tsk,

? /* struct fown_struct is never outside the context of a
struct file */
? file = container_of(fown, struct file, f_owner);
?

security/selinux/hooks.c +1 -1
-	fsec = file->f_security;
+	fsec = selinux_file(file);

?
? if (!signum)
? perm = signal_to_av(SIGIO); /* as per
send_sigio_to_task */

security/selinux/hooks.c +0 -0
@@ -3740,7 +3722,7 @@ static int selinux_file_open(struct file *file,
 const struct cred *cred)
 ?	struct file_security_struct *fsec;
 ?	struct inode_security_struct *isec;

?

security/selinux/hooks.c +1 -1
-	fsec = file->f_security;
+	fsec = selinux_file(file);

? isec = inode_security(file_inode(file));
? /*
? ?* Save inode label and policy sequence number

security/selinux/hooks.c +0 -0
@@ -3870,7 +3852,7 @@ static int
 selinux_kernel_module_from_file(struct file *file)
 ?	ad.type = LSM_AUDIT_DATA_FILE;
 ?	ad.u.file = file;

?

security/selinux/hooks.c +1 -1
-	fsec = file->f_security;
+	fsec = selinux_file(file);

? if (sid != fsec->sid) {
? rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD,
FD__USE, &ad);
? if (rc)

security/selinux/hooks.c +0 -0
@@ -6215,6 +6197,7 @@ static void selinux_ib_free_security(void
 *ib_sec)

?
?struct lsm_blob_sizes selinux_blob_sizes = {
? .lbs_cred = sizeof(struct task_security_struct),

security/selinux/hooks.c +1 -0
+	.lbs_file = sizeof(struct file_security_struct),

?};
?
?static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {

security/selinux/hooks.c +0 -0
@@ -6285,7 +6268,6 @@ static struct security_hook_list
 selinux_hooks[] __lsm_ro_after_init = {

?
? LSM_HOOK_INIT(file_permission, selinux_file_permission),
? LSM_HOOK_INIT(file_alloc_security,
selinux_file_alloc_security),

security/selinux/hooks.c +0 -1
-	LSM_HOOK_INIT(file_free_security,

selinux_file_free_security),
? LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
? LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
? LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),

security/selinux/hooks.c +0 -0
@@ -6466,9 +6448,6 @@ static __init int selinux_init(void)

? sel_inode_cache =
kmem_cache_create("selinux_inode_security",
? ????sizeof(struct
inode_security_struct),
? ????0, SLAB_PANIC, NULL);

security/selinux/hooks.c +0 -1
-	file_security_cache =

kmem_cache_create("selinux_file_security",

security/selinux/hooks.c +0 -1
-					????sizeof(struct

file_security_struct),

security/selinux/hooks.c +0 -1
-					????0, SLAB_PANIC, NULL);

? avc_init();
?
? security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks),
"selinux");

security/selinux/include/objsec.h +0 -0
index c0bdb7232f39..504e15ed234f 100644
@@ -161,4 +161,9 @@ static inline struct task_security_struct
 *selinux_cred(const struct cred *cred)
 ?	return cred->security;
 ?}

?
+static inline struct file_security_struct *selinux_file(const struct file *file)

security/selinux/include/objsec.h +4 -0
+{
+	return file->f_security;
+}
+

?#endif /* _SELINUX_OBJSEC_H_ */

security/smack/smack.h +0 -0
index ab1d217800e2..d14e8d17eea0 100644
@@ -361,6 +361,11 @@ static inline struct task_smack
 *smack_cred(const struct cred *cred)
 ?	return cred->security;
 ?}

?
+static inline struct smack_known **smack_file(const struct file *file)

security/smack/smack.h +4 -0
+{
+	return file->f_security;
+}
+

?/*
? * Is the directory transmuting?
? */

security/smack/smack_lsm.c +0 -0
index ff4e5c632410..a807624aff9a 100644
@@ -1575,25 +1575,13 @@ static void smack_inode_getsecid(struct inode
 *inode, u32 *secid)

? */
?static int smack_file_alloc_security(struct file *file) ?{

security/smack/smack_lsm.c +1 -1
-	struct smack_known *skp = smk_of_current();
+	struct smack_known **blob = smack_file(file);

?

security/smack/smack_lsm.c +1 -1
-	file->f_security = skp;
+	*blob = smk_of_current();

? return 0;
?}
?
?/**
- * smack_file_free_security - clear a file security blob
- * @file: the object
- *
- * The security blob for a file is a pointer to the master
- * label list, so no memory is freed.
- */

security/smack/smack_lsm.c +0 -6
-static void smack_file_free_security(struct file *file)
-{
-	file->f_security = NULL;
-}
-
-/**

? * smack_file_ioctl - Smack check on ioctls
? * @file: the object
? * @cmd: what to do

security/smack/smack_lsm.c +0 -0
@@ -1817,7 +1805,9 @@ static int smack_mmap_file(struct file *file,

? */
?static void smack_file_set_fowner(struct file *file) ?{

security/smack/smack_lsm.c +3 -1
-	file->f_security = smk_of_current();
+	struct smack_known **blob = smack_file(file);
+
+	*blob = smk_of_current();

?}
?
?/**

security/smack/smack_lsm.c +0 -0
@@ -1834,6 +1824,7 @@ static void smack_file_set_fowner(struct file
 *file)
 ?static int smack_file_send_sigiotask(struct task_struct *tsk,

? ?????struct fown_struct *fown, int
signum)
?{

security/smack/smack_lsm.c +1 -0
+	struct smack_known **blob;

? struct smack_known *skp;
? struct smack_known *tkp = smk_of_task(smack_cred(tsk-

Quoted 1 line

cred));

? struct file *file;

security/smack/smack_lsm.c +0 -0
@@ -1846,7 +1837,8 @@ static int smack_file_send_sigiotask(struct
 task_struct *tsk,
 ?	file = container_of(fown, struct file, f_owner);

?
? /* we don't log here as rc can be overriden */

security/smack/smack_lsm.c +2 -1
-	skp = file->f_security;
+	blob = smack_file(file);
+	skp = *blob;

? rc = smk_access(skp, tkp, MAY_DELIVER, NULL);
? rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc);
? if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))

security/smack/smack_lsm.c +0 -0
@@ -4578,6 +4570,7 @@ static int smack_inode_getsecctx(struct inode
 *inode, void **ctx, u32 *ctxlen)

?
?struct lsm_blob_sizes smack_blob_sizes = {
? .lbs_cred = sizeof(struct task_smack),

security/smack/smack_lsm.c +1 -0
+	.lbs_file = sizeof(struct smack_known *),

?};
?
?static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {

security/smack/smack_lsm.c +0 -0
@@ -4615,7 +4608,6 @@ static struct security_hook_list smack_hooks[]
 __lsm_ro_after_init = {
Quoted 8 lines
Quoted 8 lines
security/smack/smack_lsm.c +0 -0
 ?	LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid),

?
? LSM_HOOK_INIT(file_alloc_security,
smack_file_alloc_security),

security/smack/smack_lsm.c +0 -1
-	LSM_HOOK_INIT(file_free_security, smack_file_free_security),

? LSM_HOOK_INIT(file_ioctl, smack_file_ioctl),
? LSM_HOOK_INIT(file_lock, smack_file_lock),
? LSM_HOOK_INIT(file_fcntl, smack_file_fcntl),

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

maintainer
#6 lore raw

PATCH 3/9 LSM: Manage file security blobs

Quoted 212 lines · Casey Schaufler
Quoted 202 lines · Stephen Smalley
Quoted 194 lines · Casey Schaufler

Subject: [PATCH 3/9] LSM: Manage file security blobs

Move the management of file security blobs from the individual security modules to the security infrastructure. The security modules using file blobs have been updated accordingly. Modules are required to identify the space they need at module initialization. In some cases a module no longer needs to supply a blob management hook, in which case the hook has been removed.

---

?include/linux/lsm_hooks.h???????????|??1 +
?security/apparmor/include/context.h |??5 +++++
?security/apparmor/include/file.h????|??2 +-
?security/apparmor/lsm.c?????????????| 19 ++++++++--------
?security/security.c?????????????????| 43
+++++++++++++++++++++++++++++++++++++
?security/selinux/hooks.c????????????| 41 +++++++++----------------
----------
?security/selinux/include/objsec.h???|??5 +++++
?security/smack/smack.h??????????????|??5 +++++
?security/smack/smack_lsm.c??????????| 26 ++++++++--------------

?9 files changed, 89 insertions(+), 58 deletions(-)

include/linux/lsm_hooks.h +0 -0
index ee4fcc51fa91..e5d0f1e01b81 100644
@@ -1919,6 +1919,7 @@ struct security_hook_list {

? */
?struct lsm_blob_sizes {
? int lbs_cred;

include/linux/lsm_hooks.h +1 -0
+	int	lbs_file;

?};
?
?/*

security/apparmor/include/context.h +0 -0
index 301ab3a0dd04..c6e106a533e8 100644
@@ -87,6 +87,11 @@ static inline struct aa_label
 *aa_get_newest_cred_label(const struct cred *cred)
 ?	return aa_get_newest_label(aa_cred_raw_label(cred));
 ?}

?
+static inline struct aa_file_ctx *apparmor_file(const struct file *file)

security/apparmor/include/context.h +4 -0
+{
+	return file->f_security;
+}
+

?/**
? * __aa_task_raw_label - retrieve another task's label ? * @task: task to query??(NOT NULL)

security/apparmor/include/file.h +0 -0
index 4c2c8ac8842f..b9efe6bc226b 100644
@@ -32,7 +32,7 @@ struct path;

? ?AA_MAY_CHMOD | AA_MAY_CHOWN |
AA_MAY_LOCK | \
? ?AA_EXEC_MMAP | AA_MAY_LINK)
?

security/apparmor/include/file.h +1 -1
-#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
+#define file_ctx(X) apparmor_file(X)

?
?/* struct aa_file_ctx - the AppArmor context the file was opened in ? * @lock: lock to update the ctx

security/apparmor/lsm.c +0 -0
index d80293bde5bf..f2814ba84481 100644
@@ -402,21 +402,21 @@ static int apparmor_file_open(struct file
 *file, const struct cred *cred)

?
?static int apparmor_file_alloc_security(struct file *file) ?{

security/apparmor/lsm.c +1 -3
-	int error = 0;
-
-	/* freed by apparmor_file_free_security */
+	struct aa_file_ctx *ctx = file_ctx(file);

? struct aa_label *label = begin_current_label_crit_section();

security/apparmor/lsm.c +0 -4
-	file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL);
-	if (!file_ctx(file))
-		error = -ENOMEM;
-	end_current_label_crit_section(label);

?

security/apparmor/lsm.c +4 -1
-	return error;
+	spin_lock_init(&ctx->lock);
+	rcu_assign_pointer(ctx->label, aa_get_label(label));
+	end_current_label_crit_section(label);
+	return 0;

?}
?
?static void apparmor_file_free_security(struct file *file) ?{

security/apparmor/lsm.c +4 -1
-	aa_free_file_ctx(file_ctx(file));
+	struct aa_file_ctx *ctx = file_ctx(file);
+
+	if (ctx)
+		aa_put_label(rcu_access_pointer(ctx->label));

?}
?
?static int common_file_perm(const char *op, struct file *file, u32 mask)

security/apparmor/lsm.c +0 -0
@@ -1078,6 +1078,7 @@ static void apparmor_sock_graft(struct sock
 *sk, struct socket *parent)

?
?struct lsm_blob_sizes apparmor_blob_sizes = {
? .lbs_cred = sizeof(struct aa_task_ctx),

security/apparmor/lsm.c +1 -0
+	.lbs_file = sizeof(struct aa_file_ctx),

?};
?
?static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {

security/security.c +0 -0
index 6fadc3860fb0..4d8e702fa22f 100644
@@ -37,6 +37,8 @@
 ?struct security_hook_heads security_hook_heads __lsm_ro_after_init;
 ?static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);

?

security/security.c +2 -0
+static struct kmem_cache *lsm_file_cache;
+

?char *lsm_names;
?static struct lsm_blob_sizes blob_sizes;
?

security/security.c +0 -0
@@ -83,6 +85,13 @@ int __init security_init(void)
 ?	do_security_initcalls();

?
? /*

security/security.c +5 -0
+	?* Create any kmem_caches needed for blobs
+	?*/
+	if (blob_sizes.lbs_file)
+		lsm_file_cache = kmem_cache_create("lsm_file_cache",
+						???blob_sizes.lbs_fi

le, 0,

security/security.c +1 -0
+						???SLAB_PANIC,

NULL);

security/security.c +1 -0
+	/*

? ?* The second call to a module specific init function
? ?* adds hooks to the hook lists and does any other early
? ?* initializations required.

security/security.c +0 -0
@@ -91,6 +100,7 @@ int __init security_init(void)

?
?#ifdef CONFIG_SECURITY_LSM_DEBUG
? pr_info("LSM: cred blob size???????= %d\n",
blob_sizes.lbs_cred);

security/security.c +1 -0
+	pr_info("LSM: file blob size???????= %d\n",

blob_sizes.lbs_file);
?#endif
?
? return 0;

security/security.c +20 -0
@@ -267,6 +277,26 @@ static void __init lsm_set_size(int *need, int
 *lbs)
 ?void __init security_add_blobs(struct lsm_blob_sizes *needed)
 ?{
 ?	lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+	lsm_set_size(&needed->lbs_file, &blob_sizes.lbs_file);
+}
+
+/**
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
+ *
+ * Allocate the file blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_file_alloc(struct file *file)
+{
+	if (!lsm_file_cache)
+		return 0;
+
+	file->f_security = kmem_cache_zalloc(lsm_file_cache,
 GFP_KERNEL);
+	if (file->f_security == NULL)
+		return -ENOMEM;
+	return 0;
 ?}

?
?/*

security/security.c +0 -0
@@ -952,12 +982,25 @@ int security_file_permission(struct file *file,
 int mask)

?
?int security_file_alloc(struct file *file)
?{

security/security.c +4 -0
+	int rc = lsm_file_alloc(file);
+
+	if (rc)
+		return rc;
Quoted 1 line

? return call_int_hook(file_alloc_security, 0, file);

Suppose that a module's file_alloc_security() hook returns an error. What should happen to the blob allocated by lsm_file_alloc()? In general, callers assumes that security_file_alloc() handles cleanup internally if it returns an error and do not call security_file_free(); this is also true of other similar alloc hooks I believe. ?Further, if we allow the module file_alloc_security() hooks to perform any

Quoted 8 lines

allocation themselves, then we have a similar problem with regard to cleanup if any one of them fails; to be fully safe, we'd need to call the file_free_security() hook on the ones that had previously returned success. Either we need to handle such errors within security_file_alloc(), or we need to dispense with the ability to allocate and return an error code from the module's file_alloc_security(), i.e. make them return void, and probably rename them to file_init_security() or similar.

Quoted 8 lines

I like the idea of changing file_alloc_security() to file_init_security() or maybe file_setup_security() and making the hook a void function. If a module wants to allocate space on its own it will need to deal with the fact that it may have been unable to do so. I hesitate to prohibit modules from allocating their own space because someone is going to want to have a list of attributes. Trying to manage memory that you don't know about is a loosing proposition.

Changing it to a void is just going to lead to LSMs that handle this them selves having to deny every access of the object, because that is the only sane thing they can do if the data they need isn't present.

It far better to have the one failure upfront than having an LSM rejecting every access to the object after the fact. And looking down the road to namespacing for containers I don't see away to handle some of the things that will be needed without an LSM doing allocations and managing stuff internally, but thats an argument for a different patch series.

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#7 lore raw

PATCH 3/9 LSM: Manage file security blobs

Quoted 220 lines · John Johansen
Quoted 211 lines · Casey Schaufler
Quoted 202 lines · Stephen Smalley
Quoted 194 lines · Casey Schaufler

Subject: [PATCH 3/9] LSM: Manage file security blobs

Move the management of file security blobs from the individual security modules to the security infrastructure. The security modules using file blobs have been updated accordingly. Modules are required to identify the space they need at module initialization. In some cases a module no longer needs to supply a blob management hook, in which case the hook has been removed.

---

?include/linux/lsm_hooks.h???????????|??1 +
?security/apparmor/include/context.h |??5 +++++
?security/apparmor/include/file.h????|??2 +-
?security/apparmor/lsm.c?????????????| 19 ++++++++--------
?security/security.c?????????????????| 43
+++++++++++++++++++++++++++++++++++++
?security/selinux/hooks.c????????????| 41 +++++++++----------------
----------
?security/selinux/include/objsec.h???|??5 +++++
?security/smack/smack.h??????????????|??5 +++++
?security/smack/smack_lsm.c??????????| 26 ++++++++--------------

?9 files changed, 89 insertions(+), 58 deletions(-)

include/linux/lsm_hooks.h +0 -0
index ee4fcc51fa91..e5d0f1e01b81 100644
@@ -1919,6 +1919,7 @@ struct security_hook_list {

? */
?struct lsm_blob_sizes {
? int lbs_cred;

include/linux/lsm_hooks.h +1 -0
+	int	lbs_file;

?};
?
?/*

security/apparmor/include/context.h +0 -0
index 301ab3a0dd04..c6e106a533e8 100644
@@ -87,6 +87,11 @@ static inline struct aa_label
 *aa_get_newest_cred_label(const struct cred *cred)
 ?	return aa_get_newest_label(aa_cred_raw_label(cred));
 ?}

?
+static inline struct aa_file_ctx *apparmor_file(const struct file *file)

security/apparmor/include/context.h +4 -0
+{
+	return file->f_security;
+}
+

?/**
? * __aa_task_raw_label - retrieve another task's label ? * @task: task to query??(NOT NULL)

security/apparmor/include/file.h +0 -0
index 4c2c8ac8842f..b9efe6bc226b 100644
@@ -32,7 +32,7 @@ struct path;

? ?AA_MAY_CHMOD | AA_MAY_CHOWN |
AA_MAY_LOCK | \
? ?AA_EXEC_MMAP | AA_MAY_LINK)
?

security/apparmor/include/file.h +1 -1
-#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
+#define file_ctx(X) apparmor_file(X)

?
?/* struct aa_file_ctx - the AppArmor context the file was opened in ? * @lock: lock to update the ctx

security/apparmor/lsm.c +0 -0
index d80293bde5bf..f2814ba84481 100644
@@ -402,21 +402,21 @@ static int apparmor_file_open(struct file
 *file, const struct cred *cred)

?
?static int apparmor_file_alloc_security(struct file *file) ?{

security/apparmor/lsm.c +1 -3
-	int error = 0;
-
-	/* freed by apparmor_file_free_security */
+	struct aa_file_ctx *ctx = file_ctx(file);

? struct aa_label *label = begin_current_label_crit_section();

security/apparmor/lsm.c +0 -4
-	file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL);
-	if (!file_ctx(file))
-		error = -ENOMEM;
-	end_current_label_crit_section(label);

?

security/apparmor/lsm.c +4 -1
-	return error;
+	spin_lock_init(&ctx->lock);
+	rcu_assign_pointer(ctx->label, aa_get_label(label));
+	end_current_label_crit_section(label);
+	return 0;

?}
?
?static void apparmor_file_free_security(struct file *file) ?{

security/apparmor/lsm.c +4 -1
-	aa_free_file_ctx(file_ctx(file));
+	struct aa_file_ctx *ctx = file_ctx(file);
+
+	if (ctx)
+		aa_put_label(rcu_access_pointer(ctx->label));

?}
?
?static int common_file_perm(const char *op, struct file *file, u32 mask)

security/apparmor/lsm.c +0 -0
@@ -1078,6 +1078,7 @@ static void apparmor_sock_graft(struct sock
 *sk, struct socket *parent)

?
?struct lsm_blob_sizes apparmor_blob_sizes = {
? .lbs_cred = sizeof(struct aa_task_ctx),

security/apparmor/lsm.c +1 -0
+	.lbs_file = sizeof(struct aa_file_ctx),

?};
?
?static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {

security/security.c +0 -0
index 6fadc3860fb0..4d8e702fa22f 100644
@@ -37,6 +37,8 @@
 ?struct security_hook_heads security_hook_heads __lsm_ro_after_init;
 ?static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);

?

security/security.c +2 -0
+static struct kmem_cache *lsm_file_cache;
+

?char *lsm_names;
?static struct lsm_blob_sizes blob_sizes;
?

security/security.c +0 -0
@@ -83,6 +85,13 @@ int __init security_init(void)
 ?	do_security_initcalls();

?
? /*

security/security.c +5 -0
+	?* Create any kmem_caches needed for blobs
+	?*/
+	if (blob_sizes.lbs_file)
+		lsm_file_cache = kmem_cache_create("lsm_file_cache",
+						???blob_sizes.lbs_fi

le, 0,

security/security.c +1 -0
+						???SLAB_PANIC,

NULL);

security/security.c +1 -0
+	/*

? ?* The second call to a module specific init function
? ?* adds hooks to the hook lists and does any other early
? ?* initializations required.

security/security.c +0 -0
@@ -91,6 +100,7 @@ int __init security_init(void)

?
?#ifdef CONFIG_SECURITY_LSM_DEBUG
? pr_info("LSM: cred blob size???????= %d\n",
blob_sizes.lbs_cred);

security/security.c +1 -0
+	pr_info("LSM: file blob size???????= %d\n",

blob_sizes.lbs_file);
?#endif
?
? return 0;

security/security.c +20 -0
@@ -267,6 +277,26 @@ static void __init lsm_set_size(int *need, int
 *lbs)
 ?void __init security_add_blobs(struct lsm_blob_sizes *needed)
 ?{
 ?	lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+	lsm_set_size(&needed->lbs_file, &blob_sizes.lbs_file);
+}
+
+/**
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
+ *
+ * Allocate the file blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_file_alloc(struct file *file)
+{
+	if (!lsm_file_cache)
+		return 0;
+
+	file->f_security = kmem_cache_zalloc(lsm_file_cache,
 GFP_KERNEL);
+	if (file->f_security == NULL)
+		return -ENOMEM;
+	return 0;
 ?}

?
?/*

security/security.c +0 -0
@@ -952,12 +982,25 @@ int security_file_permission(struct file *file,
 int mask)

?
?int security_file_alloc(struct file *file)
?{

security/security.c +4 -0
+	int rc = lsm_file_alloc(file);
+
+	if (rc)
+		return rc;
Quoted 1 line

? return call_int_hook(file_alloc_security, 0, file);

Suppose that a module's file_alloc_security() hook returns an error. What should happen to the blob allocated by lsm_file_alloc()? In general, callers assumes that security_file_alloc() handles cleanup internally if it returns an error and do not call security_file_free(); this is also true of other similar alloc hooks I believe. ?Further, if we allow the module file_alloc_security() hooks to perform any

Quoted 8 lines

allocation themselves, then we have a similar problem with regard to cleanup if any one of them fails; to be fully safe, we'd need to call the file_free_security() hook on the ones that had previously returned success. Either we need to handle such errors within security_file_alloc(), or we need to dispense with the ability to allocate and return an error code from the module's file_alloc_security(), i.e. make them return void, and probably rename them to file_init_security() or similar.

Quoted 8 lines

I like the idea of changing file_alloc_security() to file_init_security() or maybe file_setup_security() and making the hook a void function. If a module wants to allocate space on its own it will need to deal with the fact that it may have been unable to do so. I hesitate to prohibit modules from allocating their own space because someone is going to want to have a list of attributes. Trying to manage memory that you don't know about is a loosing proposition.

Quoted 3 lines

Changing it to a void is just going to lead to LSMs that handle this them selves having to deny every access of the object, because that is the only sane thing they can do if the data they need isn't present.

It's also not going to work for the IPC cases where SELinux is doing access checks in the alloc functions. I sure wasn't expecting that. But the reality is that no security module does additional allocation, and I don't see any initialization that requires cleanup. Life will be a whole lot simpler if we keep it that way.

Or, we can have a post_file_alloc_security() hook which takes a boolean that tells the function to complete or delete the action. The boolean would be set depending on whether security_file_alloc() succeeded or failed. It would be called in security_file_alloc() after the file_alloc_security() functions. Hm. That would keep it contained and mean that only modules that do their own management would have to have a hook. Brilliant! Messy, but workable. And best of all, nothing needs to be done until we have a module that needs it.

Quoted 5 lines

It far better to have the one failure upfront than having an LSM rejecting every access to the object after the fact. And looking down the road to namespacing for containers I don't see away to handle some of the things that will be needed without an LSM doing allocations and managing stuff internally, but thats an argument for a different patch series.

OK, I'll buy that. Let's plan for post_file_alloc entries when the need arises, and leave the code the way it is for now.

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#8 lore raw

PATCH 3/9 LSM: Manage file security blobs

Quoted 239 lines · Casey Schaufler
Quoted 220 lines · John Johansen
Quoted 211 lines · Casey Schaufler
Quoted 202 lines · Stephen Smalley
Quoted 194 lines · Casey Schaufler

Subject: [PATCH 3/9] LSM: Manage file security blobs

Move the management of file security blobs from the individual security modules to the security infrastructure. The security modules using file blobs have been updated accordingly. Modules are required to identify the space they need at module initialization. In some cases a module no longer needs to supply a blob management hook, in which case the hook has been removed.

---

?include/linux/lsm_hooks.h???????????|??1 +
?security/apparmor/include/context.h |??5 +++++
?security/apparmor/include/file.h????|??2 +-
?security/apparmor/lsm.c?????????????| 19 ++++++++--------
?security/security.c?????????????????| 43
+++++++++++++++++++++++++++++++++++++
?security/selinux/hooks.c????????????| 41 +++++++++----------------
----------
?security/selinux/include/objsec.h???|??5 +++++
?security/smack/smack.h??????????????|??5 +++++
?security/smack/smack_lsm.c??????????| 26 ++++++++--------------

?9 files changed, 89 insertions(+), 58 deletions(-)

include/linux/lsm_hooks.h +0 -0
index ee4fcc51fa91..e5d0f1e01b81 100644
@@ -1919,6 +1919,7 @@ struct security_hook_list {

? */
?struct lsm_blob_sizes {
? int lbs_cred;

include/linux/lsm_hooks.h +1 -0
+	int	lbs_file;

?};
?
?/*

security/apparmor/include/context.h +0 -0
index 301ab3a0dd04..c6e106a533e8 100644
@@ -87,6 +87,11 @@ static inline struct aa_label
 *aa_get_newest_cred_label(const struct cred *cred)
 ?	return aa_get_newest_label(aa_cred_raw_label(cred));
 ?}

?
+static inline struct aa_file_ctx *apparmor_file(const struct file *file)

security/apparmor/include/context.h +4 -0
+{
+	return file->f_security;
+}
+

?/**
? * __aa_task_raw_label - retrieve another task's label ? * @task: task to query??(NOT NULL)

security/apparmor/include/file.h +0 -0
index 4c2c8ac8842f..b9efe6bc226b 100644
@@ -32,7 +32,7 @@ struct path;

? ?AA_MAY_CHMOD | AA_MAY_CHOWN |
AA_MAY_LOCK | \
? ?AA_EXEC_MMAP | AA_MAY_LINK)
?

security/apparmor/include/file.h +1 -1
-#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
+#define file_ctx(X) apparmor_file(X)

?
?/* struct aa_file_ctx - the AppArmor context the file was opened in ? * @lock: lock to update the ctx

security/apparmor/lsm.c +0 -0
index d80293bde5bf..f2814ba84481 100644
@@ -402,21 +402,21 @@ static int apparmor_file_open(struct file
 *file, const struct cred *cred)

?
?static int apparmor_file_alloc_security(struct file *file) ?{

security/apparmor/lsm.c +1 -3
-	int error = 0;
-
-	/* freed by apparmor_file_free_security */
+	struct aa_file_ctx *ctx = file_ctx(file);

? struct aa_label *label = begin_current_label_crit_section();

security/apparmor/lsm.c +0 -4
-	file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL);
-	if (!file_ctx(file))
-		error = -ENOMEM;
-	end_current_label_crit_section(label);

?

security/apparmor/lsm.c +4 -1
-	return error;
+	spin_lock_init(&ctx->lock);
+	rcu_assign_pointer(ctx->label, aa_get_label(label));
+	end_current_label_crit_section(label);
+	return 0;

?}
?
?static void apparmor_file_free_security(struct file *file) ?{

security/apparmor/lsm.c +4 -1
-	aa_free_file_ctx(file_ctx(file));
+	struct aa_file_ctx *ctx = file_ctx(file);
+
+	if (ctx)
+		aa_put_label(rcu_access_pointer(ctx->label));

?}
?
?static int common_file_perm(const char *op, struct file *file, u32 mask)

security/apparmor/lsm.c +0 -0
@@ -1078,6 +1078,7 @@ static void apparmor_sock_graft(struct sock
 *sk, struct socket *parent)

?
?struct lsm_blob_sizes apparmor_blob_sizes = {
? .lbs_cred = sizeof(struct aa_task_ctx),

security/apparmor/lsm.c +1 -0
+	.lbs_file = sizeof(struct aa_file_ctx),

?};
?
?static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {

security/security.c +0 -0
index 6fadc3860fb0..4d8e702fa22f 100644
@@ -37,6 +37,8 @@
 ?struct security_hook_heads security_hook_heads __lsm_ro_after_init;
 ?static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);

?

security/security.c +2 -0
+static struct kmem_cache *lsm_file_cache;
+

?char *lsm_names;
?static struct lsm_blob_sizes blob_sizes;
?

security/security.c +0 -0
@@ -83,6 +85,13 @@ int __init security_init(void)
 ?	do_security_initcalls();

?
? /*

security/security.c +5 -0
+	?* Create any kmem_caches needed for blobs
+	?*/
+	if (blob_sizes.lbs_file)
+		lsm_file_cache = kmem_cache_create("lsm_file_cache",
+						???blob_sizes.lbs_fi

le, 0,

security/security.c +1 -0
+						???SLAB_PANIC,

NULL);

security/security.c +1 -0
+	/*

? ?* The second call to a module specific init function
? ?* adds hooks to the hook lists and does any other early
? ?* initializations required.

security/security.c +0 -0
@@ -91,6 +100,7 @@ int __init security_init(void)

?
?#ifdef CONFIG_SECURITY_LSM_DEBUG
? pr_info("LSM: cred blob size???????= %d\n",
blob_sizes.lbs_cred);

security/security.c +1 -0
+	pr_info("LSM: file blob size???????= %d\n",

blob_sizes.lbs_file);
?#endif
?
? return 0;

security/security.c +20 -0
@@ -267,6 +277,26 @@ static void __init lsm_set_size(int *need, int
 *lbs)
 ?void __init security_add_blobs(struct lsm_blob_sizes *needed)
 ?{
 ?	lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+	lsm_set_size(&needed->lbs_file, &blob_sizes.lbs_file);
+}
+
+/**
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
+ *
+ * Allocate the file blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_file_alloc(struct file *file)
+{
+	if (!lsm_file_cache)
+		return 0;
+
+	file->f_security = kmem_cache_zalloc(lsm_file_cache,
 GFP_KERNEL);
+	if (file->f_security == NULL)
+		return -ENOMEM;
+	return 0;
 ?}

?
?/*

security/security.c +0 -0
@@ -952,12 +982,25 @@ int security_file_permission(struct file *file,
 int mask)

?
?int security_file_alloc(struct file *file)
?{

security/security.c +4 -0
+	int rc = lsm_file_alloc(file);
+
+	if (rc)
+		return rc;
Quoted 1 line

? return call_int_hook(file_alloc_security, 0, file);

Suppose that a module's file_alloc_security() hook returns an error. What should happen to the blob allocated by lsm_file_alloc()? In general, callers assumes that security_file_alloc() handles cleanup internally if it returns an error and do not call security_file_free(); this is also true of other similar alloc hooks I believe. ?Further, if we allow the module file_alloc_security() hooks to perform any

Quoted 8 lines

allocation themselves, then we have a similar problem with regard to cleanup if any one of them fails; to be fully safe, we'd need to call the file_free_security() hook on the ones that had previously returned success. Either we need to handle such errors within security_file_alloc(), or we need to dispense with the ability to allocate and return an error code from the module's file_alloc_security(), i.e. make them return void, and probably rename them to file_init_security() or similar.

Quoted 8 lines

I like the idea of changing file_alloc_security() to file_init_security() or maybe file_setup_security() and making the hook a void function. If a module wants to allocate space on its own it will need to deal with the fact that it may have been unable to do so. I hesitate to prohibit modules from allocating their own space because someone is going to want to have a list of attributes. Trying to manage memory that you don't know about is a loosing proposition.

Quoted 3 lines

Changing it to a void is just going to lead to LSMs that handle this them selves having to deny every access of the object, because that is the only sane thing they can do if the data they need isn't present.

It's also not going to work for the IPC cases where SELinux is doing access checks in the alloc functions. I sure wasn't expecting that. But the reality is that no security module does additional allocation, and I don't see any initialization that requires cleanup. Life will be a whole lot simpler if we keep it that way.

Or, we can have a post_file_alloc_security() hook which takes a boolean that tells the function to complete or delete the action. The boolean would be set depending on whether security_file_alloc() succeeded or failed. It would be called in security_file_alloc() after the file_alloc_security() functions. Hm. That would keep it contained and mean that only modules that do their own management would have to have a hook. Brilliant! Messy, but workable. And best of all, nothing needs to be done until we have a module that needs it.

Quoted 7 lines
Quoted 5 lines

It far better to have the one failure upfront than having an LSM rejecting every access to the object after the fact. And looking down the road to namespacing for containers I don't see away to handle some of the things that will be needed without an LSM doing allocations and managing stuff internally, but thats an argument for a different patch series.

OK, I'll buy that. Let's plan for post_file_alloc entries when the need arises, and leave the code the way it is for now.

Here's what I think it would look like, in case I wasn't clear:

int security_file_alloc(struct file *file)
{
int rc = lsm_file_alloc(file);

if (rc)
return rc;
rc = call_int_hook(file_alloc_security, 0, file); call_void_hook(post_file_alloc_security, file, rc != 0); return rc;
}

The 3rd argument to the post_file_alloc_security functions is true if the data should be deleted and false if the operation should be completed. The post_file_alloc_security functions are not allowed to fail. They can't make access control checks.

Quoted 6 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#9 lore raw

PATCH 3/9 LSM: Manage file security blobs

In reply to Casey Schaufler
Quoted 303 lines · Casey Schaufler
Quoted 268 lines · John Johansen
Quoted 252 lines · Casey Schaufler
Quoted 242 lines · Stephen Smalley
Quoted 223 lines · Casey Schaufler

Subject: [PATCH 3/9] LSM: Manage file security blobs

Move the management of file security blobs from the individual
security modules to the security infrastructure. The security modules
using file blobs have been updated accordingly. Modules are required
to identify the space they need at module initialization. In some
cases a module no longer needs to supply a blob management hook, in
which case the hook has been removed.

---

?include/linux/lsm_hooks.h???????????|??1 +
?security/apparmor/include/context.h |??5 +++++
?security/apparmor/include/file.h????|??2 +-
?security/apparmor/lsm.c?????????????| 19 ++++++++--------
?security/security.c?????????????????| 43

+++++++++++++++++++++++++++++++++++++
?security/selinux/hooks.c????????????| 41 +++++++++--------
--------
----------

?security/selinux/include/objsec.h???|??5 +++++
?security/smack/smack.h??????????????|??5 +++++
?security/smack/smack_lsm.c??????????| 26 ++++++++-----------

---
?9 files changed, 89 insertions(+), 58 deletions(-)

include/linux/lsm_hooks.h +0 -0
index ee4fcc51fa91..e5d0f1e01b81 100644
@@ -1919,6 +1919,7 @@ struct security_hook_list {

? */
?struct lsm_blob_sizes {
? int lbs_cred;

include/linux/lsm_hooks.h +1 -0
+	int	lbs_file;

?};
?
?/*

security/apparmor/include/context.h +0 -0
index 301ab3a0dd04..c6e106a533e8 100644
@@ -87,6 +87,11 @@ static inline struct aa_label
 *aa_get_newest_cred_label(const struct cred *cred)
 ?	return aa_get_newest_label(aa_cred_raw_label(cred));
 ?}

?
+static inline struct aa_file_ctx *apparmor_file(const struct file
*file)

security/apparmor/include/context.h +4 -0
+{
+	return file->f_security;
+}
+

?/**
? * __aa_task_raw_label - retrieve another task's label ? * @task: task to query??(NOT NULL)

security/apparmor/include/file.h +0 -0
index 4c2c8ac8842f..b9efe6bc226b 100644
@@ -32,7 +32,7 @@ struct path;

? ?AA_MAY_CHMOD | AA_MAY_CHOWN
|
AA_MAY_LOCK | \
? ?AA_EXEC_MMAP | AA_MAY_LINK)
?

security/apparmor/include/file.h +1 -1
-#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
+#define file_ctx(X) apparmor_file(X)

?
?/* struct aa_file_ctx - the AppArmor context the file was opened in
? * @lock: lock to update the ctx

security/apparmor/lsm.c +0 -0
index d80293bde5bf..f2814ba84481 100644
@@ -402,21 +402,21 @@ static int apparmor_file_open(struct

file
*file, const struct cred *cred)
?
?static int apparmor_file_alloc_security(struct file *file) ?{

security/apparmor/lsm.c +1 -3
-	int error = 0;
-
-	/* freed by apparmor_file_free_security */
+	struct aa_file_ctx *ctx = file_ctx(file);

? struct aa_label *label =
begin_current_label_crit_section();

security/apparmor/lsm.c +0 -1
-	file->f_security = aa_alloc_file_ctx(label,

GFP_KERNEL);

security/apparmor/lsm.c +0 -3
-	if (!file_ctx(file))
-		error = -ENOMEM;
-	end_current_label_crit_section(label);

?

security/apparmor/lsm.c +4 -1
-	return error;
+	spin_lock_init(&ctx->lock);
+	rcu_assign_pointer(ctx->label, aa_get_label(label));
+	end_current_label_crit_section(label);
+	return 0;

?}
?
?static void apparmor_file_free_security(struct file *file) ?{

security/apparmor/lsm.c +4 -1
-	aa_free_file_ctx(file_ctx(file));
+	struct aa_file_ctx *ctx = file_ctx(file);
+
+	if (ctx)
+		aa_put_label(rcu_access_pointer(ctx-
Quoted 1 line

label));

?}
?
?static int common_file_perm(const char *op, struct file *file, u32
mask)

security/apparmor/lsm.c +0 -0
@@ -1078,6 +1078,7 @@ static void apparmor_sock_graft(struct

sock
*sk, struct socket *parent)
?
?struct lsm_blob_sizes apparmor_blob_sizes = {
? .lbs_cred = sizeof(struct aa_task_ctx),

security/apparmor/lsm.c +1 -0
+	.lbs_file = sizeof(struct aa_file_ctx),

?};
?
?static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {

security/security.c +0 -0
index 6fadc3860fb0..4d8e702fa22f 100644
@@ -37,6 +37,8 @@

?struct security_hook_heads security_hook_heads
__lsm_ro_after_init;
?static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);
?

security/security.c +2 -0
+static struct kmem_cache *lsm_file_cache;
+

?char *lsm_names;
?static struct lsm_blob_sizes blob_sizes;
?

security/security.c +0 -0
@@ -83,6 +85,13 @@ int __init security_init(void)
 ?	do_security_initcalls();

?
? /*

security/security.c +4 -0
+	?* Create any kmem_caches needed for blobs
+	?*/
+	if (blob_sizes.lbs_file)
+		lsm_file_cache =

kmem_cache_create("lsm_file_cache",

security/security.c +1 -0
+						???blob_size

s.lbs_fi
le, 0,

security/security.c +1 -0
+						???SLAB_PANI

C,
NULL);

security/security.c +1 -0
+	/*

? ?* The second call to a module specific init
function
? ?* adds hooks to the hook lists and does any other
early
? ?* initializations required.

security/security.c +0 -0
@@ -91,6 +100,7 @@ int __init security_init(void)

?
?#ifdef CONFIG_SECURITY_LSM_DEBUG
? pr_info("LSM: cred blob size???????= %d\n",
blob_sizes.lbs_cred);

security/security.c +1 -0
+	pr_info("LSM: file blob size???????= %d\n",

blob_sizes.lbs_file);
?#endif
?
? return 0;

security/security.c +0 -0
@@ -267,6 +277,26 @@ static void __init lsm_set_size(int
 *need, int
 *lbs)

?void __init security_add_blobs(struct lsm_blob_sizes *needed)
?{
? lsm_set_size(&needed->lbs_cred,
&blob_sizes.lbs_cred);

security/security.c +1 -0
+	lsm_set_size(&needed->lbs_file,

&blob_sizes.lbs_file);

security/security.c +16 -0
+}
+
+/**
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
+ *
+ * Allocate the file blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_file_alloc(struct file *file)
+{
+	if (!lsm_file_cache)
+		return 0;
+
+	file->f_security = kmem_cache_zalloc(lsm_file_cache,

GFP_KERNEL);

security/security.c +3 -0
+	if (file->f_security == NULL)
+		return -ENOMEM;
+	return 0;

?}
?
?/*

security/security.c +0 -0
@@ -952,12 +982,25 @@ int security_file_permission(struct
 file *file,
 int mask)

?
?int security_file_alloc(struct file *file)
?{

security/security.c +4 -0
+	int rc = lsm_file_alloc(file);
+
+	if (rc)
+		return rc;
Quoted 1 line

? return call_int_hook(file_alloc_security, 0, file);

Suppose that a module's file_alloc_security() hook returns an error.?
What should happen to the blob allocated by lsm_file_alloc()? In
general, callers assumes that security_file_alloc() handles cleanup
internally if it returns an error and do not call security_file_free();
this is also true of other similar alloc hooks I believe. ?Further, if
we allow the module file_alloc_security() hooks to perform any allocation themselves, then we have a similar problem with regard to
cleanup if any one of them fails; to be fully safe, we'd need to call
the file_free_security() hook on the ones that had previously

Quoted 8 lines

returned
success. Either we need to handle such errors within security_file_alloc(), or we need to dispense with the ability to
allocate and return an error code from the module's file_alloc_security(), i.e. make them return void, and probably rename
them to file_init_security() or similar.

Quoted 14 lines

I like the idea of changing file_alloc_security() to file_init_security()
or maybe file_setup_security() and making the hook a void function. If a
module wants to allocate space on its own it will need to deal with the
fact that it may have been unable to do so. I hesitate to prohibit modules
from allocating their own space because someone is going to want to have a
list of attributes. Trying to manage memory that you don't know about is
a loosing proposition.

Quoted 5 lines

Changing it to a void is just going to lead to LSMs that handle this them
selves having to deny every access of the object, because that is the only
sane thing they can do if the data they need isn't present.

It's also not going to work for the IPC cases where SELinux is doing access checks in the alloc functions. I sure wasn't expecting that. But the reality is that no security module does additional allocation, and I don't see any initialization that requires cleanup. Life will be a whole lot simpler if we keep it that way.

Or, we can have a post_file_alloc_security() hook which takes a boolean
that tells the function to complete or delete the action. The boolean would be set depending on whether security_file_alloc() succeeded or failed. It would be called in security_file_alloc() after the file_alloc_security() functions. Hm. That would keep it contained and mean that only modules that do their own management would have to have
a hook. Brilliant! Messy, but workable. And best of all, nothing needs
to be done until we have a module that needs it.

Quoted 9 lines

It far better to have the one failure upfront than having an LSM rejecting
every access to the object after the fact. And looking down the road to
namespacing for containers I don't see away to handle some of the things
that will be needed without an LSM doing allocations and managing stuff
internally, but thats an argument for a different patch series.

Quoted 3 lines

OK, I'll buy that. Let's plan for post_file_alloc entries when the need
arises, and leave the code the way it is for now.?

At a minimum, you need to change the code to free the lsm blob if any of the hook calls fail; otherwise, you'll leak memory.

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#10 lore raw

PATCH 4/9 LSM: Manage task security blobs

In reply to Casey Schaufler

Subject: [PATCH 4/9] LSM: Manage task security blobs

Move management of task security blobs into the security infrastructure. Modules are required to identify the space they require. At this time there are no modules that use task blobs.

---
 include/linux/lsm_hooks.h |  1 +
 security/security.c       | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 33 insertions(+)
include/linux/lsm_hooks.h +1 -0
index e5d0f1e01b81..44f8619d93d6 100644
@@ -1920,6 +1920,7 @@ struct security_hook_list {
 struct lsm_blob_sizes {
 	int	lbs_cred;
 	int	lbs_file;
+	int	lbs_task;
 };
 
 /*
security/security.c +32 -0
index 4d8e702fa22f..70740b902e16 100644
@@ -101,6 +101,7 @@ int __init security_init(void)
 #ifdef CONFIG_SECURITY_LSM_DEBUG
 	pr_info("LSM: cred blob size       = %d\n", blob_sizes.lbs_cred);
 	pr_info("LSM: file blob size       = %d\n", blob_sizes.lbs_file);
+	pr_info("LSM: task blob size       = %d\n", blob_sizes.lbs_task);
 #endif
 
 	return 0;
@@ -278,6 +279,7 @@ void __init security_add_blobs(struct lsm_blob_sizes *needed)
 {
 	lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
 	lsm_set_size(&needed->lbs_file, &blob_sizes.lbs_file);
+	lsm_set_size(&needed->lbs_task, &blob_sizes.lbs_task);
 }
 
 /**
@@ -299,6 +301,29 @@ int lsm_file_alloc(struct file *file)
 	return 0;
 }
 
+/**
+ * lsm_task_alloc - allocate a composite task blob
+ * @task: the task that needs a blob
+ *
+ * Allocate the task blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_task_alloc(struct task_struct *task)
+{
+#ifdef CONFIG_SECURITY_LSM_DEBUG
+	if (task->security)
+		pr_info("%s: Inbound task blob is not NULL.\n", __func__);
+#endif
+	if (blob_sizes.lbs_task == 0)
+		return 0;
+
+	task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL);
+	if (task->security == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
 /*
  * Hook list operation macros.
  *
@@ -1102,12 +1127,19 @@ int security_file_open(struct file *file, const struct cred *cred)
 
 int security_task_alloc(struct task_struct *task, unsigned long clone_flags)
 {
+	int rc = lsm_task_alloc(task);
+
+	if (rc)
+		return rc;
 	return call_int_hook(task_alloc, 0, task, clone_flags);
 }
 
 void security_task_free(struct task_struct *task)
 {
 	call_void_hook(task_free, task);
+
+	kfree(task->security);
+	task->security = NULL;
 }
 
 int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
Signature · 7 lines
2.13.0


--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
author maintainer
#11 lore raw

PATCH 5/9 LSM: Manage remaining security blobs

In reply to Casey Schaufler

Subject: [PATCH 5/9] LSM: Manage remaining security blobs

Move management of the inode, ipc, key, msg_msg, sock and superblock security blobs from the security modules to the infrastructure. Use of the blob pointers is abstracted in the security modules.

---
 include/linux/lsm_hooks.h         |   8 +
 security/apparmor/include/net.h   |   6 +
 security/apparmor/lsm.c           |  22 +--
 security/security.c               | 258 +++++++++++++++++++++++++++-
 security/selinux/hooks.c          | 333 ++++++++++++------------------------
 security/selinux/include/objsec.h |  65 ++++++-
 security/selinux/netlabel.c       |  15 +-
 security/selinux/selinuxfs.c      |   4 +-
 security/selinux/ss/services.c    |   3 +-
 security/smack/smack.h            |  61 ++++++-
 security/smack/smack_lsm.c        | 349 +++++++++++---------------------------
 security/smack/smack_netfilter.c  |   8 +-
 12 files changed, 610 insertions(+), 522 deletions(-)
include/linux/lsm_hooks.h +8 -0
index 44f8619d93d6..cae3f6591044 100644
@@ -1920,6 +1920,12 @@ struct security_hook_list {
 struct lsm_blob_sizes {
 	int	lbs_cred;
 	int	lbs_file;
+	int	lbs_inode;
+	int	lbs_ipc;
+	int	lbs_key;
+	int	lbs_msg_msg;
+	int	lbs_sock;
+	int	lbs_superblock;
 	int	lbs_task;
 };
 
@@ -1983,9 +1989,11 @@ static inline void loadpin_add_hooks(void) { };
 #endif
 
 extern int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
+extern int lsm_inode_alloc(struct inode *inode);
 
 #ifdef CONFIG_SECURITY
 void lsm_early_cred(struct cred *cred);
+void lsm_early_inode(struct inode *inode);
 #endif
 
 #endif /* ! __LINUX_LSM_HOOKS_H */
security/apparmor/include/net.h +6 -0
index 140c8efcf364..c0400c3a24f7 100644
@@ -56,8 +56,14 @@ struct aa_sk_ctx {
 	struct path path;
 };
 
+#ifdef CONFIG_SECURITY_STACKING
+#define SK_CTX(X) ((X)->sk_security + apparmor_blob_sizes.lbs_sock)
+#define SOCK_ctx(X) (SOCK_INODE(X)->i_security + apparmor_blob_sizes.lbs_inode)
+#else
 #define SK_CTX(X) ((X)->sk_security)
 #define SOCK_ctx(X) SOCK_INODE(X)->i_security
+#endif
+
 #define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P)				  \
 	struct lsm_network_audit NAME ## _net = { .sk = (SK),		  \
 						  .family = (F)};	  \
security/apparmor/lsm.c +3 -19
index f2814ba84481..8edbf79062cd 100644
@@ -715,33 +715,15 @@ static int apparmor_task_kill(struct task_struct *target, struct siginfo *info,
 }
 
 /**
- * apparmor_sk_alloc_security - allocate and attach the sk_security field
- */
-static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags)
-{
-	struct aa_sk_ctx *ctx;
-
-	ctx = kzalloc(sizeof(*ctx), flags);
-	if (!ctx)
-		return -ENOMEM;
-
-	SK_CTX(sk) = ctx;
-
-	return 0;
-}
-
-/**
  * apparmor_sk_free_security - free the sk_security field
  */
 static void apparmor_sk_free_security(struct sock *sk)
 {
 	struct aa_sk_ctx *ctx = SK_CTX(sk);
 
-	SK_CTX(sk) = NULL;
 	aa_put_label(ctx->label);
 	aa_put_label(ctx->peer);
 	path_put(&ctx->path);
-	kfree(ctx);
 }
 
 /**
@@ -1079,6 +1061,7 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
 struct lsm_blob_sizes apparmor_blob_sizes = {
 	.lbs_cred = sizeof(struct aa_task_ctx),
 	.lbs_file = sizeof(struct aa_file_ctx),
+	.lbs_sock = sizeof(struct aa_sk_ctx),
 };
 
 static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
@@ -1115,7 +1098,6 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
 	LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
 	LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
 
-	LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security),
 	LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security),
 	LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security),
 
@@ -1487,6 +1469,8 @@ static int __init apparmor_init(void)
 	if (!finish) {
 		if (apparmor_enabled && security_module_enable("apparmor"))
 			security_add_blobs(&apparmor_blob_sizes);
+		else
+			apparmor_enabled = 0;
 		finish = 1;
 		return 0;
 	}
security/security.c +256 -2

392 lines not on this page · raw message

security/selinux/hooks.c +104 -229

874 lines not on this page · raw message

security/selinux/include/objsec.h +61 -4

75 lines not on this page · raw message

security/selinux/netlabel.c +8 -7
index aaba6677ee2e..0b0091c04688 100644
@@ -32,6 +32,7 @@
 #include <linux/gfp.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
+#include <linux/lsm_hooks.h>
 #include <net/sock.h>
 #include <net/netlabel.h>
 #include <net/ip.h>
@@ -82,7 +83,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
 static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
 {
 	int rc;
-	struct sk_security_struct *sksec = sk->sk_security;
+	struct sk_security_struct *sksec = selinux_sock(sk);
 	struct netlbl_lsm_secattr *secattr;
 
 	if (sksec->nlbl_secattr != NULL)
@@ -114,7 +115,7 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
 							const struct sock *sk,
 							u32 sid)
 {
-	struct sk_security_struct *sksec = sk->sk_security;
+	struct sk_security_struct *sksec = selinux_sock(sk);
 	struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
 
 	if (secattr == NULL)
@@ -249,7 +250,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
 	 * being labeled by it's parent socket, if it is just exit */
 	sk = skb_to_full_sk(skb);
 	if (sk != NULL) {
-		struct sk_security_struct *sksec = sk->sk_security;
+		struct sk_security_struct *sksec = selinux_sock(sk);
 		if (sksec->nlbl_state != NLBL_REQSKB)
 			return 0;
 		secattr = selinux_netlbl_sock_getattr(sk, sid);
@@ -311,7 +312,7 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
  */
 void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
 {
-	struct sk_security_struct *sksec = sk->sk_security;
+	struct sk_security_struct *sksec = selinux_sock(sk);
 
 	if (family == PF_INET)
 		sksec->nlbl_state = NLBL_LABELED;
@@ -332,7 +333,7 @@ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
 int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
 {
 	int rc;
-	struct sk_security_struct *sksec = sk->sk_security;
+	struct sk_security_struct *sksec = selinux_sock(sk);
 	struct netlbl_lsm_secattr *secattr;
 
 	if (family != PF_INET && family != PF_INET6)
@@ -446,7 +447,7 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
 {
 	int rc = 0;
 	struct sock *sk = sock->sk;
-	struct sk_security_struct *sksec = sk->sk_security;
+	struct sk_security_struct *sksec = selinux_sock(sk);
 	struct netlbl_lsm_secattr secattr;
 
 	if (selinux_netlbl_option(level, optname) &&
@@ -482,7 +483,7 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
 int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
 {
 	int rc;
-	struct sk_security_struct *sksec = sk->sk_security;
+	struct sk_security_struct *sksec = selinux_sock(sk);
 	struct netlbl_lsm_secattr *secattr;
 
 	if (sksec->nlbl_state != NLBL_REQSKB &&
security/selinux/selinuxfs.c +2 -2
index 855a13053a81..1b4bed79101e 100644
@@ -1300,7 +1300,7 @@ static int sel_make_bools(void)
 		if (len >= PAGE_SIZE)
 			goto out;
 
-		isec = (struct inode_security_struct *)inode->i_security;
+		isec = (struct inode_security_struct *)selinux_inode(inode);
 		ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid);
 		if (ret) {
 			pr_warn_ratelimited("SELinux: no sid found, defaulting to security isid for %s\n",
@@ -1841,7 +1841,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
 		goto err;
 
 	inode->i_ino = ++sel_last_ino;
-	isec = (struct inode_security_struct *)inode->i_security;
+	isec = (struct inode_security_struct *)selinux_inode(inode);
 	isec->sid = SECINITSID_DEVNULL;
 	isec->sclass = SECCLASS_CHR_FILE;
 	isec->initialized = LABEL_INITIALIZED;
security/selinux/ss/services.c +2 -1
index e4a1c0dc561a..bfd09d0ddfd2 100644
@@ -52,6 +52,7 @@
 #include <linux/selinux.h>
 #include <linux/flex_array.h>
 #include <linux/vmalloc.h>
+#include <linux/lsm_hooks.h>
 #include <net/netlabel.h>
 
 #include "flask.h"
@@ -2659,7 +2660,7 @@ int security_fs_use(struct super_block *sb)
 {
 	int rc = 0;
 	struct ocontext *c;
-	struct superblock_security_struct *sbsec = sb->s_security;
+	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 	const char *fstype = sb->s_type->name;
 
 	read_lock(&policy_rwlock);
security/smack/smack.h +59 -2

78 lines not on this page · raw message

security/smack/smack_lsm.c +97 -252

828 lines not on this page · raw message

security/smack/smack_netfilter.c +4 -4
index e36d17835d4f..701a1cc1bdcc 100644
@@ -31,8 +31,8 @@ static unsigned int smack_ipv6_output(void *priv,
 	struct socket_smack *ssp;
 	struct smack_known *skp;
 
-	if (sk && sk->sk_security) {
-		ssp = sk->sk_security;
+	if (sk && smack_sock(sk)) {
+		ssp = smack_sock(sk);
 		skp = ssp->smk_out;
 		skb->secmark = skp->smk_secid;
 	}
@@ -49,8 +49,8 @@ static unsigned int smack_ipv4_output(void *priv,
 	struct socket_smack *ssp;
 	struct smack_known *skp;
 
-	if (sk && sk->sk_security) {
-		ssp = sk->sk_security;
+	if (sk && smack_sock(sk)) {
+		ssp = smack_sock(sk);
 		skp = ssp->smk_out;
 		skb->secmark = skp->smk_secid;
 	}
Signature · 7 lines
2.13.0


--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
maintainer
#12 lore raw

PATCH 5/9 LSM: Manage remaining security blobs

Hello.

I browsed https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1734686
and found a problem with how security blob is initialized.

Quoted 5 lines · Casey Schaufler
security/security.c +5 -0
+/**
+ * lsm_sock_alloc - allocate a composite sock blob
+ * @sock: the sock that needs a blob
+ * @priority: allocation mode
+ *

security/security.c int lsm_task_alloc(struct task_struct *task) · line 477

Quoted 10 lines
security/security.c +10 -0
+ * Allocate the sock blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_sock_alloc(struct sock *sock, gfp_t priority)
+{
+#ifdef CONFIG_SECURITY_LSM_DEBUG
+	if (sock->sk_security)
+		pr_info("%s: Inbound sock blob is not NULL.\n", __func__);
+#endif

If none of LSM modules use sock->sk_security, sock->sk_security is not initialized to NULL (and sk_prot_alloc() does not always use __GFP_ZERO).

Quoted 10 lines
security/security.c +8 -0
+	if (blob_sizes.lbs_sock == 0)
+		return 0;
+
+	sock->sk_security = kzalloc(blob_sizes.lbs_sock, priority);
+	if (sock->sk_security == NULL)
+		return -ENOMEM;
+	return 0;
+}

security/security.c EXPORT_SYMBOL(security_socket_getpeersec_dgram); · line 1857

Quoted 7 lines
security/security.c +4 -0
@@ -1609,12 +1851,18 @@ EXPORT_SYMBOL(security_socket_getpeersec_dgram);
 
 int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
 {
+	int rc = lsm_sock_alloc(sk, priority);
+
+	if (rc)
+		return rc;

In that report, no major LSMs are active because apparmor=0 is passed at kernel command line. Thus, security_sk_alloc() does not initialize sk->sk_security field and

security/security.c EXPORT_SYMBOL(security_socket_getpeersec_dgram); · line 1863

Quoted 6 lines
security/security.c +0 -0
 	return call_int_hook(sk_alloc_security, 0, sk, family, priority);
 }
 
 void security_sk_free(struct sock *sk)
 {
 	call_void_hook(sk_free_security, sk);

causes random oops at kfree().

security/security.c EXPORT_SYMBOL(security_socket_getpeersec_dgram); · line 1866

Quoted 3 lines
security/security.c +2 -0
+	kfree(sk->sk_security);
+	sk->sk_security = NULL;
 }

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#13 lore raw

PATCH 5/9 LSM: Manage remaining security blobs

Quoted 15 lines · Tetsuo Handa

Hello.

I browsed https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1734686
and found a problem with how security blob is initialized.

Quoted 9 lines · Casey Schaufler

+/**
+ * lsm_sock_alloc - allocate a composite sock blob
+ * @sock: the sock that needs a blob
+ * @priority: allocation mode
+ *
+ * Allocate the sock blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */

Quoted 8 lines

security/security.c int lsm_task_alloc(struct task_struct *task) · line 477

Quoted 6 lines
security/security.c +6 -0
+int lsm_sock_alloc(struct sock *sock, gfp_t priority)
+{
+#ifdef CONFIG_SECURITY_LSM_DEBUG
+	if (sock->sk_security)
+		pr_info("%s: Inbound sock blob is not NULL.\n", __func__);
+#endif

If none of LSM modules use sock->sk_security, sock->sk_security is not initialized to NULL (and sk_prot_alloc() does not always use __GFP_ZERO).

Thank you. I will be working on the next revision real soon and will include a fix for this.

Quoted 29 lines
Quoted 10 lines
security/security.c +8 -0
+	if (blob_sizes.lbs_sock == 0)
+		return 0;
+
+	sock->sk_security = kzalloc(blob_sizes.lbs_sock, priority);
+	if (sock->sk_security == NULL)
+		return -ENOMEM;
+	return 0;
+}

security/security.c EXPORT_SYMBOL(security_socket_getpeersec_dgram); · line 1857

Quoted 7 lines
security/security.c +4 -0
@@ -1609,12 +1851,18 @@ EXPORT_SYMBOL(security_socket_getpeersec_dgram);
 
 int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
 {
+	int rc = lsm_sock_alloc(sk, priority);
+
+	if (rc)
+		return rc;

In that report, no major LSMs are active because apparmor=0 is passed at kernel command line. Thus, security_sk_alloc() does not initialize sk->sk_security field and

security/security.c EXPORT_SYMBOL(security_socket_getpeersec_dgram); · line 1863

Quoted 6 lines
security/security.c +0 -0
 	return call_int_hook(sk_alloc_security, 0, sk, family, priority);
 }
 
 void security_sk_free(struct sock *sk)
 {
 	call_void_hook(sk_free_security, sk);

causes random oops at kfree().

Quoted 8 lines

security/security.c EXPORT_SYMBOL(security_socket_getpeersec_dgram); · line 1866

Quoted 3 lines
security/security.c +2 -0
+	kfree(sk->sk_security);
+	sk->sk_security = NULL;
 }

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

maintainer
#14 lore raw

PATCH 5/9 LSM: Manage remaining security blobs

Quoted 25 lines · Casey Schaufler
Quoted 15 lines · Tetsuo Handa

Hello.

I browsed https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1734686
and found a problem with how security blob is initialized.

Quoted 9 lines · Casey Schaufler

+/**
+ * lsm_sock_alloc - allocate a composite sock blob
+ * @sock: the sock that needs a blob
+ * @priority: allocation mode
+ *
+ * Allocate the sock blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */

Quoted 8 lines

Review

Quoted 6 lines
(quoted diff) +6 -0
+int lsm_sock_alloc(struct sock *sock, gfp_t priority)
+{
+#ifdef CONFIG_SECURITY_LSM_DEBUG
+	if (sock->sk_security)
+		pr_info("%s: Inbound sock blob is not NULL.\n", __func__);
+#endif

If none of LSM modules use sock->sk_security, sock->sk_security is not initialized to NULL (and sk_prot_alloc() does not always use __GFP_ZERO).

Quoted 3 lines

Thank you. I will be working on the next revision real soon and will include a fix for this.

Below is a patch to avoid uninitialized ->security field. (Strictly speaking, we can remove more lines because kmalloc(0) != NULL. But this patch does not remove such lines in case we want to check for ->security != NULL in future code.)

----------

security/security.c +27 -46
diff -ur linux-4.13.0-17.20.orig/security/security.c linux-4.13.0-17.20/security/security.c
@@ -324,12 +324,10 @@
  */
 int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (cred->security)
-		pr_info("%s: Inbound cred blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_cred == 0)
+	if (blob_sizes.lbs_cred == 0) {
+		cred->security = NULL;
 		return 0;
+	}
 
 	cred->security = kzalloc(blob_sizes.lbs_cred, gfp);
 	if (cred->security == NULL)
@@ -406,12 +404,10 @@
  */
 int lsm_file_alloc(struct file *file)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (file->f_security)
-		pr_info("%s: Inbound file blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_file == 0)
+	if (blob_sizes.lbs_file == 0) {
+		file->f_security = NULL;
 		return 0;
+	}
 
 	file->f_security = kzalloc(blob_sizes.lbs_file, GFP_KERNEL);
 	if (file->f_security == NULL)
@@ -487,12 +483,10 @@
  */
 int lsm_task_alloc(struct task_struct *task)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (task->security)
-		pr_info("%s: Inbound task blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_task == 0)
+	if (blob_sizes.lbs_task == 0) {
+		task->security = NULL;
 		return 0;
+	}
 
 	task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL);
 	if (task->security == NULL)
@@ -518,12 +512,10 @@
  */
 int lsm_inode_alloc(struct inode *inode)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (inode->i_security)
-		pr_info("%s: Inbound inode blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_inode == 0)
+	if (blob_sizes.lbs_inode == 0) {
+		inode->i_security = NULL;
 		return 0;
+	}
 
 	inode->i_security = kzalloc(blob_sizes.lbs_inode, GFP_KERNEL);
 	if (inode->i_security == NULL)
@@ -560,12 +552,10 @@
  */
 int lsm_ipc_alloc(struct kern_ipc_perm *kip)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (kip->security)
-		pr_info("%s: Inbound ipc blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_ipc == 0)
+	if (blob_sizes.lbs_ipc == 0) {
+		kip->security = NULL;
 		return 0;
+	}
 
 	kip->security = kzalloc(blob_sizes.lbs_ipc, GFP_KERNEL);
 	if (kip->security == NULL)
@@ -584,12 +574,10 @@
  */
 int lsm_key_alloc(struct key *key)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (key->security)
-		pr_info("%s: Inbound key blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_key == 0)
+	if (blob_sizes.lbs_key == 0) {
+		key->security = NULL;
 		return 0;
+	}
 
 	key->security = kzalloc(blob_sizes.lbs_key, GFP_KERNEL);
 	if (key->security == NULL)
@@ -608,12 +596,10 @@
  */
 int lsm_msg_msg_alloc(struct msg_msg *mp)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (mp->security)
-		pr_info("%s: Inbound msg_msg blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_msg_msg == 0)
+	if (blob_sizes.lbs_msg_msg == 0) {
+		mp->security = NULL;
 		return 0;
+	}
 
 	mp->security = kzalloc(blob_sizes.lbs_msg_msg, GFP_KERNEL);
 	if (mp->security == NULL)
@@ -632,13 +618,10 @@
  */
 int lsm_sock_alloc(struct sock *sock, gfp_t priority)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (sock->sk_security)
-		pr_info("%s: Inbound sock blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_sock == 0)
+	if (blob_sizes.lbs_sock == 0) {
+		sock->sk_security = NULL;
 		return 0;
-
+	}
 	sock->sk_security = kzalloc(blob_sizes.lbs_sock, priority);
 	if (sock->sk_security == NULL)
 		return -ENOMEM;
@@ -655,12 +638,10 @@
  */
 int lsm_superblock_alloc(struct super_block *sb)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (sb->s_security)
-		pr_info("%s: Inbound superblock blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_superblock == 0)
+	if (blob_sizes.lbs_superblock == 0) {
+		sb->s_security = NULL;
 		return 0;
+	}
 
 	sb->s_security = kzalloc(blob_sizes.lbs_superblock, GFP_KERNEL);
 	if (sb->s_security == NULL)

----------

I noticed that Ubuntu 17.10 kernel crashes upon boot if the administrator tried to specify one of (or none of) major LSM modules other than AppArmor using security= parameter. It turned out that the cause is that we are failing to disable AppArmor when security= parameter is used (and apparmor=0 is not used).

----------

[    0.000000] Linux version 4.13.0-17-generic (buildd at lcy01-amd64-011) (gcc version 7.2.0 (Ubuntu 7.2.0-8ubuntu3)) #20-Ubuntu SMP Mon Nov 6 10:04:08 UTC 2017 (Ubuntu 4.13.0-17.20-generic 4.13.8)
[    0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.13.0-17-generic root=UUID=379f2d1d-c10e-4423-a3fd-a64863cda7b0 ro console=ttyS0,115200n8 console=tty security=none
(...snipped...)
[    0.000000] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-4.13.0-17-generic root=UUID=379f2d1d-c10e-4423-a3fd-a64863cda7b0 ro console=ttyS0,115200n8 console=tty security=none
[    0.000000] LSM: command line set 'none' security module(s).
(...snipped...)
[    0.040322] Security Framework initialized
[    0.041502] Yama: becoming mindful.
[    0.050757] BUG: unable to handle kernel NULL pointer dereference at 0000000000000020
[    0.052000] IP: apparmor_init+0x26f/0x2fa
[    0.052000] PGD 0 
[    0.052000] P4D 0 
[    0.052000] 
[    0.052000] Oops: 0002 [#1] SMP
[    0.052000] Modules linked in:
[    0.052000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.13.0-17-generic #20-Ubuntu
[    0.052000] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/02/2015
[    0.052000] task: ffffffffa6410480 task.stack: ffffffffa6400000
[    0.052000] RIP: 0010:apparmor_init+0x26f/0x2fa
[    0.052000] RSP: 0000:ffffffffa6403e38 EFLAGS: 00010206
[    0.052000] RAX: ffff8c6279012800 RBX: 0000000000000000 RCX: ffff8c6279012b98
[    0.052000] RDX: 0000000000000020 RSI: 0000000000000080 RDI: 0000000000000000
[    0.052000] RBP: ffffffffa6403e78 R08: ffff8c6278820000 R09: ffff8c6279006a00
[    0.052000] R10: ffffffffa6403dd0 R11: 0000000000020120 R12: ffffffffa6457fe0
[    0.052000] R13: 0000000000017210 R14: ffffffffa636e3e0 R15: 0000000000000000
[    0.052000] FS:  0000000000000000(0000) GS:ffff8c6279600000(0000) knlGS:0000000000000000
[    0.052000] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.052000] CR2: 0000000000000020 CR3: 000000006bc09000 CR4: 00000000000406b0
[    0.052000] Call Trace:
[    0.052000]  do_security_initcalls+0x1c/0x25
[    0.052000]  security_init+0x49/0x4d
[    0.052000]  start_kernel+0x465/0x4e1
[    0.052000]  ? early_idt_handler_array+0x120/0x120
[    0.052000]  x86_64_start_reservations+0x24/0x26
[    0.052000]  x86_64_start_kernel+0x13e/0x161
[    0.052000]  secondary_startup_64+0x9f/0x9f
[    0.052000] Code: ff 48 8b 05 ac 43 3f 00 48 63 15 0d 2d e8 ff 49 03 54 24 78 48 8b 40 68 48 89 c1 48 81 c1 98 03 00 00 74 07 f0 ff 80 98 03 00 00 <48> 89 0a be 3b 00 00 00 48 c7 c2 13 96 2c a6 48 c7 c7 00 38 38 
[    0.052000] RIP: apparmor_init+0x26f/0x2fa RSP: ffffffffa6403e38
[    0.052000] CR2: 0000000000000020
[    0.052000] ---[ end trace 754b9ec1da9bb5fc ]---
[    0.052000] Kernel panic - not syncing: Attempted to kill the idle task!
[    0.052000] ---[ end Kernel panic - not syncing: Attempted to kill the idle task!
[    0.000000] Linux version 4.13.0-17-generic (buildd at lcy01-amd64-011) (gcc version 7.2.0 (Ubuntu 7.2.0-8ubuntu3)) #20-Ubuntu SMP Mon Nov 6 10:04:08 UTC 2017 (Ubuntu 4.13.0-17.20-generic 4.13.8)
[    0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.13.0-17-generic root=UUID=379f2d1d-c10e-4423-a3fd-a64863cda7b0 ro console=ttyS0,115200n8 console=tty security=selinux
(...snipped...)
[    0.000000] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-4.13.0-17-generic root=UUID=379f2d1d-c10e-4423-a3fd-a64863cda7b0 ro console=ttyS0,115200n8 console=tty security=selinux
[    0.000000] LSM: command line set 'selinux' security module(s).
(...snipped...)
[    0.038014] Security Framework initialized
[    0.039119] Yama: becoming mindful.
[    0.040019] SELinux:  Disabled at boot.
[    0.049252] AppArmor: AppArmor initialized
[    0.076808] Dentry cache hash table entries: 524288 (order: 10, 4194304 bytes)
[    0.091667] Inode-cache hash table entries: 262144 (order: 9, 2097152 bytes)
[    0.092461] Mount-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.096417] Mountpoint-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.099552] Disabled fast string operations
[    0.100007] CPU: Physical Processor ID: 0
[    0.101090] ENERGY_PERF_BIAS: Set to 'normal', was 'performance'
[    0.102650] ENERGY_PERF_BIAS: View and update with x86_energy_perf_policy(8)
[    0.104008] mce: CPU supports 0 MCE banks
[    0.105095] Last level iTLB entries: 4KB 512, 2MB 8, 4MB 8
[    0.108003] Last level dTLB entries: 4KB 512, 2MB 32, 4MB 32, 1GB 0
[    0.109930] Freeing SMP alternatives memory: 36K
[    0.121143] smpboot: Max logical packages: 128
[    0.124000] x2apic enabled
[    0.124026] Switched APIC routing to physical x2apic.
[    0.130183] ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1
[    0.132000] smpboot: CPU0: Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz (family: 0x6, model: 0x2a, stepping: 0x7)
[    0.132556] Performance Events: SandyBridge events, core PMU driver.
[    0.135024] core: CPUID marked event: 'cpu cycles' unavailable
[    0.136007] core: CPUID marked event: 'instructions' unavailable
[    0.138399] core: CPUID marked event: 'bus cycles' unavailable
[    0.140008] core: CPUID marked event: 'cache references' unavailable
[    0.142397] core: CPUID marked event: 'cache misses' unavailable
[    0.144004] core: CPUID marked event: 'branch instructions' unavailable
[    0.146528] core: CPUID marked event: 'branch misses' unavailable
[    0.148022] ... version:                1
[    0.149754] ... bit width:              48
[    0.151620] ... generic registers:      4
[    0.152006] ... value mask:             0000ffffffffffff
[    0.154124] ... max period:             000000007fffffff
[    0.156004] ... fixed-purpose events:   0
[    0.157598] ... event mask:             000000000000000f
[    0.159990] Hierarchical SRCU implementation.
[    0.160195] BUG: unable to handle kernel NULL pointer dereference at 000000000000000b
[    0.163303] IP: __kmalloc_node+0x135/0x2a0
[    0.164000] PGD 0 
[    0.164000] P4D 0 
[    0.164000] 
[    0.164000] Oops: 0000 [#1] SMP
[    0.164000] Modules linked in:
[    0.164000] CPU: 0 PID: 2 Comm: kthreadd Not tainted 4.13.0-17-generic #20-Ubuntu
[    0.164000] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/02/2015
[    0.164000] task: ffff980cf8658000 task.stack: ffffb809c0654000
[    0.164000] RIP: 0010:__kmalloc_node+0x135/0x2a0
[    0.164000] RSP: 0000:ffffb809c0657c70 EFLAGS: 00010246
[    0.164000] RAX: 0000000000000000 RBX: 00000000014080c0 RCX: 0000000000000178
[    0.164000] RDX: 0000000000000177 RSI: 0000000000000000 RDI: 000000000001f420
[    0.164000] RBP: ffffb809c0657cb0 R08: ffff980cf961f420 R09: ffff980cf9007900
[    0.164000] R10: ffffffffffffc000 R11: ffffd809bfffffff R12: 00000000014080c0
[    0.164000] R13: 0000000000000020 R14: 000000000000000b R15: ffff980cf9007900
[    0.164000] FS:  0000000000000000(0000) GS:ffff980cf9600000(0000) knlGS:0000000000000000
[    0.164000] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.164000] CR2: 000000000000000b CR3: 000000012b009000 CR4: 00000000000406f0
[    0.164000] Call Trace:
[    0.164000]  ? __vmalloc_node_range+0xd4/0x260
[    0.164000]  __vmalloc_node_range+0xd4/0x260
[    0.164000]  copy_process.part.31+0x662/0x1ae0
[    0.164000]  ? _do_fork+0xdf/0x3f0
[    0.164000]  ? kthread_create_on_node+0x70/0x70
[    0.164000]  ? pick_next_task_fair+0x48e/0x560
[    0.164000]  _do_fork+0xdf/0x3f0
[    0.164000]  ? __schedule+0x293/0x890
[    0.164000]  kernel_thread+0x29/0x30
[    0.164000]  kthreadd+0x29f/0x2f0
[    0.164000]  ? kthread_create_on_cpu+0xa0/0xa0
[    0.164000]  ret_from_fork+0x25/0x30
[    0.164000] Code: 89 cf 4c 89 4d c0 e8 0b 7f 01 00 49 89 c7 4c 8b 4d c0 4d 85 ff 0f 85 47 ff ff ff 45 31 f6 eb 3c 49 63 47 20 49 8b 3f 48 8d 4a 01 <49> 8b 1c 06 4c 89 f0 65 48 0f c7 0f 0f 94 c0 84 c0 0f 84 20 ff 
[    0.164000] RIP: __kmalloc_node+0x135/0x2a0 RSP: ffffb809c0657c70
[    0.164000] CR2: 000000000000000b
[    0.164000] ---[ end trace 8bd0169accb86cdb ]---
[    0.000000] Linux version 4.13.0-17-generic (buildd at lcy01-amd64-011) (gcc version 7.2.0 (Ubuntu 7.2.0-8ubuntu3)) #20-Ubuntu SMP Mon Nov 6 10:04:08 UTC 2017 (Ubuntu 4.13.0-17.20-generic 4.13.8)
[    0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.13.0-17-generic root=UUID=379f2d1d-c10e-4423-a3fd-a64863cda7b0 ro console=ttyS0,115200n8 console=tty security=tomoyo
(...snipped...)
[    0.000000] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-4.13.0-17-generic root=UUID=379f2d1d-c10e-4423-a3fd-a64863cda7b0 ro console=ttyS0,115200n8 console=tty security=tomoyo
[    0.000000] LSM: command line set 'tomoyo' security module(s).
(...snipped...)
[    0.038327] Security Framework initialized
[    0.040005] Yama: becoming mindful.
[    0.040999] TOMOYO Linux initialized
[    0.049585] AppArmor: AppArmor initialized
[    0.077621] Dentry cache hash table entries: 524288 (order: 10, 4194304 bytes)
[    0.092942] Inode-cache hash table entries: 262144 (order: 9, 2097152 bytes)
[    0.095309] Mount-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.096408] Mountpoint-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.100988] Disabled fast string operations
[    0.102220] CPU: Physical Processor ID: 0
[    0.103379] ENERGY_PERF_BIAS: Set to 'normal', was 'performance'
[    0.104004] ENERGY_PERF_BIAS: View and update with x86_energy_perf_policy(8)
[    0.105951] mce: CPU supports 0 MCE banks
[    0.108017] Last level iTLB entries: 4KB 512, 2MB 8, 4MB 8
[    0.109524] Last level dTLB entries: 4KB 512, 2MB 32, 4MB 32, 1GB 0
[    0.111426] Freeing SMP alternatives memory: 36K
[    0.117374] BUG: unable to handle kernel NULL pointer dereference at 0000000000000003
[    0.119676] IP: __kmalloc+0x9b/0x200
[    0.120000] PGD 0 
[    0.120000] P4D 0 
[    0.120000] 
[    0.120000] Oops: 0000 [#1] SMP
[    0.120000] Modules linked in:
[    0.120000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.13.0-17-generic #20-Ubuntu
[    0.120000] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/02/2015
[    0.120000] task: ffffffff9a810480 task.stack: ffffffff9a800000
[    0.120000] RIP: 0010:__kmalloc+0x9b/0x200
[    0.120000] RSP: 0000:ffffffff9a803c58 EFLAGS: 00010206
[    0.120000] RAX: 0000000000000000 RBX: 0000000000008000 RCX: 0000000000000037
[    0.120000] RDX: 0000000000000036 RSI: 0000000000000000 RDI: 000000000001f3e0
[    0.120000] RBP: ffffffff9a803c88 R08: ffff9a55b961f3e0 R09: ffff9a55b9007c00
[    0.120000] R10: 0000000000000000 R11: 00000000000200c8 R12: 0000000000000003
[    0.120000] R13: 00000000014080c0 R14: 0000000000000008 R15: ffff9a55b9007c00
[    0.120000] FS:  0000000000000000(0000) GS:ffff9a55b9600000(0000) knlGS:0000000000000000
[    0.120000] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.120000] CR2: 0000000000000003 CR3: 00000000ba809000 CR4: 00000000000406f0
[    0.120000] Call Trace:
[    0.120000]  ? security_prepare_creds+0x73/0x90
[    0.120000]  security_prepare_creds+0x73/0x90
[    0.120000]  prepare_creds+0xbd/0xf0
[    0.120000]  copy_creds+0x2f/0x120
[    0.120000]  copy_process.part.31+0x2e5/0x1ae0
[    0.120000]  ? enqueue_task_fair+0xaf/0x6b0
[    0.120000]  ? kthread_create_on_cpu+0xa0/0xa0
[    0.120000]  ? sched_clock+0x9/0x10
[    0.120000]  _do_fork+0xdf/0x3f0
[    0.120000]  ? update_rq_clock+0x30/0x80
[    0.120000]  ? do_set_mempolicy+0x30/0x130
[    0.120000]  kernel_thread+0x29/0x30
[    0.120000]  rest_init+0x74/0xc0
[    0.120000]  start_kernel+0x4c0/0x4e1
[    0.120000]  ? early_idt_handler_array+0x120/0x120
[    0.120000]  x86_64_start_reservations+0x24/0x26
[    0.120000]  x86_64_start_kernel+0x13e/0x161
[    0.120000]  secondary_startup_64+0x9f/0x9f
[    0.120000] Code: 08 65 4c 03 05 f7 07 3e 66 49 83 78 10 00 4d 8b 20 0f 84 f7 00 00 00 4d 85 e4 0f 84 ee 00 00 00 49 63 41 20 49 8b 39 48 8d 4a 01 <49> 8b 1c 04 4c 89 e0 65 48 0f c7 0f 0f 94 c0 84 c0 74 bb 49 63 
[    0.120000] RIP: __kmalloc+0x9b/0x200 RSP: ffffffff9a803c58
[    0.120000] CR2: 0000000000000003
[    0.120000] ---[ end trace bee324c32248c3f4 ]---
[    0.120000] Kernel panic - not syncing: Attempted to kill the idle task!
[    0.120000] ---[ end Kernel panic - not syncing: Attempted to kill the idle task!

----------

cred->security for AppArmor will not be allocated (and therefore will trigger NULL pointer dereference) because security_add_blobs(&apparmor_blob_sizes) is not called when the administrator asked not to enable AppArmor. We need to reset apparmor_enabled to 0 in order to prevent apparmor_init() from calling set_init_ctx().

----------
static inline struct aa_task_ctx *apparmor_cred(const struct cred *cred) {

#ifdef CONFIG_SECURITY_STACKING
        return cred->security + apparmor_blob_sizes.lbs_cred;
#else
        return cred->security;

#endif
}

static int __init set_init_ctx(void)

{
        struct cred *cred = (struct cred *)current->real_cred;
        struct aa_task_ctx *ctx;

        lsm_early_cred(cred);
        ctx = apparmor_cred(cred);

        ctx->label = aa_get_label(ns_unconfined(root_ns));

        return 0;
}

----------

Thus, please also apply below patch.

----------

security/apparmor/lsm.c +2 -0
diff -ur linux-4.13.0-17.20.orig/security/apparmor/lsm.c linux-4.13.0-17.20/security/apparmor/lsm.c
@@ -1562,6 +1562,8 @@
 		    security_module_enable("apparmor",
 				IS_ENABLED(CONFIG_SECURITY_APPARMOR_STACKED)))
 			security_add_blobs(&apparmor_blob_sizes);
+		else
+			apparmor_enabled = 0;
 		finish = 1;
 		return 0;
 	}

----------
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#15 lore raw

PATCH 5/9 LSM: Manage remaining security blobs

Quoted 25 lines · Tetsuo Handa
Quoted 24 lines · Casey Schaufler
Quoted 23 lines · Tetsuo Handa

Hello.

I browsed https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1734686
and found a problem with how security blob is initialized.

Quoted 5 lines · Casey Schaufler
(quoted diff) +5 -0
+/**
+ * lsm_sock_alloc - allocate a composite sock blob
+ * @sock: the sock that needs a blob
+ * @priority: allocation mode
+ *

Review

Quoted 10 lines
(quoted diff) +10 -0
+ * Allocate the sock blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_sock_alloc(struct sock *sock, gfp_t priority)
+{
+#ifdef CONFIG_SECURITY_LSM_DEBUG
+	if (sock->sk_security)
+		pr_info("%s: Inbound sock blob is not NULL.\n", __func__);
+#endif

If none of LSM modules use sock->sk_security, sock->sk_security is not initialized to NULL (and sk_prot_alloc() does not always use __GFP_ZERO).

Quoted 7 lines
Quoted 3 lines

Thank you. I will be working on the next revision real soon and will include a fix for this.

Below is a patch to avoid uninitialized ->security field. (Strictly speaking, we can remove more lines because kmalloc(0) != NULL. But this patch does not remove such lines in case we want to check for ->security != NULL in future code.)

Thank you. I will incorporate this.

Quoted 383 lines

----------
diff -ur linux-4.13.0-17.20.orig/security/security.c linux-4.13.0-17.20/security/security.c

security/security.c +27 -47
@@ -324,12 +324,10 @@
  */
 int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (cred->security)
-		pr_info("%s: Inbound cred blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_cred == 0)
+	if (blob_sizes.lbs_cred == 0) {
+		cred->security = NULL;
 		return 0;
+	}
 
 	cred->security = kzalloc(blob_sizes.lbs_cred, gfp);
 	if (cred->security == NULL)
@@ -406,12 +404,10 @@
  */
 int lsm_file_alloc(struct file *file)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (file->f_security)
-		pr_info("%s: Inbound file blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_file == 0)
+	if (blob_sizes.lbs_file == 0) {
+		file->f_security = NULL;
 		return 0;
+	}
 
 	file->f_security = kzalloc(blob_sizes.lbs_file, GFP_KERNEL);
 	if (file->f_security == NULL)
@@ -487,12 +483,10 @@
  */
 int lsm_task_alloc(struct task_struct *task)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (task->security)
-		pr_info("%s: Inbound task blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_task == 0)
+	if (blob_sizes.lbs_task == 0) {
+		task->security = NULL;
 		return 0;
+	}
 
 	task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL);
 	if (task->security == NULL)
@@ -518,12 +512,10 @@
  */
 int lsm_inode_alloc(struct inode *inode)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (inode->i_security)
-		pr_info("%s: Inbound inode blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_inode == 0)
+	if (blob_sizes.lbs_inode == 0) {
+		inode->i_security = NULL;
 		return 0;
+	}
 
 	inode->i_security = kzalloc(blob_sizes.lbs_inode, GFP_KERNEL);
 	if (inode->i_security == NULL)
@@ -560,12 +552,10 @@
  */
 int lsm_ipc_alloc(struct kern_ipc_perm *kip)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (kip->security)
-		pr_info("%s: Inbound ipc blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_ipc == 0)
+	if (blob_sizes.lbs_ipc == 0) {
+		kip->security = NULL;
 		return 0;
+	}
 
 	kip->security = kzalloc(blob_sizes.lbs_ipc, GFP_KERNEL);
 	if (kip->security == NULL)
@@ -584,12 +574,10 @@
  */
 int lsm_key_alloc(struct key *key)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (key->security)
-		pr_info("%s: Inbound key blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_key == 0)
+	if (blob_sizes.lbs_key == 0) {
+		key->security = NULL;
 		return 0;
+	}
 
 	key->security = kzalloc(blob_sizes.lbs_key, GFP_KERNEL);
 	if (key->security == NULL)
@@ -608,12 +596,10 @@
  */
 int lsm_msg_msg_alloc(struct msg_msg *mp)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (mp->security)
-		pr_info("%s: Inbound msg_msg blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_msg_msg == 0)
+	if (blob_sizes.lbs_msg_msg == 0) {
+		mp->security = NULL;
 		return 0;
+	}
 
 	mp->security = kzalloc(blob_sizes.lbs_msg_msg, GFP_KERNEL);
 	if (mp->security == NULL)
@@ -632,13 +618,10 @@
  */
 int lsm_sock_alloc(struct sock *sock, gfp_t priority)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (sock->sk_security)
-		pr_info("%s: Inbound sock blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_sock == 0)
+	if (blob_sizes.lbs_sock == 0) {
+		sock->sk_security = NULL;
 		return 0;
-
+	}
 	sock->sk_security = kzalloc(blob_sizes.lbs_sock, priority);
 	if (sock->sk_security == NULL)
 		return -ENOMEM;
@@ -655,12 +638,10 @@
  */
 int lsm_superblock_alloc(struct super_block *sb)
 {
-#ifdef CONFIG_SECURITY_LSM_DEBUG
-	if (sb->s_security)
-		pr_info("%s: Inbound superblock blob is not NULL.\n", __func__);
-#endif
-	if (blob_sizes.lbs_superblock == 0)
+	if (blob_sizes.lbs_superblock == 0) {
+		sb->s_security = NULL;
 		return 0;
+	}
 
 	sb->s_security = kzalloc(blob_sizes.lbs_superblock, GFP_KERNEL);
 	if (sb->s_security == NULL)
----------

I noticed that Ubuntu 17.10 kernel crashes upon boot if the administrator tried to specify one of (or none of) major LSM modules other than AppArmor using security= parameter. It turned out that the cause is that we are failing to disable AppArmor when security= parameter is used (and apparmor=0 is not used).

----------

[    0.000000] Linux version 4.13.0-17-generic (buildd at lcy01-amd64-011) (gcc version 7.2.0 (Ubuntu 7.2.0-8ubuntu3)) #20-Ubuntu SMP Mon Nov 6 10:04:08 UTC 2017 (Ubuntu 4.13.0-17.20-generic 4.13.8)
[    0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.13.0-17-generic root=UUID=379f2d1d-c10e-4423-a3fd-a64863cda7b0 ro console=ttyS0,115200n8 console=tty security=none
(...snipped...)
[    0.000000] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-4.13.0-17-generic root=UUID=379f2d1d-c10e-4423-a3fd-a64863cda7b0 ro console=ttyS0,115200n8 console=tty security=none
[    0.000000] LSM: command line set 'none' security module(s).
(...snipped...)
[    0.040322] Security Framework initialized
[    0.041502] Yama: becoming mindful.
[    0.050757] BUG: unable to handle kernel NULL pointer dereference at 0000000000000020
[    0.052000] IP: apparmor_init+0x26f/0x2fa
[    0.052000] PGD 0 
[    0.052000] P4D 0 
[    0.052000] 
[    0.052000] Oops: 0002 [#1] SMP
[    0.052000] Modules linked in:
[    0.052000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.13.0-17-generic #20-Ubuntu
[    0.052000] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/02/2015
[    0.052000] task: ffffffffa6410480 task.stack: ffffffffa6400000
[    0.052000] RIP: 0010:apparmor_init+0x26f/0x2fa
[    0.052000] RSP: 0000:ffffffffa6403e38 EFLAGS: 00010206
[    0.052000] RAX: ffff8c6279012800 RBX: 0000000000000000 RCX: ffff8c6279012b98
[    0.052000] RDX: 0000000000000020 RSI: 0000000000000080 RDI: 0000000000000000
[    0.052000] RBP: ffffffffa6403e78 R08: ffff8c6278820000 R09: ffff8c6279006a00
[    0.052000] R10: ffffffffa6403dd0 R11: 0000000000020120 R12: ffffffffa6457fe0
[    0.052000] R13: 0000000000017210 R14: ffffffffa636e3e0 R15: 0000000000000000
[    0.052000] FS:  0000000000000000(0000) GS:ffff8c6279600000(0000) knlGS:0000000000000000
[    0.052000] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.052000] CR2: 0000000000000020 CR3: 000000006bc09000 CR4: 00000000000406b0
[    0.052000] Call Trace:
[    0.052000]  do_security_initcalls+0x1c/0x25
[    0.052000]  security_init+0x49/0x4d
[    0.052000]  start_kernel+0x465/0x4e1
[    0.052000]  ? early_idt_handler_array+0x120/0x120
[    0.052000]  x86_64_start_reservations+0x24/0x26
[    0.052000]  x86_64_start_kernel+0x13e/0x161
[    0.052000]  secondary_startup_64+0x9f/0x9f
[    0.052000] Code: ff 48 8b 05 ac 43 3f 00 48 63 15 0d 2d e8 ff 49 03 54 24 78 48 8b 40 68 48 89 c1 48 81 c1 98 03 00 00 74 07 f0 ff 80 98 03 00 00 <48> 89 0a be 3b 00 00 00 48 c7 c2 13 96 2c a6 48 c7 c7 00 38 38 
[    0.052000] RIP: apparmor_init+0x26f/0x2fa RSP: ffffffffa6403e38
[    0.052000] CR2: 0000000000000020
[    0.052000] ---[ end trace 754b9ec1da9bb5fc ]---
[    0.052000] Kernel panic - not syncing: Attempted to kill the idle task!
[    0.052000] ---[ end Kernel panic - not syncing: Attempted to kill the idle task!
[    0.000000] Linux version 4.13.0-17-generic (buildd at lcy01-amd64-011) (gcc version 7.2.0 (Ubuntu 7.2.0-8ubuntu3)) #20-Ubuntu SMP Mon Nov 6 10:04:08 UTC 2017 (Ubuntu 4.13.0-17.20-generic 4.13.8)
[    0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.13.0-17-generic root=UUID=379f2d1d-c10e-4423-a3fd-a64863cda7b0 ro console=ttyS0,115200n8 console=tty security=selinux
(...snipped...)
[    0.000000] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-4.13.0-17-generic root=UUID=379f2d1d-c10e-4423-a3fd-a64863cda7b0 ro console=ttyS0,115200n8 console=tty security=selinux
[    0.000000] LSM: command line set 'selinux' security module(s).
(...snipped...)
[    0.038014] Security Framework initialized
[    0.039119] Yama: becoming mindful.
[    0.040019] SELinux:  Disabled at boot.
[    0.049252] AppArmor: AppArmor initialized
[    0.076808] Dentry cache hash table entries: 524288 (order: 10, 4194304 bytes)
[    0.091667] Inode-cache hash table entries: 262144 (order: 9, 2097152 bytes)
[    0.092461] Mount-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.096417] Mountpoint-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.099552] Disabled fast string operations
[    0.100007] CPU: Physical Processor ID: 0
[    0.101090] ENERGY_PERF_BIAS: Set to 'normal', was 'performance'
[    0.102650] ENERGY_PERF_BIAS: View and update with x86_energy_perf_policy(8)
[    0.104008] mce: CPU supports 0 MCE banks
[    0.105095] Last level iTLB entries: 4KB 512, 2MB 8, 4MB 8
[    0.108003] Last level dTLB entries: 4KB 512, 2MB 32, 4MB 32, 1GB 0
[    0.109930] Freeing SMP alternatives memory: 36K
[    0.121143] smpboot: Max logical packages: 128
[    0.124000] x2apic enabled
[    0.124026] Switched APIC routing to physical x2apic.
[    0.130183] ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1
[    0.132000] smpboot: CPU0: Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz (family: 0x6, model: 0x2a, stepping: 0x7)
[    0.132556] Performance Events: SandyBridge events, core PMU driver.
[    0.135024] core: CPUID marked event: 'cpu cycles' unavailable
[    0.136007] core: CPUID marked event: 'instructions' unavailable
[    0.138399] core: CPUID marked event: 'bus cycles' unavailable
[    0.140008] core: CPUID marked event: 'cache references' unavailable
[    0.142397] core: CPUID marked event: 'cache misses' unavailable
[    0.144004] core: CPUID marked event: 'branch instructions' unavailable
[    0.146528] core: CPUID marked event: 'branch misses' unavailable
[    0.148022] ... version:                1
[    0.149754] ... bit width:              48
[    0.151620] ... generic registers:      4
[    0.152006] ... value mask:             0000ffffffffffff
[    0.154124] ... max period:             000000007fffffff
[    0.156004] ... fixed-purpose events:   0
[    0.157598] ... event mask:             000000000000000f
[    0.159990] Hierarchical SRCU implementation.
[    0.160195] BUG: unable to handle kernel NULL pointer dereference at 000000000000000b
[    0.163303] IP: __kmalloc_node+0x135/0x2a0
[    0.164000] PGD 0 
[    0.164000] P4D 0 
[    0.164000] 
[    0.164000] Oops: 0000 [#1] SMP
[    0.164000] Modules linked in:
[    0.164000] CPU: 0 PID: 2 Comm: kthreadd Not tainted 4.13.0-17-generic #20-Ubuntu
[    0.164000] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/02/2015
[    0.164000] task: ffff980cf8658000 task.stack: ffffb809c0654000
[    0.164000] RIP: 0010:__kmalloc_node+0x135/0x2a0
[    0.164000] RSP: 0000:ffffb809c0657c70 EFLAGS: 00010246
[    0.164000] RAX: 0000000000000000 RBX: 00000000014080c0 RCX: 0000000000000178
[    0.164000] RDX: 0000000000000177 RSI: 0000000000000000 RDI: 000000000001f420
[    0.164000] RBP: ffffb809c0657cb0 R08: ffff980cf961f420 R09: ffff980cf9007900
[    0.164000] R10: ffffffffffffc000 R11: ffffd809bfffffff R12: 00000000014080c0
[    0.164000] R13: 0000000000000020 R14: 000000000000000b R15: ffff980cf9007900
[    0.164000] FS:  0000000000000000(0000) GS:ffff980cf9600000(0000) knlGS:0000000000000000
[    0.164000] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.164000] CR2: 000000000000000b CR3: 000000012b009000 CR4: 00000000000406f0
[    0.164000] Call Trace:
[    0.164000]  ? __vmalloc_node_range+0xd4/0x260
[    0.164000]  __vmalloc_node_range+0xd4/0x260
[    0.164000]  copy_process.part.31+0x662/0x1ae0
[    0.164000]  ? _do_fork+0xdf/0x3f0
[    0.164000]  ? kthread_create_on_node+0x70/0x70
[    0.164000]  ? pick_next_task_fair+0x48e/0x560
[    0.164000]  _do_fork+0xdf/0x3f0
[    0.164000]  ? __schedule+0x293/0x890
[    0.164000]  kernel_thread+0x29/0x30
[    0.164000]  kthreadd+0x29f/0x2f0
[    0.164000]  ? kthread_create_on_cpu+0xa0/0xa0
[    0.164000]  ret_from_fork+0x25/0x30
[    0.164000] Code: 89 cf 4c 89 4d c0 e8 0b 7f 01 00 49 89 c7 4c 8b 4d c0 4d 85 ff 0f 85 47 ff ff ff 45 31 f6 eb 3c 49 63 47 20 49 8b 3f 48 8d 4a 01 <49> 8b 1c 06 4c 89 f0 65 48 0f c7 0f 0f 94 c0 84 c0 0f 84 20 ff 
[    0.164000] RIP: __kmalloc_node+0x135/0x2a0 RSP: ffffb809c0657c70
[    0.164000] CR2: 000000000000000b
[    0.164000] ---[ end trace 8bd0169accb86cdb ]---
[    0.000000] Linux version 4.13.0-17-generic (buildd at lcy01-amd64-011) (gcc version 7.2.0 (Ubuntu 7.2.0-8ubuntu3)) #20-Ubuntu SMP Mon Nov 6 10:04:08 UTC 2017 (Ubuntu 4.13.0-17.20-generic 4.13.8)
[    0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.13.0-17-generic root=UUID=379f2d1d-c10e-4423-a3fd-a64863cda7b0 ro console=ttyS0,115200n8 console=tty security=tomoyo
(...snipped...)
[    0.000000] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-4.13.0-17-generic root=UUID=379f2d1d-c10e-4423-a3fd-a64863cda7b0 ro console=ttyS0,115200n8 console=tty security=tomoyo
[    0.000000] LSM: command line set 'tomoyo' security module(s).
(...snipped...)
[    0.038327] Security Framework initialized
[    0.040005] Yama: becoming mindful.
[    0.040999] TOMOYO Linux initialized
[    0.049585] AppArmor: AppArmor initialized
[    0.077621] Dentry cache hash table entries: 524288 (order: 10, 4194304 bytes)
[    0.092942] Inode-cache hash table entries: 262144 (order: 9, 2097152 bytes)
[    0.095309] Mount-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.096408] Mountpoint-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.100988] Disabled fast string operations
[    0.102220] CPU: Physical Processor ID: 0
[    0.103379] ENERGY_PERF_BIAS: Set to 'normal', was 'performance'
[    0.104004] ENERGY_PERF_BIAS: View and update with x86_energy_perf_policy(8)
[    0.105951] mce: CPU supports 0 MCE banks
[    0.108017] Last level iTLB entries: 4KB 512, 2MB 8, 4MB 8
[    0.109524] Last level dTLB entries: 4KB 512, 2MB 32, 4MB 32, 1GB 0
[    0.111426] Freeing SMP alternatives memory: 36K
[    0.117374] BUG: unable to handle kernel NULL pointer dereference at 0000000000000003
[    0.119676] IP: __kmalloc+0x9b/0x200
[    0.120000] PGD 0 
[    0.120000] P4D 0 
[    0.120000] 
[    0.120000] Oops: 0000 [#1] SMP
[    0.120000] Modules linked in:
[    0.120000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.13.0-17-generic #20-Ubuntu
[    0.120000] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/02/2015
[    0.120000] task: ffffffff9a810480 task.stack: ffffffff9a800000
[    0.120000] RIP: 0010:__kmalloc+0x9b/0x200
[    0.120000] RSP: 0000:ffffffff9a803c58 EFLAGS: 00010206
[    0.120000] RAX: 0000000000000000 RBX: 0000000000008000 RCX: 0000000000000037
[    0.120000] RDX: 0000000000000036 RSI: 0000000000000000 RDI: 000000000001f3e0
[    0.120000] RBP: ffffffff9a803c88 R08: ffff9a55b961f3e0 R09: ffff9a55b9007c00
[    0.120000] R10: 0000000000000000 R11: 00000000000200c8 R12: 0000000000000003
[    0.120000] R13: 00000000014080c0 R14: 0000000000000008 R15: ffff9a55b9007c00
[    0.120000] FS:  0000000000000000(0000) GS:ffff9a55b9600000(0000) knlGS:0000000000000000
[    0.120000] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.120000] CR2: 0000000000000003 CR3: 00000000ba809000 CR4: 00000000000406f0
[    0.120000] Call Trace:
[    0.120000]  ? security_prepare_creds+0x73/0x90
[    0.120000]  security_prepare_creds+0x73/0x90
[    0.120000]  prepare_creds+0xbd/0xf0
[    0.120000]  copy_creds+0x2f/0x120
[    0.120000]  copy_process.part.31+0x2e5/0x1ae0
[    0.120000]  ? enqueue_task_fair+0xaf/0x6b0
[    0.120000]  ? kthread_create_on_cpu+0xa0/0xa0
[    0.120000]  ? sched_clock+0x9/0x10
[    0.120000]  _do_fork+0xdf/0x3f0
[    0.120000]  ? update_rq_clock+0x30/0x80
[    0.120000]  ? do_set_mempolicy+0x30/0x130
[    0.120000]  kernel_thread+0x29/0x30
[    0.120000]  rest_init+0x74/0xc0
[    0.120000]  start_kernel+0x4c0/0x4e1
[    0.120000]  ? early_idt_handler_array+0x120/0x120
[    0.120000]  x86_64_start_reservations+0x24/0x26
[    0.120000]  x86_64_start_kernel+0x13e/0x161
[    0.120000]  secondary_startup_64+0x9f/0x9f
[    0.120000] Code: 08 65 4c 03 05 f7 07 3e 66 49 83 78 10 00 4d 8b 20 0f 84 f7 00 00 00 4d 85 e4 0f 84 ee 00 00 00 49 63 41 20 49 8b 39 48 8d 4a 01 <49> 8b 1c 04 4c 89 e0 65 48 0f c7 0f 0f 94 c0 84 c0 74 bb 49 63 
[    0.120000] RIP: __kmalloc+0x9b/0x200 RSP: ffffffff9a803c58
[    0.120000] CR2: 0000000000000003
[    0.120000] ---[ end trace bee324c32248c3f4 ]---
[    0.120000] Kernel panic - not syncing: Attempted to kill the idle task!
[    0.120000] ---[ end Kernel panic - not syncing: Attempted to kill the idle task!

----------

cred->security for AppArmor will not be allocated (and therefore will trigger NULL pointer dereference) because security_add_blobs(&apparmor_blob_sizes) is not called when the administrator asked not to enable AppArmor. We need to reset apparmor_enabled to 0 in order to prevent apparmor_init() from calling set_init_ctx().

----------
static inline struct aa_task_ctx *apparmor_cred(const struct cred *cred) {

#ifdef CONFIG_SECURITY_STACKING
        return cred->security + apparmor_blob_sizes.lbs_cred;
#else
        return cred->security;

#endif
}

static int __init set_init_ctx(void)

{
        struct cred *cred = (struct cred *)current->real_cred;
        struct aa_task_ctx *ctx;

        lsm_early_cred(cred);
        ctx = apparmor_cred(cred);

        ctx->label = aa_get_label(ns_unconfined(root_ns));

        return 0;
}
Quoted 3 lines

----------

Thus, please also apply below patch.

Thank you. I will incorporate this, too.

Quoted 7 lines

----------
diff -ur linux-4.13.0-17.20.orig/security/apparmor/lsm.c linux-4.13.0-17.20/security/apparmor/lsm.c

security/apparmor/lsm.c

Quoted 9 lines
security/apparmor/lsm.c +2 -1
@@ -1562,6 +1562,8 @@
 		    security_module_enable("apparmor",
 				IS_ENABLED(CONFIG_SECURITY_APPARMOR_STACKED)))
 			security_add_blobs(&apparmor_blob_sizes);
+		else
+			apparmor_enabled = 0;
 		finish = 1;
 		return 0;
 	}
----------

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#16 lore raw

PATCH 6/9 LSM: General stacking

In reply to Casey Schaufler

Subject: [PATCH 6/9] LSM: General stacking

Leverage the infrastructure management of the security blobs to allow stacking of security modules in all but the most extreme case. Security modules are informed of the location of their data within the blobs at module initialization.

Stacking is optional. If stacking is not configured the old limit of one "major" security module applies. If stacking is configured TOMOYO can be configured with an of the other modules. SELinux, Smack and AppArmor use (or in the AppArmor case, threaten to use) secids, which are not (yet) shareable.

A subdirectory has been added to /proc/.../attr for each of SELinux and AppArmor (Smack introduced such a subdirectory earlier) to disambiguate what data is provided in the proc/.../attr interfaces.

Unlike earlier versions of this patch, there is no "context" entry introduced. No mechanism is provided to get all of the process security data at the same time.

---
 Documentation/admin-guide/LSM/index.rst | 14 ++++--
 fs/proc/base.c                          | 29 +++++++++++
 include/linux/lsm_hooks.h               |  2 +-
 security/Kconfig                        | 86 +++++++++++++++++++++++++++++++++
 security/apparmor/include/context.h     | 10 ++++
 security/apparmor/lsm.c                 |  8 ++-
 security/security.c                     | 30 +++++++++++-
 security/selinux/hooks.c                |  3 +-
 security/selinux/include/objsec.h       |  8 +++
 security/smack/smack.h                  |  9 ++++
 security/smack/smack_lsm.c              | 17 +++----
 security/tomoyo/common.h                | 12 ++++-
 security/tomoyo/tomoyo.c                |  3 +-
 13 files changed, 210 insertions(+), 21 deletions(-)
Documentation/admin-guide/LSM/index.rst +10 -4
index 9842e21afd4a..d3d8af174042 100644
@@ -17,10 +17,16 @@ MAC extensions, other extensions can be built using the LSM to provide
 specific changes to system operation when these tweaks are not available
 in the core functionality of Linux itself.
 
-The Linux capabilities modules will always be included. This may be
-followed by any number of "minor" modules and at most one "major" module.
-For more details on capabilities, see ``capabilities(7)`` in the Linux
-man-pages project.
+The Linux capabilities modules will always be included. For more details
+on capabilities, see ``capabilities(7)`` in the Linux man-pages project.
+
+Security modules that do not use the security data blobs maintained
+by the LSM infrastructure are considered "minor" modules. These may be
+included at compile time and stacked explicitly. Security modules that
+use the LSM maintained security blobs are considered "major" modules.
+These may only be stacked if the CONFIG_LSM_STACKED configuration
+option is used. If this is chosen all of the security modules selected
+will be used.
 
 A list of the active security modules can be found by reading
 ``/sys/kernel/security/lsm``. This is a comma separated list, and
fs/proc/base.c +29 -0
index a096e90fc12e..e6ee90483916 100644
@@ -2593,6 +2593,18 @@ static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \
 	.setattr	= proc_setattr, \
 }
 
+#ifdef CONFIG_SECURITY_SELINUX
+static const struct pid_entry selinux_attr_dir_stuff[] = {
+	ATTR("selinux", "current",	0666),
+	ATTR("selinux", "prev",		0444),
+	ATTR("selinux", "exec",		0666),
+	ATTR("selinux", "fscreate",	0666),
+	ATTR("selinux", "keycreate",	0666),
+	ATTR("selinux", "sockcreate",	0666),
+};
+LSM_DIR_OPS(selinux);
+#endif
+
 #ifdef CONFIG_SECURITY_SMACK
 static const struct pid_entry smack_attr_dir_stuff[] = {
 	ATTR("smack", "current",	0666),
@@ -2600,6 +2612,15 @@ static const struct pid_entry smack_attr_dir_stuff[] = {
 LSM_DIR_OPS(smack);
 #endif
 
+#ifdef CONFIG_SECURITY_APPARMOR
+static const struct pid_entry apparmor_attr_dir_stuff[] = {
+	ATTR("apparmor", "current",	0666),
+	ATTR("apparmor", "prev",	0444),
+	ATTR("apparmor", "exec",	0666),
+};
+LSM_DIR_OPS(apparmor);
+#endif
+
 static const struct pid_entry attr_dir_stuff[] = {
 	ATTR(NULL, "current",		0666),
 	ATTR(NULL, "prev",		0444),
@@ -2607,10 +2628,18 @@ static const struct pid_entry attr_dir_stuff[] = {
 	ATTR(NULL, "fscreate",		0666),
 	ATTR(NULL, "keycreate",		0666),
 	ATTR(NULL, "sockcreate",	0666),
+#ifdef CONFIG_SECURITY_SELINUX
+	DIR("selinux",			0555,
+	    proc_selinux_attr_dir_inode_ops, proc_selinux_attr_dir_ops),
+#endif
 #ifdef CONFIG_SECURITY_SMACK
 	DIR("smack",			0555,
 	    proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops),
 #endif
+#ifdef CONFIG_SECURITY_APPARMOR
+	DIR("apparmor",			0555,
+	    proc_apparmor_attr_dir_inode_ops, proc_apparmor_attr_dir_ops),
+#endif
 };
 
 static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx)
include/linux/lsm_hooks.h +1 -1
index cae3f6591044..84643a3ae378 100644
@@ -1975,7 +1975,7 @@ static inline void security_delete_hooks(struct security_hook_list *hooks,
 #define __lsm_ro_after_init	__ro_after_init
 #endif /* CONFIG_SECURITY_WRITABLE_HOOKS */
 
-extern int __init security_module_enable(const char *module);
+extern bool __init security_module_enable(const char *lsm, const bool stacked);
 extern void __init capability_add_hooks(void);
 #ifdef CONFIG_SECURITY_YAMA
 extern void __init yama_add_hooks(void);
security/Kconfig +86 -0

101 lines not on this page · raw message

security/apparmor/include/context.h +10 -0
index c6e106a533e8..c6d5dbbd18b0 100644
@@ -55,9 +55,15 @@ int aa_set_current_hat(struct aa_label *label, u64 token);
 int aa_restore_previous_label(u64 cookie);
 struct aa_label *aa_get_task_label(struct task_struct *task);
 
+extern struct lsm_blob_sizes apparmor_blob_sizes;
+
 static inline struct aa_task_ctx *apparmor_cred(const struct cred *cred)
 {
+#ifdef CONFIG_SECURITY_STACKING
+	return cred->security + apparmor_blob_sizes.lbs_cred;
+#else
 	return cred->security;
+#endif
 }
 
 /**
@@ -89,7 +95,11 @@ static inline struct aa_label *aa_get_newest_cred_label(const struct cred *cred)
 
 static inline struct aa_file_ctx *apparmor_file(const struct file *file)
 {
+#ifdef CONFIG_SECURITY_STACKING
+	return file->f_security + apparmor_blob_sizes.lbs_file;
+#else
 	return file->f_security;
+#endif
 }
 
 /**
security/apparmor/lsm.c +6 -2
index 8edbf79062cd..b36d08f5ce1d 100644
@@ -1467,7 +1467,9 @@ static int __init apparmor_init(void)
 	int error;
 
 	if (!finish) {
-		if (apparmor_enabled && security_module_enable("apparmor"))
+		if (apparmor_enabled &&
+		    security_module_enable("apparmor",
+				IS_ENABLED(CONFIG_SECURITY_APPARMOR_STACKED)))
 			security_add_blobs(&apparmor_blob_sizes);
 		else
 			apparmor_enabled = 0;
@@ -1475,7 +1477,9 @@ static int __init apparmor_init(void)
 		return 0;
 	}
 
-	if (!apparmor_enabled || !security_module_enable("apparmor")) {
+	if (!apparmor_enabled ||
+	    !security_module_enable("apparmor",
+				IS_ENABLED(CONFIG_SECURITY_APPARMOR_STACKED))) {
 		aa_info_message("AppArmor disabled by boot time parameter");
 		apparmor_enabled = 0;
 		return 0;
security/security.c +28 -2
index 8439acd36160..a306a5447d43 100644
@@ -35,6 +35,7 @@
 
 /* Maximum number of letters for an LSM name string */
 #define SECURITY_NAME_MAX	10
+#define MODULE_STACK		"(stacking)"
 
 struct security_hook_heads security_hook_heads __lsm_ro_after_init;
 static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);
@@ -47,7 +48,11 @@ static struct lsm_blob_sizes blob_sizes;
 
 /* Boot-time LSM user choice */
 static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
+#ifdef CONFIG_SECURITY_STACKING
+	MODULE_STACK;
+#else
 	CONFIG_DEFAULT_SECURITY;
+#endif
 
 static void __init do_security_initcalls(void)
 {
@@ -167,6 +172,7 @@ static int lsm_append(char *new, char **result)
 /**
  * security_module_enable - Load given security module on boot ?
  * @module: the name of the module
+ * @stacked: indicates that the module wants to be stacked
  *
  * Each LSM must pass this method before registering its own operations
  * to avoid security registration races. This method may also be used
@@ -182,9 +188,29 @@ static int lsm_append(char *new, char **result)
  *
  * Otherwise, return false.
  */
-int __init security_module_enable(const char *module)
+bool __init security_module_enable(const char *lsm, const bool stacked)
 {
-	return !strcmp(module, chosen_lsm);
+#ifdef CONFIG_SECURITY_STACKING
+	/*
+	 * Module defined on the command line security=XXXX
+	 */
+	if (strcmp(chosen_lsm, MODULE_STACK)) {
+		if (!strcmp(lsm, chosen_lsm)) {
+			pr_info("Command line sets the %s security module.\n",
+				lsm);
+			return true;
+		}
+		return false;
+	}
+	/*
+	 * Module configured as stacked.
+	 */
+	return stacked;
+#else
+	if (strcmp(lsm, chosen_lsm) == 0)
+		return true;
+	return false;
+#endif
 }
 
 /**
security/selinux/hooks.c +2 -1
index cfee70096f97..a3466517c55c 100644
@@ -6300,7 +6300,8 @@ static __init int selinux_init(void)
 {
 	static int finish;
 
-	if (!security_module_enable("selinux")) {
+	if (!security_module_enable("selinux",
+				IS_ENABLED(CONFIG_SECURITY_SELINUX_STACKED))) {
 		selinux_enabled = 0;
 		return 0;
 	}
security/selinux/include/objsec.h +8 -0
index f2f1e2d15eb8..7abb443c2ed2 100644
@@ -155,12 +155,20 @@ extern struct lsm_blob_sizes selinux_blob_sizes;
 
 static inline struct task_security_struct *selinux_cred(const struct cred *cred)
 {
+#ifdef CONFIG_SECURITY_STACKING
+	return cred->security + selinux_blob_sizes.lbs_cred;
+#else
 	return cred->security;
+#endif
 }
 
 static inline struct file_security_struct *selinux_file(const struct file *file)
 {
+#ifdef CONFIG_SECURITY_STACKING
+	return file->f_security + selinux_blob_sizes.lbs_file;
+#else
 	return file->f_security;
+#endif
 }
 
 static inline struct inode_security_struct *selinux_inode(
security/smack/smack.h +9 -0
index 1b875c2f3d9d..e7611de071f1 100644
@@ -336,6 +336,7 @@ extern struct smack_known *smack_syslog_label;
 extern struct smack_known *smack_unconfined;
 #endif
 extern int smack_ptrace_rule;
+extern struct lsm_blob_sizes smack_blob_sizes;
 
 extern struct smack_known smack_known_floor;
 extern struct smack_known smack_known_hat;
@@ -358,12 +359,20 @@ extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
 
 static inline struct task_smack *smack_cred(const struct cred *cred)
 {
+#ifdef CONFIG_SECURITY_STACKING
+	return cred->security + smack_blob_sizes.lbs_cred;
+#else
 	return cred->security;
+#endif
 }
 
 static inline struct smack_known **smack_file(const struct file *file)
 {
+#ifdef CONFIG_SECURITY_STACKING
+	return file->f_security + smack_blob_sizes.lbs_file;
+#else
 	return file->f_security;
+#endif
 }
 
 static inline struct inode_smack *smack_inode(const struct inode *inode)
security/smack/smack_lsm.c +8 -9
index 4588c48aab86..e3f32f4d322a 100644
@@ -3427,18 +3427,16 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
 {
 	struct smack_known *skp = smk_of_task_struct(p);
 	char *cp;
-	int slen;
 
-	if (strcmp(name, "current") != 0)
+	if (strcmp(name, "current") == 0) {
+		cp = kstrdup(skp->smk_known, GFP_KERNEL);
+		if (cp == NULL)
+			return -ENOMEM;
+	} else
 		return -EINVAL;
 
-	cp = kstrdup(skp->smk_known, GFP_KERNEL);
-	if (cp == NULL)
-		return -ENOMEM;
-
-	slen = strlen(cp);
 	*value = cp;
-	return slen;
+	return strlen(cp);
 }
 
 /**
@@ -4594,7 +4592,8 @@ static __init int smack_init(void)
 	struct cred *cred = (struct cred *) current->cred;
 	struct task_smack *tsp;
 
-	if (!security_module_enable("smack"))
+	if (!security_module_enable("smack",
+				IS_ENABLED(CONFIG_SECURITY_SMACK_STACKED)))
 		return 0;
 
 	if (!finish) {
security/tomoyo/common.h +11 -1
index cbcfccc84784..2eed9d44eec1 100644
@@ -1085,6 +1085,7 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain;
 extern struct tomoyo_policy_namespace tomoyo_kernel_namespace;
 extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
 extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
+extern struct lsm_blob_sizes tomoyo_blob_sizes;
 
 /********** Inlined functions. **********/
 
@@ -1204,7 +1205,11 @@ static inline void tomoyo_put_group(struct tomoyo_group *group)
  */
 static inline struct tomoyo_domain_info **tomoyo_cred(const struct cred *cred)
 {
+#ifdef CONFIG_SECURITY_STACKING
+	return cred->security + tomoyo_blob_sizes.lbs_cred;
+#else
 	return cred->security;
+#endif
 }
 
 /**
@@ -1214,8 +1219,13 @@ static inline struct tomoyo_domain_info **tomoyo_cred(const struct cred *cred)
  */
 static inline struct tomoyo_domain_info *tomoyo_domain(void)
 {
-	struct tomoyo_domain_info **blob = tomoyo_cred(current_cred());
+	const struct cred *cred = current_cred();
+	struct tomoyo_domain_info **blob;
+
+	if (cred->security == NULL)
+		return NULL;
 
+	blob = tomoyo_cred(cred);
 	return *blob;
 }
 
security/tomoyo/tomoyo.c +2 -1
index 1224a59291fb..32173de284f8 100644
@@ -561,7 +561,8 @@ static int __init tomoyo_init(void)
 	struct cred *cred = (struct cred *) current_cred();
 	struct tomoyo_domain_info **blob;
 
-	if (!security_module_enable("tomoyo"))
+	if (!security_module_enable("tomoyo",
+				IS_ENABLED(CONFIG_SECURITY_TOMOYO_STACKED)))
 		return 0;
 
 	if (!finish) {
Signature · 7 lines
2.13.0


--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
author maintainer
#17 lore raw

PATCH 7/9 LSM: Shared secids

In reply to Casey Schaufler

Subject: [PATCH 7/9] LSM: Shared secids

Introduces a mechanism for mapping a set of security module secids to and from a "token". The module interfaces are changed to generally hide the mechanism from both the security modules and the callers of the security hooks.

The implementation of the lsm_token functions is functional but not production ready. At the least, it needs locking and lifetime management which it lacks. The versions here do work with Ubuntu 17.04 and Fedora 27 in workstation configurations.

---
 include/linux/lsm_hooks.h        |  43 +++++-
 include/net/request_sock.h       |   2 +
 security/Makefile                |   1 +
 security/security.c              | 292 ++++++++++++++++++++++++++++++++++++++-
 security/selinux/hooks.c         |  31 ++++-
 security/selinux/include/xfrm.h  |   2 +-
 security/selinux/xfrm.c          |   6 +-
 security/smack/smack.h           |  11 ++
 security/smack/smack_lsm.c       |  14 +-
 security/smack/smack_netfilter.c |   6 +-
 security/stacking.c              | 188 +++++++++++++++++++++++++
 11 files changed, 570 insertions(+), 26 deletions(-)
 create mode 100644 security/stacking.c
include/linux/lsm_hooks.h +41 -2
index 84643a3ae378..d49d4f3544cf 100644
@@ -1624,7 +1624,7 @@ union security_list_options {
 	void (*secmark_refcount_inc)(void);
 	void (*secmark_refcount_dec)(void);
 	void (*req_classify_flow)(const struct request_sock *req,
-					struct flowi *fl);
+					u32 *fl_secid);
 	int (*tun_dev_alloc_security)(void **security);
 	void (*tun_dev_free_security)(void *security);
 	int (*tun_dev_create)(void);
@@ -1660,7 +1660,7 @@ union security_list_options {
 					u8 dir);
 	int (*xfrm_state_pol_flow_match)(struct xfrm_state *x,
 						struct xfrm_policy *xp,
-						const struct flowi *fl);
+						u32 fl_secid);
 	int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall);
 #endif	/* CONFIG_SECURITY_NETWORK_XFRM */
 
@@ -1912,9 +1912,48 @@ struct security_hook_list {
 	struct list_head		*head;
 	union security_list_options	hook;
 	char				*lsm;
+	int				lsm_index;
 } __randomize_layout;
 
 /*
+ * The maximum number of major security modules.
+ * Used to avoid excessive memory management while
+ * mapping global and module specific secids.
+ *
+ * Currently SELinux, Smack, AppArmor, TOMOYO
+ * Oh, but Casey needs to come up with the right way
+ * to identify a "major" module, so use the total number
+ * of modules (including minor) for now.
+ * Minor: Capability, Yama, LoadPin
+ */
+#define	LSM_MAX_MAJOR	8
+
+#ifdef CONFIG_SECURITY_STACKING
+struct lsm_secids {
+	u32	secid[LSM_MAX_MAJOR];
+};
+
+extern u32 lsm_secids_to_token(const struct lsm_secids *secids);
+extern void lsm_token_to_secids(const u32 token, struct lsm_secids *secids);
+extern u32 lsm_token_get_secid(const u32 token, int lsm);
+extern u32 lsm_token_set_secid(const u32 token, u32 lsecid, int lsm);
+extern u32 lsm_token_to_module_secid(const u32 token, int lsm);
+extern void lsm_secids_init(struct lsm_secids *secids);
+#else /* CONFIG_SECURITY_STACKING */
+
+static inline u32 lsm_token_get_secid(const u32 token, int lsm)
+{
+	return token;
+}
+
+static inline u32 lsm_token_set_secid(const u32 token, u32 lsecid, int lsm)
+{
+	return lsecid;
+}
+
+#endif /* CONFIG_SECURITY_STACKING */
+
+/*
  * Security blob size or offset data.
  */
 struct lsm_blob_sizes {
include/net/request_sock.h +2 -0
index 23e22054aa60..07c0e919c4e7 100644
@@ -102,6 +102,8 @@ reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk_listener,
 	sk_tx_queue_clear(req_to_sk(req));
 	req->saved_syn = NULL;
 	refcount_set(&req->rsk_refcnt, 0);
+	req->secid = 0;
+	req->peer_secid = 0;
 
 	return req;
 }
security/Makefile +1 -0
index f2d71cdb8e19..05e6d525b5a1 100644
@@ -25,6 +25,7 @@ obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/
 obj-$(CONFIG_SECURITY_YAMA)		+= yama/
 obj-$(CONFIG_SECURITY_LOADPIN)		+= loadpin/
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
+obj-$(CONFIG_SECURITY_STACKING)		+= stacking.o
 
 # Object integrity file lists
 subdir-$(CONFIG_INTEGRITY)		+= integrity
security/security.c +286 -6

434 lines not on this page · raw message

security/selinux/hooks.c +24 -7
index a3466517c55c..e6d6ab671493 100644
@@ -100,6 +100,9 @@
 /* SECMARK reference count */
 static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
 
+/* Index into lsm_secids */
+static int selinux_secids_index;
+
 #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
 int selinux_enforcing;
 
@@ -4617,6 +4620,11 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
 			    SECCLASS_NODE, NODE__RECVFROM, ad);
 }
 
+static u32 selinux_token_to_secid(u32 token)
+{
+	return lsm_token_get_secid(token, selinux_secids_index);
+}
+
 static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
 				       u16 family)
 {
@@ -4636,7 +4644,9 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
 		return err;
 
 	if (selinux_secmark_enabled()) {
-		err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
+		err = avc_has_perm(sk_sid,
+				   selinux_token_to_secid(skb->secmark),
+				   SECCLASS_PACKET,
 				   PACKET__RECV, &ad);
 		if (err)
 			return err;
@@ -4710,7 +4720,9 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 	}
 
 	if (secmark_active) {
-		err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
+		err = avc_has_perm(sk_sid,
+				   selinux_token_to_secid(skb->secmark),
+				   SECCLASS_PACKET,
 				   PACKET__RECV, &ad);
 		if (err)
 			return err;
@@ -4909,9 +4921,9 @@ static void selinux_secmark_refcount_dec(void)
 }
 
 static void selinux_req_classify_flow(const struct request_sock *req,
-				      struct flowi *fl)
+				      u32 *fl_secid)
 {
-	fl->flowi_secid = req->secid;
+	*fl_secid = req->secid;
 }
 
 static int selinux_tun_dev_alloc_security(void **security)
@@ -5073,7 +5085,8 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb,
 	}
 
 	if (secmark_active)
-		if (avc_has_perm(peer_sid, skb->secmark,
+		if (avc_has_perm(peer_sid,
+				 selinux_token_to_secid(skb->secmark),
 				 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
 			return NF_DROP;
 
@@ -5185,7 +5198,8 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
 		return NF_DROP;
 
 	if (selinux_secmark_enabled())
-		if (avc_has_perm(sksec->sid, skb->secmark,
+		if (avc_has_perm(sksec->sid,
+				 selinux_token_to_secid(skb->secmark),
 				 SECCLASS_PACKET, PACKET__SEND, &ad))
 			return NF_DROP_ERR(-ECONNREFUSED);
 
@@ -5308,7 +5322,8 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
 		return NF_DROP;
 
 	if (secmark_active)
-		if (avc_has_perm(peer_sid, skb->secmark,
+		if (avc_has_perm(peer_sid,
+				 selinux_token_to_secid(skb->secmark),
 				 SECCLASS_PACKET, secmark_perm, &ad))
 			return NF_DROP_ERR(-ECONNREFUSED);
 
@@ -6328,6 +6343,8 @@ static __init int selinux_init(void)
 
 	security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
 
+	selinux_secids_index = selinux_hooks[0].lsm_index;
+
 	if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
 		panic("SELinux: Unable to register AVC netcache callback\n");
 
security/selinux/include/xfrm.h +1 -1
index 36a7ce9e11ff..0235b0cfd0ce 100644
@@ -25,7 +25,7 @@ int selinux_xfrm_state_delete(struct xfrm_state *x);
 int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir);
 int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
 				      struct xfrm_policy *xp,
-				      const struct flowi *fl);
+				      u32 fl_secid);
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 extern atomic_t selinux_xfrm_refcount;
security/selinux/xfrm.c +3 -3
index 789d07bd900f..d71e2c32b5da 100644
@@ -174,7 +174,7 @@ int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir)
  */
 int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
 				      struct xfrm_policy *xp,
-				      const struct flowi *fl)
+				      u32 fl_secid)
 {
 	u32 state_sid;
 
@@ -196,13 +196,13 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
 
 	state_sid = x->security->ctx_sid;
 
-	if (fl->flowi_secid != state_sid)
+	if (fl_secid != state_sid)
 		return 0;
 
 	/* We don't need a separate SA Vs. policy polmatch check since the SA
 	 * is now of the same label as the flow and a flow Vs. policy polmatch
 	 * check had already happened in selinux_xfrm_policy_lookup() above. */
-	return (avc_has_perm(fl->flowi_secid, state_sid,
+	return (avc_has_perm(fl_secid, state_sid,
 			    SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO,
 			    NULL) ? 0 : 1);
 }
security/smack/smack.h +11 -0
index e7611de071f1..b16846e3d1f1 100644
@@ -328,6 +328,7 @@ void smk_destroy_label_list(struct list_head *list);
  * Shared data.
  */
 extern int smack_enabled;
+extern int smack_secids_index;
 extern int smack_cipso_direct;
 extern int smack_cipso_mapped;
 extern struct smack_known *smack_net_ambient;
@@ -432,6 +433,16 @@ static inline struct smack_known **smack_key(const struct key *key)
 }
 #endif /* CONFIG_KEYS */
 
+static inline u32 smack_token_to_secid(u32 token)
+{
+	return lsm_token_get_secid(token, smack_secids_index);
+}
+
+static inline u32 smack_to_token(u32 token, u32 secid)
+{
+	return lsm_token_set_secid(token, secid, smack_secids_index);
+}
+
 /*
  * Is the directory transmuting?
  */
security/smack/smack_lsm.c +9 -5
index e3f32f4d322a..9031f2dc8bfb 100644
@@ -57,6 +57,7 @@ static LIST_HEAD(smk_ipv6_port_list);
 #endif
 static struct kmem_cache *smack_inode_cache;
 int smack_enabled;
+int smack_secids_index;
 
 static const match_table_t smk_mount_tokens = {
 	{Opt_fsdefault, SMK_FSDEFAULT "%s"},
@@ -3789,7 +3790,8 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 		 * The secmark is assumed to reflect policy better.
 		 */
 		if (skb && skb->secmark != 0) {
-			skp = smack_from_secid(skb->secmark);
+			skp = smack_from_secid(smack_token_to_secid(
+							skb->secmark));
 			goto access_check;
 		}
 #endif /* CONFIG_SECURITY_SMACK_NETFILTER */
@@ -3834,7 +3836,8 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 			break;
 #ifdef SMACK_IPV6_SECMARK_LABELING
 		if (skb && skb->secmark != 0)
-			skp = smack_from_secid(skb->secmark);
+			skp = smack_from_secid(smack_token_to_secid(
+							skb->secmark));
 		else
 			skp = smack_ipv6host_label(&sadd);
 		if (skp == NULL)
@@ -3932,7 +3935,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
 		break;
 	case PF_INET:
 #ifdef CONFIG_SECURITY_SMACK_NETFILTER
-		s = skb->secmark;
+		s = smack_token_to_secid(skb->secmark);
 		if (s != 0)
 			break;
 #endif
@@ -3951,7 +3954,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
 		break;
 	case PF_INET6:
 #ifdef SMACK_IPV6_SECMARK_LABELING
-		s = skb->secmark;
+		s = smack_token_to_secid(skb->secmark);
 #endif
 		break;
 	}
@@ -4030,7 +4033,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
 	 * The secmark is assumed to reflect policy better.
 	 */
 	if (skb && skb->secmark != 0) {
-		skp = smack_from_secid(skb->secmark);
+		skp = smack_from_secid(smack_token_to_secid(skb->secmark));
 		goto access_check;
 	}
 #endif /* CONFIG_SECURITY_SMACK_NETFILTER */
@@ -4618,6 +4621,7 @@ static __init int smack_init(void)
 	 * Register with LSM
 	 */
 	security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack");
+	smack_secids_index = smack_hooks[0].lsm_index;
 	smack_enabled = 1;
 
 	pr_info("Smack:  Initializing.\n");
security/smack/smack_netfilter.c +4 -2
index 701a1cc1bdcc..ee2e16d0b1a3 100644
@@ -34,7 +34,8 @@ static unsigned int smack_ipv6_output(void *priv,
 	if (sk && smack_sock(sk)) {
 		ssp = smack_sock(sk);
 		skp = ssp->smk_out;
-		skb->secmark = skp->smk_secid;
+		skb->secmark = lsm_token_set_secid(skb->secmark,
+					skp->smk_secid, smack_secids_index);
 	}
 
 	return NF_ACCEPT;
@@ -52,7 +53,8 @@ static unsigned int smack_ipv4_output(void *priv,
 	if (sk && smack_sock(sk)) {
 		ssp = smack_sock(sk);
 		skp = ssp->smk_out;
-		skb->secmark = skp->smk_secid;
+		skb->secmark = lsm_token_set_secid(skb->secmark,
+					skp->smk_secid, smack_secids_index);
 	}
 
 	return NF_ACCEPT;
security/stacking.c new file +188 -0

188 lines not on this page · raw message

Signature · 7 lines
2.13.0


--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info@ http://vger.kernel.org/majordomo-info.html
author maintainer
#18 lore raw

PATCH 8/9 LSM: Multiple security mount options

In reply to Casey Schaufler

Subject: [PATCH 8/9] LSM: Multiple security mount options

There needs to be separate data for each of the
security modules that support mount options.
Expand the security_mnt_opts structure to include
an entry for each security module that uses them.

It would be better to have a variable size blob,
but there isn't a convenient place to hang such.

---
 fs/btrfs/super.c           | 10 +++---
 include/linux/security.h   | 53 ++++++++++++++++++++-------
 security/security.c        | 15 ++++++--
 security/selinux/hooks.c   | 90 +++++++++++++++++++++++-----------------------
 security/smack/smack_lsm.c | 54 ++++++++++++++--------------
 5 files changed, 131 insertions(+), 91 deletions(-)
fs/btrfs/super.c +5 -5
index 35a128acfbd1..f8f828267d45 100644
@@ -1512,15 +1512,15 @@ static int setup_security_options(struct btrfs_fs_info *fs_info,
 		return ret;
 
 #ifdef CONFIG_SECURITY
-	if (!fs_info->security_opts.num_mnt_opts) {
+	if (fs_info->security_opts.selinux.num_mnt_opts != 0 ||
+	    fs_info->security_opts.smack.num_mnt_opts != 0) {
 		/* first time security setup, copy sec_opts to fs_info */
 		memcpy(&fs_info->security_opts, sec_opts, sizeof(*sec_opts));
 	} else {
 		/*
-		 * Since SELinux (the only one supporting security_mnt_opts)
-		 * does NOT support changing context during remount/mount of
-		 * the same sb, this must be the same or part of the same
-		 * security options, just free it.
+		 * Since no modules support changing context during
+		 * remount/mount of the same sb, this must be the same
+		 * or part of the same security options, just free it.
 		 */
 		security_free_mnt_opts(sec_opts);
 	}
include/linux/security.h +41 -12

75 lines not on this page · raw message

security/security.c +12 -3
index 0269971b3b05..7a004006e761 100644
@@ -771,9 +771,18 @@ int security_sb_set_mnt_opts(struct super_block *sb,
 				unsigned long kern_flags,
 				unsigned long *set_kern_flags)
 {
-	return call_int_hook(sb_set_mnt_opts,
-				opts->num_mnt_opts ? -EOPNOTSUPP : 0, sb,
-				opts, kern_flags, set_kern_flags);
+	int nobody = 0;
+
+#ifdef SECURITY_EXTREME_STACKING
+	if (opts->selinux.num_mnt_opts != 0 || opts->smack.num_mnt_opts != 0)
+		nobody = -EOPNOTSUPP;
+#else
+	if (opts->selinux.num_mnt_opts != 0)
+		nobody = -EOPNOTSUPP;
+#endif
+
+	return call_int_hook(sb_set_mnt_opts, nobody, sb, opts, kern_flags,
+				set_kern_flags);
 }
 EXPORT_SYMBOL(security_sb_set_mnt_opts);
 
security/selinux/hooks.c +45 -45

192 lines not on this page · raw message

security/smack/smack_lsm.c +28 -26

118 lines not on this page · raw message

Signature · 7 lines
2.13.0


--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#19 lore raw

PATCH 8/9 LSM: Multiple security mount options

Quoted 293 lines · Casey Schaufler

Subject: [PATCH 8/9] LSM: Multiple security mount options

There needs to be separate data for each of the security modules that support mount options. Expand the security_mnt_opts structure to include an entry for each security module that uses them.

It would be better to have a variable size blob, but there isn't a convenient place to hang such.

---

?fs/btrfs/super.c???????????| 10 +++---
?include/linux/security.h???| 53 ++++++++++++++++++++-------
?security/security.c????????| 15 ++++++--
?security/selinux/hooks.c???| 90 +++++++++++++++++++++++-------------

----------
?security/smack/smack_lsm.c | 54 ++++++++++++++-------------- ?5 files changed, 131 insertions(+), 91 deletions(-)

fs/btrfs/super.c +0 -0
index 35a128acfbd1..f8f828267d45 100644
@@ -1512,15 +1512,15 @@ static int setup_security_options(struct
 btrfs_fs_info *fs_info,
 ?		return ret;

?
?#ifdef CONFIG_SECURITY

fs/btrfs/super.c +2 -1
-	if (!fs_info->security_opts.num_mnt_opts) {
+	if (fs_info->security_opts.selinux.num_mnt_opts != 0 ||
+	????fs_info->security_opts.smack.num_mnt_opts != 0) {

? /* first time security setup, copy sec_opts to
fs_info */
? memcpy(&fs_info->security_opts, sec_opts,
sizeof(*sec_opts));
? } else {
? /*

fs/btrfs/super.c +0 -1
-		?* Since SELinux (the only one supporting

security_mnt_opts)

fs/btrfs/super.c +0 -1
-		?* does NOT support changing context during

remount/mount of

fs/btrfs/super.c +0 -1
-		?* the same sb, this must be the same or part of the

same

fs/btrfs/super.c +2 -1
-		?* security options, just free it.
+		?* Since no modules support changing context during
+		?* remount/mount of the same sb, this must be the

same

fs/btrfs/super.c +1 -0
+		?* or part of the same security options, just free

it.
? ?*/
? security_free_mnt_opts(sec_opts);
? }

include/linux/security.h +0 -0
index 46ec92658ad3..3a70b23a7dcc 100644
@@ -163,34 +163,63 @@ typedef int (*initxattrs) (struct inode *inode,

?
?#ifdef CONFIG_SECURITY
?

include/linux/security.h +1 -1
-struct security_mnt_opts {
+struct lsm_mnt_opts {

? char **mnt_opts;
? int *mnt_opts_flags;
? int num_mnt_opts;
?};
?

include/linux/security.h +13 -0
+
+struct security_mnt_opts {
+#ifdef CONFIG_SECURITY_STACKING
+	struct lsm_mnt_opts?????selinux;
+	struct lsm_mnt_opts?????smack;
+#else
+	union {
+		struct lsm_mnt_opts?????selinux;
+		struct lsm_mnt_opts?????smack;
+	};
+#endif
+};
+

?int call_lsm_notifier(enum lsm_event event, void *data); ?int register_lsm_notifier(struct notifier_block *nb); ?int unregister_lsm_notifier(struct notifier_block *nb); ?
?static inline void security_init_mnt_opts(struct security_mnt_opts *opts)
?{

include/linux/security.h +8 -3
-	opts->mnt_opts = NULL;
-	opts->mnt_opts_flags = NULL;
-	opts->num_mnt_opts = 0;
+	opts->selinux.mnt_opts = NULL;
+	opts->selinux.mnt_opts_flags = NULL;
+	opts->selinux.num_mnt_opts = 0;
+#ifdef CONFIG_SECURITY_STACKING
+	opts->smack.mnt_opts = NULL;
+	opts->smack.mnt_opts_flags = NULL;
+	opts->smack.num_mnt_opts = 0;
+#endif

?}
?
?static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
?{
? int i;

include/linux/security.h +19 -8
-	if (opts->mnt_opts)
-		for (i = 0; i < opts->num_mnt_opts; i++)
-			kfree(opts->mnt_opts[i]);
-	kfree(opts->mnt_opts);
-	opts->mnt_opts = NULL;
-	kfree(opts->mnt_opts_flags);
-	opts->mnt_opts_flags = NULL;
-	opts->num_mnt_opts = 0;
+	if (opts->selinux.mnt_opts)
+		for (i = 0; i < opts->selinux.num_mnt_opts; i++)
+			kfree(opts->selinux.mnt_opts[i]);
+	kfree(opts->selinux.mnt_opts);
+	opts->selinux.mnt_opts = NULL;
+	kfree(opts->selinux.mnt_opts_flags);
+	opts->selinux.mnt_opts_flags = NULL;
+	opts->selinux.num_mnt_opts = 0;
+
+#ifdef CONFIG_SECURITY_STACKING
+	if (opts->smack.mnt_opts)
+		for (i = 0; i < opts->smack.num_mnt_opts; i++)
+			kfree(opts->smack.mnt_opts[i]);
+	kfree(opts->smack.mnt_opts);
+	opts->smack.mnt_opts = NULL;
+	kfree(opts->smack.mnt_opts_flags);
+	opts->smack.mnt_opts_flags = NULL;
+	opts->smack.num_mnt_opts = 0;
+#endif

?}
?
?/* prototypes */

security/security.c +11 -3
index 0269971b3b05..7a004006e761 100644
@@ -771,9 +771,18 @@ int security_sb_set_mnt_opts(struct super_block
 *sb,
 ?				unsigned long kern_flags,
 ?				unsigned long *set_kern_flags)
 ?{
-	return call_int_hook(sb_set_mnt_opts,
-				opts->num_mnt_opts ? -EOPNOTSUPP :
 0, sb,
-				opts, kern_flags, set_kern_flags);
+	int nobody = 0;
+
+#ifdef SECURITY_EXTREME_STACKING
+	if (opts->selinux.num_mnt_opts != 0 || opts-
 >smack.num_mnt_opts != 0)
+		nobody = -EOPNOTSUPP;
+#else
+	if (opts->selinux.num_mnt_opts != 0)
+		nobody = -EOPNOTSUPP;
+#endif
+
+	return call_int_hook(sb_set_mnt_opts, nobody, sb, opts,

kern_flags,

security/security.c +1 -0
+				set_kern_flags);

?} ?EXPORT_SYMBOL(security_sb_set_mnt_opts); ?

security/selinux/hooks.c +0 -0
index e6d6ab671493..395fbfa7bfac 100644
@@ -545,21 +545,23 @@ static int selinux_get_mnt_opts(const struct
 super_block *sb,

? /* count the number of mount options for this sb */
? for (i = 0; i < NUM_SEL_MNT_OPTS; i++) {
? if (tmp & 0x01)

security/selinux/hooks.c +1 -1
-			opts->num_mnt_opts++;
+			opts->selinux.num_mnt_opts++;

? tmp >>= 1;
? }
? /* Check if the Label support flag is set */
? if (sbsec->flags & SBLABEL_MNT)

security/selinux/hooks.c +1 -1
-		opts->num_mnt_opts++;
+		opts->selinux.num_mnt_opts++;

?

security/selinux/hooks.c +0 -1
-	opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *),

GFP_ATOMIC);

security/selinux/hooks.c +2 -1
-	if (!opts->mnt_opts) {
+	opts->selinux.mnt_opts = kcalloc(opts->selinux.num_mnt_opts,
+						sizeof(char *),

GFP_ATOMIC);

security/selinux/hooks.c +1 -0
+	if (!opts->selinux.mnt_opts) {

? rc = -ENOMEM;
? goto out_free;
? }
?

security/selinux/hooks.c +0 -1
-	opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts,

sizeof(int), GFP_ATOMIC);

security/selinux/hooks.c +1 -1
-	if (!opts->mnt_opts_flags) {
+	opts->selinux.mnt_opts_flags = kcalloc(opts-
Quoted 1 line

selinux.num_mnt_opts,

security/selinux/hooks.c +1 -0
+						sizeof(int),

GFP_ATOMIC);

security/selinux/hooks.c +1 -0
+	if (!opts->selinux.mnt_opts_flags) {

? rc = -ENOMEM;
? goto out_free;
? }

security/selinux/hooks.c +6 -6
@@ -569,22 +571,22 @@ static int selinux_get_mnt_opts(const struct
 super_block *sb,
 ?		rc = security_sid_to_context(sbsec->sid, &context,
 &len);
 ?		if (rc)
 ?			goto out_free;
-		opts->mnt_opts[i] = context;
-		opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
+		opts->selinux.mnt_opts[i] = context;
+		opts->selinux.mnt_opts_flags[i++] = FSCONTEXT_MNT;
 ?	}
 ?	if (sbsec->flags & CONTEXT_MNT) {
 ?		rc = security_sid_to_context(sbsec->mntpoint_sid,
 &context, &len);
 ?		if (rc)
 ?			goto out_free;
-		opts->mnt_opts[i] = context;
-		opts->mnt_opts_flags[i++] = CONTEXT_MNT;
+		opts->selinux.mnt_opts[i] = context;
+		opts->selinux.mnt_opts_flags[i++] = CONTEXT_MNT;
 ?	}
 ?	if (sbsec->flags & DEFCONTEXT_MNT) {
 ?		rc = security_sid_to_context(sbsec->def_sid,
 &context, &len);
 ?		if (rc)
 ?			goto out_free;
-		opts->mnt_opts[i] = context;
-		opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
+		opts->selinux.mnt_opts[i] = context;
+		opts->selinux.mnt_opts_flags[i++] = DEFCONTEXT_MNT;

? }
? if (sbsec->flags & ROOTCONTEXT_MNT) {
? struct dentry *root = sbsec->sb->s_root;

security/selinux/hooks.c +4 -4
@@ -594,15 +596,15 @@ static int selinux_get_mnt_opts(const struct
 super_block *sb,
 ?		rc = security_sid_to_context(isec->sid, &context,
 &len);
 ?		if (rc)
 ?			goto out_free;
-		opts->mnt_opts[i] = context;
-		opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
+		opts->selinux.mnt_opts[i] = context;
+		opts->selinux.mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
 ?	}
 ?	if (sbsec->flags & SBLABEL_MNT) {
-		opts->mnt_opts[i] = NULL;
-		opts->mnt_opts_flags[i++] = SBLABEL_MNT;
+		opts->selinux.mnt_opts[i] = NULL;
+		opts->selinux.mnt_opts_flags[i++] = SBLABEL_MNT;
 ?	}

?

security/selinux/hooks.c +1 -1
-	BUG_ON(i != opts->num_mnt_opts);
+	BUG_ON(i != opts->selinux.num_mnt_opts);

?
? return 0;
?

security/selinux/hooks.c +3 -3
@@ -648,9 +650,9 @@ static int selinux_set_mnt_opts(struct
 super_block *sb,
 ?	struct inode_security_struct *root_isec;
 ?	u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
 ?	u32 defcontext_sid = 0;
-	char **mount_options = opts->mnt_opts;
-	int *flags = opts->mnt_opts_flags;
-	int num_opts = opts->num_mnt_opts;
+	char **mount_options = opts->selinux.mnt_opts;
+	int *flags = opts->selinux.mnt_opts_flags;
+	int num_opts = opts->selinux.num_mnt_opts;

?
? mutex_lock(&sbsec->lock);
?

security/selinux/hooks.c +0 -0
@@ -1010,7 +1012,7 @@ static int selinux_parse_opts_str(char
 *options,
 ?	char *fscontext = NULL, *rootcontext = NULL;
 ?	int rc, num_mnt_opts = 0;

?

security/selinux/hooks.c +1 -1
-	opts->num_mnt_opts = 0;
+	opts->selinux.num_mnt_opts = 0;

?
? /* Standard string-based options. */
? while ((p = strsep(&options, "|")) != NULL) {

security/selinux/hooks.c +0 -0
@@ -1077,41 +1079,39 @@ static int selinux_parse_opts_str(char
 *options,

? case Opt_labelsupport:
? break;
? default:

security/selinux/hooks.c +0 -1
-			rc = -EINVAL;

? printk(KERN_WARNING "SELinux:??unknown mount
option\n");

security/selinux/hooks.c static int selinux_parse_opts_str(char *options, · line 1083

Quoted 3 lines
security/selinux/hooks.c +1 -2
-			goto out_err;
-
+			break;

You've changed what was a fatal error on mount() to just a warning. I can see why - otherwise enabling Smack+SELinux together causes systemd to pass both sets of options to mount() and then SELinux fails on the unrecognized Smack mount option. But doesn't this also mean that we will fail to catch errors where a truly unknown mount option is used? Can't really rely on people to monitor their logs and act on such warnings. It seems like we need to split the options to the security modules so that each one only sees the ones it owns, or otherwise have a validity check at the end that all of the options were consumed by at least one module.

Quoted 250 lines

? }
? }
?
? rc = -ENOMEM;

security/selinux/hooks.c +0 -1
-	opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *),

GFP_KERNEL);

security/selinux/hooks.c +1 -1
-	if (!opts->mnt_opts)
+	opts->selinux.mnt_opts = kcalloc(NUM_SEL_MNT_OPTS,

sizeof(char *), GFP_KERNEL);

security/selinux/hooks.c +1 -0
+	if (!opts->selinux.mnt_opts)

? goto out_err;
?

security/selinux/hooks.c +0 -1
-	opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS,

sizeof(int),

security/selinux/hooks.c +1 -0
+	opts->selinux.mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS,

sizeof(int),
? ???????GFP_KERNEL);

security/selinux/hooks.c +1 -1
-	if (!opts->mnt_opts_flags)
+	if (!opts->selinux.mnt_opts_flags)

? goto out_err;
?
? if (fscontext) {

security/selinux/hooks.c +0 -2
-		opts->mnt_opts[num_mnt_opts] = fscontext;
-		opts->mnt_opts_flags[num_mnt_opts++] =

FSCONTEXT_MNT;

security/selinux/hooks.c +2 -0
+		opts->selinux.mnt_opts[num_mnt_opts] = fscontext;
+		opts->selinux.mnt_opts_flags[num_mnt_opts++] =

FSCONTEXT_MNT;
? }
? if (context) {

security/selinux/hooks.c +2 -2
-		opts->mnt_opts[num_mnt_opts] = context;
-		opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
+		opts->selinux.mnt_opts[num_mnt_opts] = context;
+		opts->selinux.mnt_opts_flags[num_mnt_opts++] =

CONTEXT_MNT;
? }
? if (rootcontext) {

security/selinux/hooks.c +0 -2
-		opts->mnt_opts[num_mnt_opts] = rootcontext;
-		opts->mnt_opts_flags[num_mnt_opts++] =

ROOTCONTEXT_MNT;

security/selinux/hooks.c +2 -0
+		opts->selinux.mnt_opts[num_mnt_opts] = rootcontext;
+		opts->selinux.mnt_opts_flags[num_mnt_opts++] =

ROOTCONTEXT_MNT;
? }
? if (defcontext) {

security/selinux/hooks.c +0 -2
-		opts->mnt_opts[num_mnt_opts] = defcontext;
-		opts->mnt_opts_flags[num_mnt_opts++] =

DEFCONTEXT_MNT;

security/selinux/hooks.c +2 -0
+		opts->selinux.mnt_opts[num_mnt_opts] = defcontext;
+		opts->selinux.mnt_opts_flags[num_mnt_opts++] =

DEFCONTEXT_MNT;
? }
?

security/selinux/hooks.c +1 -1
-	opts->num_mnt_opts = num_mnt_opts;
+	opts->selinux.num_mnt_opts = num_mnt_opts;

? return 0;
?
?out_err:

security/selinux/hooks.c +0 -0
@@ -1156,15 +1156,15 @@ static void selinux_write_opts(struct
 seq_file *m,
 ?	int i;
 ?	char *prefix;

?

security/selinux/hooks.c +1 -1
-	for (i = 0; i < opts->num_mnt_opts; i++) {
+	for (i = 0; i < opts->selinux.num_mnt_opts; i++) {

? char *has_comma;
?

security/selinux/hooks.c +2 -2
-		if (opts->mnt_opts[i])
-			has_comma = strchr(opts->mnt_opts[i], ',');
+		if (opts->selinux.mnt_opts[i])
+			has_comma = strchr(opts-
Quoted 1 line

selinux.mnt_opts[i], ',');

? else
? has_comma = NULL;
?

security/selinux/hooks.c +1 -1
-		switch (opts->mnt_opts_flags[i]) {
+		switch (opts->selinux.mnt_opts_flags[i]) {

? case CONTEXT_MNT:
? prefix = CONTEXT_STR;
? break;

security/selinux/hooks.c +1 -1
@@ -1190,7 +1190,7 @@ static void selinux_write_opts(struct seq_file
 *m,
 ?		seq_puts(m, prefix);
 ?		if (has_comma)
 ?			seq_putc(m, '\"');
-		seq_escape(m, opts->mnt_opts[i], "\"\n\\");
+		seq_escape(m, opts->selinux.mnt_opts[i], "\"\n\\");
 ?		if (has_comma)
 ?			seq_putc(m, '\"');

? }

security/selinux/hooks.c +0 -0
@@ -2705,10 +2705,10 @@ static int selinux_sb_remount(struct
 super_block *sb, void *data)
 ?	if (rc)
 ?		goto out_free_secdata;

?

security/selinux/hooks.c +2 -2
-	mount_options = opts.mnt_opts;
-	flags = opts.mnt_opts_flags;
+	mount_options = opts.selinux.mnt_opts;
+	flags = opts.selinux.mnt_opts_flags;

?

security/selinux/hooks.c +1 -1
-	for (i = 0; i < opts.num_mnt_opts; i++) {
+	for (i = 0; i < opts.selinux.num_mnt_opts; i++) {

? u32 sid;
?
? if (flags[i] == SBLABEL_MNT)

security/smack/smack_lsm.c +0 -0
index 9031f2dc8bfb..9fb9148cf4b5 100644
@@ -602,7 +602,7 @@ static int smack_parse_opts_str(char *options,
 ?	int num_mnt_opts = 0;
 ?	int token;

?

security/smack/smack_lsm.c +1 -1
-	opts->num_mnt_opts = 0;
+	opts->smack.num_mnt_opts = 0;

?
? if (!options)
? return 0;

security/smack/smack_lsm.c +0 -0
@@ -652,43 +652,45 @@ static int smack_parse_opts_str(char *options,
 ?				goto out_err;
 ?			break;

? default:

security/smack/smack_lsm.c +0 -1
-			rc = -EINVAL;

? pr_warn("Smack:??unknown mount option\n");

security/smack/smack_lsm.c +1 -1
-			goto out_err;
+			break;

? }
? }
?

security/smack/smack_lsm.c +0 -1
-	opts->mnt_opts = kcalloc(NUM_SMK_MNT_OPTS, sizeof(char *),

GFP_KERNEL);

security/smack/smack_lsm.c +1 -1
-	if (!opts->mnt_opts)
+	opts->smack.mnt_opts = kcalloc(NUM_SMK_MNT_OPTS, sizeof(char

*),

security/smack/smack_lsm.c +2 -0
+					GFP_KERNEL);
+	if (!opts->smack.mnt_opts)

? goto out_err;
?

security/smack/smack_lsm.c +0 -1
-	opts->mnt_opts_flags = kcalloc(NUM_SMK_MNT_OPTS,

sizeof(int),

security/smack/smack_lsm.c +1 -2
-			GFP_KERNEL);
-	if (!opts->mnt_opts_flags)
+	opts->smack.mnt_opts_flags = kcalloc(NUM_SMK_MNT_OPTS,

sizeof(int),

security/smack/smack_lsm.c +3 -0
+					GFP_KERNEL);
+	if (!opts->smack.mnt_opts_flags) {
+		kfree(opts->smack.mnt_opts);

? goto out_err;

security/smack/smack_lsm.c +1 -0
+	}

?
? if (fsdefault) {

security/smack/smack_lsm.c +0 -2
-		opts->mnt_opts[num_mnt_opts] = fsdefault;
-		opts->mnt_opts_flags[num_mnt_opts++] =

FSDEFAULT_MNT;

security/smack/smack_lsm.c +2 -0
+		opts->smack.mnt_opts[num_mnt_opts] = fsdefault;
+		opts->smack.mnt_opts_flags[num_mnt_opts++] =

FSDEFAULT_MNT;
? }
? if (fsfloor) {

security/smack/smack_lsm.c +2 -2
-		opts->mnt_opts[num_mnt_opts] = fsfloor;
-		opts->mnt_opts_flags[num_mnt_opts++] = FSFLOOR_MNT;
+		opts->smack.mnt_opts[num_mnt_opts] = fsfloor;
+		opts->smack.mnt_opts_flags[num_mnt_opts++] =

FSFLOOR_MNT;
? }
? if (fshat) {

security/smack/smack_lsm.c +2 -2
-		opts->mnt_opts[num_mnt_opts] = fshat;
-		opts->mnt_opts_flags[num_mnt_opts++] = FSHAT_MNT;
+		opts->smack.mnt_opts[num_mnt_opts] = fshat;
+		opts->smack.mnt_opts_flags[num_mnt_opts++] =

FSHAT_MNT;
? }
? if (fsroot) {

security/smack/smack_lsm.c +2 -2
-		opts->mnt_opts[num_mnt_opts] = fsroot;
-		opts->mnt_opts_flags[num_mnt_opts++] = FSROOT_MNT;
+		opts->smack.mnt_opts[num_mnt_opts] = fsroot;
+		opts->smack.mnt_opts_flags[num_mnt_opts++] =

FSROOT_MNT;
? }
? if (fstransmute) {

security/smack/smack_lsm.c +2 -2
-		opts->mnt_opts[num_mnt_opts] = fstransmute;
-		opts->mnt_opts_flags[num_mnt_opts++] = FSTRANS_MNT;
+		opts->smack.mnt_opts[num_mnt_opts] = fstransmute;
+		opts->smack.mnt_opts_flags[num_mnt_opts++] =

FSTRANS_MNT;
? }
?

security/smack/smack_lsm.c +1 -1
-	opts->num_mnt_opts = num_mnt_opts;
+	opts->smack.num_mnt_opts = num_mnt_opts;

? return 0;
?
?out_opt_err:

security/smack/smack_lsm.c +1 -1
@@ -727,7 +729,7 @@ static int smack_set_mnt_opts(struct super_block
 *sb,
 ?	struct inode_smack *isp;
 ?	struct smack_known *skp;
 ?	int i;
-	int num_opts = opts->num_mnt_opts;
+	int num_opts = opts->smack.num_mnt_opts;
 ?	int transmute = 0;

?
? if (sp->smk_flags & SMK_SB_INITIALIZED)

security/smack/smack_lsm.c +0 -0
@@ -761,33 +763,33 @@ static int smack_set_mnt_opts(struct
 super_block *sb,
 ?	sp->smk_flags |= SMK_SB_INITIALIZED;

?
? for (i = 0; i < num_opts; i++) {

security/smack/smack_lsm.c +1 -1
-		switch (opts->mnt_opts_flags[i]) {
+		switch (opts->smack.mnt_opts_flags[i]) {

? case FSDEFAULT_MNT:

security/smack/smack_lsm.c +0 -1
-			skp = smk_import_entry(opts->mnt_opts[i],

0);

security/smack/smack_lsm.c +1 -0
+			skp = smk_import_entry(opts-
Quoted 1 line

smack.mnt_opts[i], 0);

? if (IS_ERR(skp))
? return PTR_ERR(skp);
? sp->smk_default = skp;
? break;
? case FSFLOOR_MNT:

security/smack/smack_lsm.c +0 -1
-			skp = smk_import_entry(opts->mnt_opts[i],

0);

security/smack/smack_lsm.c +1 -0
+			skp = smk_import_entry(opts-
Quoted 1 line

smack.mnt_opts[i], 0);

? if (IS_ERR(skp))
? return PTR_ERR(skp);
? sp->smk_floor = skp;
? break;
? case FSHAT_MNT:

security/smack/smack_lsm.c +0 -1
-			skp = smk_import_entry(opts->mnt_opts[i],

0);

security/smack/smack_lsm.c +1 -0
+			skp = smk_import_entry(opts-
Quoted 1 line

smack.mnt_opts[i], 0);

? if (IS_ERR(skp))
? return PTR_ERR(skp);
? sp->smk_hat = skp;
? break;
? case FSROOT_MNT:

security/smack/smack_lsm.c +0 -1
-			skp = smk_import_entry(opts->mnt_opts[i],

0);

security/smack/smack_lsm.c +1 -0
+			skp = smk_import_entry(opts-
Quoted 1 line

smack.mnt_opts[i], 0);

? if (IS_ERR(skp))
? return PTR_ERR(skp);
? sp->smk_root = skp;
? break;
? case FSTRANS_MNT:

security/smack/smack_lsm.c +0 -1
-			skp = smk_import_entry(opts->mnt_opts[i],

0);

security/smack/smack_lsm.c +1 -0
+			skp = smk_import_entry(opts-
Quoted 1 line

smack.mnt_opts[i], 0);

Quoted 3 lines

? if (IS_ERR(skp))
? return PTR_ERR(skp);
? sp->smk_root = skp;

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#20 lore raw

PATCH 8/9 LSM: Multiple security mount options

Quoted 299 lines · Stephen Smalley
Quoted 293 lines · Casey Schaufler

Subject: [PATCH 8/9] LSM: Multiple security mount options

There needs to be separate data for each of the security modules that support mount options. Expand the security_mnt_opts structure to include an entry for each security module that uses them.

It would be better to have a variable size blob, but there isn't a convenient place to hang such.

---

?fs/btrfs/super.c???????????| 10 +++---
?include/linux/security.h???| 53 ++++++++++++++++++++-------
?security/security.c????????| 15 ++++++--
?security/selinux/hooks.c???| 90 +++++++++++++++++++++++-------------

----------
?security/smack/smack_lsm.c | 54 ++++++++++++++-------------- ?5 files changed, 131 insertions(+), 91 deletions(-)

fs/btrfs/super.c +0 -0
index 35a128acfbd1..f8f828267d45 100644
@@ -1512,15 +1512,15 @@ static int setup_security_options(struct
 btrfs_fs_info *fs_info,
 ?		return ret;

?
?#ifdef CONFIG_SECURITY

fs/btrfs/super.c +2 -1
-	if (!fs_info->security_opts.num_mnt_opts) {
+	if (fs_info->security_opts.selinux.num_mnt_opts != 0 ||
+	????fs_info->security_opts.smack.num_mnt_opts != 0) {

? /* first time security setup, copy sec_opts to
fs_info */
? memcpy(&fs_info->security_opts, sec_opts,
sizeof(*sec_opts));
? } else {
? /*

fs/btrfs/super.c +0 -1
-		?* Since SELinux (the only one supporting

security_mnt_opts)

fs/btrfs/super.c +0 -1
-		?* does NOT support changing context during

remount/mount of

fs/btrfs/super.c +0 -1
-		?* the same sb, this must be the same or part of the

same

fs/btrfs/super.c +2 -1
-		?* security options, just free it.
+		?* Since no modules support changing context during
+		?* remount/mount of the same sb, this must be the

same

fs/btrfs/super.c +1 -0
+		?* or part of the same security options, just free

it.
? ?*/
? security_free_mnt_opts(sec_opts);
? }

include/linux/security.h +0 -0
index 46ec92658ad3..3a70b23a7dcc 100644
@@ -163,34 +163,63 @@ typedef int (*initxattrs) (struct inode *inode,

?
?#ifdef CONFIG_SECURITY
?

include/linux/security.h +1 -1
-struct security_mnt_opts {
+struct lsm_mnt_opts {

? char **mnt_opts;
? int *mnt_opts_flags;
? int num_mnt_opts;
?};
?

include/linux/security.h +13 -0
+
+struct security_mnt_opts {
+#ifdef CONFIG_SECURITY_STACKING
+	struct lsm_mnt_opts?????selinux;
+	struct lsm_mnt_opts?????smack;
+#else
+	union {
+		struct lsm_mnt_opts?????selinux;
+		struct lsm_mnt_opts?????smack;
+	};
+#endif
+};
+

?int call_lsm_notifier(enum lsm_event event, void *data); ?int register_lsm_notifier(struct notifier_block *nb); ?int unregister_lsm_notifier(struct notifier_block *nb); ?
?static inline void security_init_mnt_opts(struct security_mnt_opts *opts)
?{

include/linux/security.h +8 -3
-	opts->mnt_opts = NULL;
-	opts->mnt_opts_flags = NULL;
-	opts->num_mnt_opts = 0;
+	opts->selinux.mnt_opts = NULL;
+	opts->selinux.mnt_opts_flags = NULL;
+	opts->selinux.num_mnt_opts = 0;
+#ifdef CONFIG_SECURITY_STACKING
+	opts->smack.mnt_opts = NULL;
+	opts->smack.mnt_opts_flags = NULL;
+	opts->smack.num_mnt_opts = 0;
+#endif

?}
?
?static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
?{
? int i;

include/linux/security.h +19 -8
-	if (opts->mnt_opts)
-		for (i = 0; i < opts->num_mnt_opts; i++)
-			kfree(opts->mnt_opts[i]);
-	kfree(opts->mnt_opts);
-	opts->mnt_opts = NULL;
-	kfree(opts->mnt_opts_flags);
-	opts->mnt_opts_flags = NULL;
-	opts->num_mnt_opts = 0;
+	if (opts->selinux.mnt_opts)
+		for (i = 0; i < opts->selinux.num_mnt_opts; i++)
+			kfree(opts->selinux.mnt_opts[i]);
+	kfree(opts->selinux.mnt_opts);
+	opts->selinux.mnt_opts = NULL;
+	kfree(opts->selinux.mnt_opts_flags);
+	opts->selinux.mnt_opts_flags = NULL;
+	opts->selinux.num_mnt_opts = 0;
+
+#ifdef CONFIG_SECURITY_STACKING
+	if (opts->smack.mnt_opts)
+		for (i = 0; i < opts->smack.num_mnt_opts; i++)
+			kfree(opts->smack.mnt_opts[i]);
+	kfree(opts->smack.mnt_opts);
+	opts->smack.mnt_opts = NULL;
+	kfree(opts->smack.mnt_opts_flags);
+	opts->smack.mnt_opts_flags = NULL;
+	opts->smack.num_mnt_opts = 0;
+#endif

?}
?
?/* prototypes */

security/security.c +11 -3
index 0269971b3b05..7a004006e761 100644
@@ -771,9 +771,18 @@ int security_sb_set_mnt_opts(struct super_block
 *sb,
 ?				unsigned long kern_flags,
 ?				unsigned long *set_kern_flags)
 ?{
-	return call_int_hook(sb_set_mnt_opts,
-				opts->num_mnt_opts ? -EOPNOTSUPP :
 0, sb,
-				opts, kern_flags, set_kern_flags);
+	int nobody = 0;
+
+#ifdef SECURITY_EXTREME_STACKING
+	if (opts->selinux.num_mnt_opts != 0 || opts-
 > smack.num_mnt_opts != 0)
+		nobody = -EOPNOTSUPP;
+#else
+	if (opts->selinux.num_mnt_opts != 0)
+		nobody = -EOPNOTSUPP;
+#endif
+
+	return call_int_hook(sb_set_mnt_opts, nobody, sb, opts,

kern_flags,

security/security.c +1 -0
+				set_kern_flags);

?} ?EXPORT_SYMBOL(security_sb_set_mnt_opts); ?

security/selinux/hooks.c +0 -0
index e6d6ab671493..395fbfa7bfac 100644
@@ -545,21 +545,23 @@ static int selinux_get_mnt_opts(const struct
 super_block *sb,

? /* count the number of mount options for this sb */
? for (i = 0; i < NUM_SEL_MNT_OPTS; i++) {
? if (tmp & 0x01)

security/selinux/hooks.c +1 -1
-			opts->num_mnt_opts++;
+			opts->selinux.num_mnt_opts++;

? tmp >>= 1;
? }
? /* Check if the Label support flag is set */
? if (sbsec->flags & SBLABEL_MNT)

security/selinux/hooks.c +1 -1
-		opts->num_mnt_opts++;
+		opts->selinux.num_mnt_opts++;

?

security/selinux/hooks.c +0 -1
-	opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *),

GFP_ATOMIC);

security/selinux/hooks.c +2 -1
-	if (!opts->mnt_opts) {
+	opts->selinux.mnt_opts = kcalloc(opts->selinux.num_mnt_opts,
+						sizeof(char *),

GFP_ATOMIC);

security/selinux/hooks.c +1 -0
+	if (!opts->selinux.mnt_opts) {

? rc = -ENOMEM;
? goto out_free;
? }
?

security/selinux/hooks.c +0 -1
-	opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts,

sizeof(int), GFP_ATOMIC);

security/selinux/hooks.c +1 -1
-	if (!opts->mnt_opts_flags) {
+	opts->selinux.mnt_opts_flags = kcalloc(opts-
Quoted 1 line

selinux.num_mnt_opts,

security/selinux/hooks.c +1 -0
+						sizeof(int),

GFP_ATOMIC);

security/selinux/hooks.c +1 -0
+	if (!opts->selinux.mnt_opts_flags) {

? rc = -ENOMEM;
? goto out_free;
? }

security/selinux/hooks.c +6 -6
@@ -569,22 +571,22 @@ static int selinux_get_mnt_opts(const struct
 super_block *sb,
 ?		rc = security_sid_to_context(sbsec->sid, &context,
 &len);
 ?		if (rc)
 ?			goto out_free;
-		opts->mnt_opts[i] = context;
-		opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
+		opts->selinux.mnt_opts[i] = context;
+		opts->selinux.mnt_opts_flags[i++] = FSCONTEXT_MNT;
 ?	}
 ?	if (sbsec->flags & CONTEXT_MNT) {
 ?		rc = security_sid_to_context(sbsec->mntpoint_sid,
 &context, &len);
 ?		if (rc)
 ?			goto out_free;
-		opts->mnt_opts[i] = context;
-		opts->mnt_opts_flags[i++] = CONTEXT_MNT;
+		opts->selinux.mnt_opts[i] = context;
+		opts->selinux.mnt_opts_flags[i++] = CONTEXT_MNT;
 ?	}
 ?	if (sbsec->flags & DEFCONTEXT_MNT) {
 ?		rc = security_sid_to_context(sbsec->def_sid,
 &context, &len);
 ?		if (rc)
 ?			goto out_free;
-		opts->mnt_opts[i] = context;
-		opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
+		opts->selinux.mnt_opts[i] = context;
+		opts->selinux.mnt_opts_flags[i++] = DEFCONTEXT_MNT;

? }
? if (sbsec->flags & ROOTCONTEXT_MNT) {
? struct dentry *root = sbsec->sb->s_root;

security/selinux/hooks.c +4 -4
@@ -594,15 +596,15 @@ static int selinux_get_mnt_opts(const struct
 super_block *sb,
 ?		rc = security_sid_to_context(isec->sid, &context,
 &len);
 ?		if (rc)
 ?			goto out_free;
-		opts->mnt_opts[i] = context;
-		opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
+		opts->selinux.mnt_opts[i] = context;
+		opts->selinux.mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
 ?	}
 ?	if (sbsec->flags & SBLABEL_MNT) {
-		opts->mnt_opts[i] = NULL;
-		opts->mnt_opts_flags[i++] = SBLABEL_MNT;
+		opts->selinux.mnt_opts[i] = NULL;
+		opts->selinux.mnt_opts_flags[i++] = SBLABEL_MNT;
 ?	}

?

security/selinux/hooks.c +1 -1
-	BUG_ON(i != opts->num_mnt_opts);
+	BUG_ON(i != opts->selinux.num_mnt_opts);

?
? return 0;
?

security/selinux/hooks.c +3 -3
@@ -648,9 +650,9 @@ static int selinux_set_mnt_opts(struct
 super_block *sb,
 ?	struct inode_security_struct *root_isec;
 ?	u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
 ?	u32 defcontext_sid = 0;
-	char **mount_options = opts->mnt_opts;
-	int *flags = opts->mnt_opts_flags;
-	int num_opts = opts->num_mnt_opts;
+	char **mount_options = opts->selinux.mnt_opts;
+	int *flags = opts->selinux.mnt_opts_flags;
+	int num_opts = opts->selinux.num_mnt_opts;

?
? mutex_lock(&sbsec->lock);
?

security/selinux/hooks.c +0 -0
@@ -1010,7 +1012,7 @@ static int selinux_parse_opts_str(char
 *options,
 ?	char *fscontext = NULL, *rootcontext = NULL;
 ?	int rc, num_mnt_opts = 0;

?

security/selinux/hooks.c +1 -1
-	opts->num_mnt_opts = 0;
+	opts->selinux.num_mnt_opts = 0;

?
? /* Standard string-based options. */
? while ((p = strsep(&options, "|")) != NULL) {

security/selinux/hooks.c +0 -0
@@ -1077,41 +1079,39 @@ static int selinux_parse_opts_str(char
 *options,

? case Opt_labelsupport:
? break;
? default:

security/selinux/hooks.c +0 -1
-			rc = -EINVAL;

? printk(KERN_WARNING "SELinux:??unknown mount
option\n");

security/selinux/hooks.c static int selinux_parse_opts_str(char *options, · line 1083

Quoted 3 lines
security/selinux/hooks.c +1 -2
-			goto out_err;
-
+			break;

You've changed what was a fatal error on mount() to just a warning. I can see why - otherwise enabling Smack+SELinux together causes

Quoted 8 lines

systemd to pass both sets of options to mount() and then SELinux fails on the unrecognized Smack mount option. But doesn't this also mean that we will fail to catch errors where a truly unknown mount option is used? Can't really rely on people to monitor their logs and act on such warnings. It seems like we need to split the options to the security modules so that each one only sees the ones it owns, or otherwise have a validity check at the end that all of the options were consumed by at least one module.

My tests show correct behavior for all cases.

	succeeds:	smackfsroot='*'
	succeeds:	smackfsroot='*',seclabel
	fails:		ferbel=99
	fails:		smackfsroot='*',seclabel,ferbel=99

I am willing to accept that there may be combinations that do not work correctly, but I don't see one.

I am also expecting David Howells' rewhack of the mount code to land soon. That will require a complete rethink of this implementation. If that doesn't land it may be worth considering moving the logic which is almost identical in SELinux and Smack to the infrastructure and passing module specific option lists.

Quoted 250 lines
Quoted 250 lines

? }
? }
?
? rc = -ENOMEM;

security/selinux/hooks.c +0 -1
-	opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *),

GFP_KERNEL);

security/selinux/hooks.c +1 -1
-	if (!opts->mnt_opts)
+	opts->selinux.mnt_opts = kcalloc(NUM_SEL_MNT_OPTS,

sizeof(char *), GFP_KERNEL);

security/selinux/hooks.c +1 -0
+	if (!opts->selinux.mnt_opts)

? goto out_err;
?

security/selinux/hooks.c +0 -1
-	opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS,

sizeof(int),

security/selinux/hooks.c +1 -0
+	opts->selinux.mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS,

sizeof(int),
? ???????GFP_KERNEL);

security/selinux/hooks.c +1 -1
-	if (!opts->mnt_opts_flags)
+	if (!opts->selinux.mnt_opts_flags)

? goto out_err;
?
? if (fscontext) {

security/selinux/hooks.c +0 -2
-		opts->mnt_opts[num_mnt_opts] = fscontext;
-		opts->mnt_opts_flags[num_mnt_opts++] =

FSCONTEXT_MNT;

security/selinux/hooks.c +2 -0
+		opts->selinux.mnt_opts[num_mnt_opts] = fscontext;
+		opts->selinux.mnt_opts_flags[num_mnt_opts++] =

FSCONTEXT_MNT;
? }
? if (context) {

security/selinux/hooks.c +2 -2
-		opts->mnt_opts[num_mnt_opts] = context;
-		opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
+		opts->selinux.mnt_opts[num_mnt_opts] = context;
+		opts->selinux.mnt_opts_flags[num_mnt_opts++] =

CONTEXT_MNT;
? }
? if (rootcontext) {

security/selinux/hooks.c +0 -2
-		opts->mnt_opts[num_mnt_opts] = rootcontext;
-		opts->mnt_opts_flags[num_mnt_opts++] =

ROOTCONTEXT_MNT;

security/selinux/hooks.c +2 -0
+		opts->selinux.mnt_opts[num_mnt_opts] = rootcontext;
+		opts->selinux.mnt_opts_flags[num_mnt_opts++] =

ROOTCONTEXT_MNT;
? }
? if (defcontext) {

security/selinux/hooks.c +0 -2
-		opts->mnt_opts[num_mnt_opts] = defcontext;
-		opts->mnt_opts_flags[num_mnt_opts++] =

DEFCONTEXT_MNT;

security/selinux/hooks.c +2 -0
+		opts->selinux.mnt_opts[num_mnt_opts] = defcontext;
+		opts->selinux.mnt_opts_flags[num_mnt_opts++] =

DEFCONTEXT_MNT;
? }
?

security/selinux/hooks.c +1 -1
-	opts->num_mnt_opts = num_mnt_opts;
+	opts->selinux.num_mnt_opts = num_mnt_opts;

? return 0;
?
?out_err:

security/selinux/hooks.c +0 -0
@@ -1156,15 +1156,15 @@ static void selinux_write_opts(struct
 seq_file *m,
 ?	int i;
 ?	char *prefix;

?

security/selinux/hooks.c +1 -1
-	for (i = 0; i < opts->num_mnt_opts; i++) {
+	for (i = 0; i < opts->selinux.num_mnt_opts; i++) {

? char *has_comma;
?

security/selinux/hooks.c +2 -2
-		if (opts->mnt_opts[i])
-			has_comma = strchr(opts->mnt_opts[i], ',');
+		if (opts->selinux.mnt_opts[i])
+			has_comma = strchr(opts-
Quoted 1 line

selinux.mnt_opts[i], ',');

? else
? has_comma = NULL;
?

security/selinux/hooks.c +1 -1
-		switch (opts->mnt_opts_flags[i]) {
+		switch (opts->selinux.mnt_opts_flags[i]) {

? case CONTEXT_MNT:
? prefix = CONTEXT_STR;
? break;

security/selinux/hooks.c +1 -1
@@ -1190,7 +1190,7 @@ static void selinux_write_opts(struct seq_file
 *m,
 ?		seq_puts(m, prefix);
 ?		if (has_comma)
 ?			seq_putc(m, '\"');
-		seq_escape(m, opts->mnt_opts[i], "\"\n\\");
+		seq_escape(m, opts->selinux.mnt_opts[i], "\"\n\\");
 ?		if (has_comma)
 ?			seq_putc(m, '\"');

? }

security/selinux/hooks.c +0 -0
@@ -2705,10 +2705,10 @@ static int selinux_sb_remount(struct
 super_block *sb, void *data)
 ?	if (rc)
 ?		goto out_free_secdata;

?

security/selinux/hooks.c +2 -2
-	mount_options = opts.mnt_opts;
-	flags = opts.mnt_opts_flags;
+	mount_options = opts.selinux.mnt_opts;
+	flags = opts.selinux.mnt_opts_flags;

?

security/selinux/hooks.c +1 -1
-	for (i = 0; i < opts.num_mnt_opts; i++) {
+	for (i = 0; i < opts.selinux.num_mnt_opts; i++) {

? u32 sid;
?
? if (flags[i] == SBLABEL_MNT)

security/smack/smack_lsm.c +0 -0
index 9031f2dc8bfb..9fb9148cf4b5 100644
@@ -602,7 +602,7 @@ static int smack_parse_opts_str(char *options,
 ?	int num_mnt_opts = 0;
 ?	int token;

?

security/smack/smack_lsm.c +1 -1
-	opts->num_mnt_opts = 0;
+	opts->smack.num_mnt_opts = 0;

?
? if (!options)
? return 0;

security/smack/smack_lsm.c +0 -0
@@ -652,43 +652,45 @@ static int smack_parse_opts_str(char *options,
 ?				goto out_err;
 ?			break;

? default:

security/smack/smack_lsm.c +0 -1
-			rc = -EINVAL;

? pr_warn("Smack:??unknown mount option\n");

security/smack/smack_lsm.c +1 -1
-			goto out_err;
+			break;

? }
? }
?

security/smack/smack_lsm.c +0 -1
-	opts->mnt_opts = kcalloc(NUM_SMK_MNT_OPTS, sizeof(char *),

GFP_KERNEL);

security/smack/smack_lsm.c +1 -1
-	if (!opts->mnt_opts)
+	opts->smack.mnt_opts = kcalloc(NUM_SMK_MNT_OPTS, sizeof(char

*),

security/smack/smack_lsm.c +2 -0
+					GFP_KERNEL);
+	if (!opts->smack.mnt_opts)

? goto out_err;
?

security/smack/smack_lsm.c +0 -1
-	opts->mnt_opts_flags = kcalloc(NUM_SMK_MNT_OPTS,

sizeof(int),

security/smack/smack_lsm.c +1 -2
-			GFP_KERNEL);
-	if (!opts->mnt_opts_flags)
+	opts->smack.mnt_opts_flags = kcalloc(NUM_SMK_MNT_OPTS,

sizeof(int),

security/smack/smack_lsm.c +3 -0
+					GFP_KERNEL);
+	if (!opts->smack.mnt_opts_flags) {
+		kfree(opts->smack.mnt_opts);

? goto out_err;

security/smack/smack_lsm.c +1 -0
+	}

?
? if (fsdefault) {

security/smack/smack_lsm.c +0 -2
-		opts->mnt_opts[num_mnt_opts] = fsdefault;
-		opts->mnt_opts_flags[num_mnt_opts++] =

FSDEFAULT_MNT;

security/smack/smack_lsm.c +2 -0
+		opts->smack.mnt_opts[num_mnt_opts] = fsdefault;
+		opts->smack.mnt_opts_flags[num_mnt_opts++] =

FSDEFAULT_MNT;
? }
? if (fsfloor) {

security/smack/smack_lsm.c +2 -2
-		opts->mnt_opts[num_mnt_opts] = fsfloor;
-		opts->mnt_opts_flags[num_mnt_opts++] = FSFLOOR_MNT;
+		opts->smack.mnt_opts[num_mnt_opts] = fsfloor;
+		opts->smack.mnt_opts_flags[num_mnt_opts++] =

FSFLOOR_MNT;
? }
? if (fshat) {

security/smack/smack_lsm.c +2 -2
-		opts->mnt_opts[num_mnt_opts] = fshat;
-		opts->mnt_opts_flags[num_mnt_opts++] = FSHAT_MNT;
+		opts->smack.mnt_opts[num_mnt_opts] = fshat;
+		opts->smack.mnt_opts_flags[num_mnt_opts++] =

FSHAT_MNT;
? }
? if (fsroot) {

security/smack/smack_lsm.c +2 -2
-		opts->mnt_opts[num_mnt_opts] = fsroot;
-		opts->mnt_opts_flags[num_mnt_opts++] = FSROOT_MNT;
+		opts->smack.mnt_opts[num_mnt_opts] = fsroot;
+		opts->smack.mnt_opts_flags[num_mnt_opts++] =

FSROOT_MNT;
? }
? if (fstransmute) {

security/smack/smack_lsm.c +2 -2
-		opts->mnt_opts[num_mnt_opts] = fstransmute;
-		opts->mnt_opts_flags[num_mnt_opts++] = FSTRANS_MNT;
+		opts->smack.mnt_opts[num_mnt_opts] = fstransmute;
+		opts->smack.mnt_opts_flags[num_mnt_opts++] =

FSTRANS_MNT;
? }
?

security/smack/smack_lsm.c +1 -1
-	opts->num_mnt_opts = num_mnt_opts;
+	opts->smack.num_mnt_opts = num_mnt_opts;

? return 0;
?
?out_opt_err:

security/smack/smack_lsm.c +1 -1
@@ -727,7 +729,7 @@ static int smack_set_mnt_opts(struct super_block
 *sb,
 ?	struct inode_smack *isp;
 ?	struct smack_known *skp;
 ?	int i;
-	int num_opts = opts->num_mnt_opts;
+	int num_opts = opts->smack.num_mnt_opts;
 ?	int transmute = 0;

?
? if (sp->smk_flags & SMK_SB_INITIALIZED)

security/smack/smack_lsm.c +0 -0
@@ -761,33 +763,33 @@ static int smack_set_mnt_opts(struct
 super_block *sb,
 ?	sp->smk_flags |= SMK_SB_INITIALIZED;

?
? for (i = 0; i < num_opts; i++) {

security/smack/smack_lsm.c +1 -1
-		switch (opts->mnt_opts_flags[i]) {
+		switch (opts->smack.mnt_opts_flags[i]) {

? case FSDEFAULT_MNT:

security/smack/smack_lsm.c +0 -1
-			skp = smk_import_entry(opts->mnt_opts[i],

0);

security/smack/smack_lsm.c +1 -0
+			skp = smk_import_entry(opts-
Quoted 1 line

smack.mnt_opts[i], 0);

? if (IS_ERR(skp))
? return PTR_ERR(skp);
? sp->smk_default = skp;
? break;
? case FSFLOOR_MNT:

security/smack/smack_lsm.c +0 -1
-			skp = smk_import_entry(opts->mnt_opts[i],

0);

security/smack/smack_lsm.c +1 -0
+			skp = smk_import_entry(opts-
Quoted 1 line

smack.mnt_opts[i], 0);

? if (IS_ERR(skp))
? return PTR_ERR(skp);
? sp->smk_floor = skp;
? break;
? case FSHAT_MNT:

security/smack/smack_lsm.c +0 -1
-			skp = smk_import_entry(opts->mnt_opts[i],

0);

security/smack/smack_lsm.c +1 -0
+			skp = smk_import_entry(opts-
Quoted 1 line

smack.mnt_opts[i], 0);

? if (IS_ERR(skp))
? return PTR_ERR(skp);
? sp->smk_hat = skp;
? break;
? case FSROOT_MNT:

security/smack/smack_lsm.c +0 -1
-			skp = smk_import_entry(opts->mnt_opts[i],

0);

security/smack/smack_lsm.c +1 -0
+			skp = smk_import_entry(opts-
Quoted 1 line

smack.mnt_opts[i], 0);

? if (IS_ERR(skp))
? return PTR_ERR(skp);
? sp->smk_root = skp;
? break;
? case FSTRANS_MNT:

security/smack/smack_lsm.c +0 -1
-			skp = smk_import_entry(opts->mnt_opts[i],

0);

security/smack/smack_lsm.c +1 -0
+			skp = smk_import_entry(opts-
Quoted 4 lines
Quoted 4 lines
Quoted 1 line

smack.mnt_opts[i], 0);

? if (IS_ERR(skp))
? return PTR_ERR(skp);
? sp->smk_root = skp;

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#21 lore raw

PATCH 9/9 LSM: Full security module stacking

In reply to Casey Schaufler

Subject: [PATCH 9/9] LSM: Full security module stacking

Allow any combination of existing security modules, including those using secids and security marked networking.

The interfaces used by filesystems to maintain security attributes:
security_inode_setsecctx security_inode_getsecctx security_inode_notifysecctx
have been trained to keep a full set of attributes using the "lsm1='data1',lsm2='data2'" format.

A sockopt interface has been added to identify which security module should be invoked when secids are translated to secctx and back. If none is specified the first module will be used. This eliminates the ambiguity of what data will be seen in user-space at the cost of requiring user-space code to be explicit about what it wants to see.

Issues remain with the use of netlabel, as SELinux and Smack use the interfaces differently.

Audit has not been fully tested, and may not always be providing the correct security module information.

---
 arch/alpha/include/uapi/asm/socket.h    |   2 +
 arch/frv/include/uapi/asm/socket.h      |   2 +
 arch/ia64/include/uapi/asm/socket.h     |   2 +
 arch/m32r/include/uapi/asm/socket.h     |   2 +
 arch/mips/include/uapi/asm/socket.h     |   2 +
 arch/mn10300/include/uapi/asm/socket.h  |   2 +
 arch/parisc/include/uapi/asm/socket.h   |   2 +
 arch/s390/include/uapi/asm/socket.h     |   2 +
 arch/sparc/include/uapi/asm/socket.h    |   2 +
 arch/xtensa/include/uapi/asm/socket.h   |   2 +
 fs/xattr.c                              |   2 +-
 include/linux/security.h                |  35 ++-
 include/net/scm.h                       |   3 +-
 include/uapi/asm-generic/socket.h       |   2 +
 kernel/audit.c                          |  16 +-
 kernel/auditsc.c                        |   4 +-
 kernel/cred.c                           |   2 +-
 net/core/sock.c                         |   4 +
 net/ipv4/ip_sockglue.c                  |   8 +-
 net/netfilter/nf_conntrack_netlink.c    |   9 +-
 net/netfilter/nf_conntrack_standalone.c |   2 +-
 net/netfilter/nfnetlink_queue.c         |   3 +-
 net/netfilter/xt_SECMARK.c              |   2 +-
 net/netlabel/netlabel_unlabeled.c       |  12 +-
 net/netlabel/netlabel_user.c            |   2 +-
 security/Kconfig                        |  52 +----
 security/security.c                     | 378 ++++++++++++++++++++++++++++----
 security/selinux/hooks.c                |   4 +
 security/smack/smack_lsm.c              |  18 +-
 29 files changed, 456 insertions(+), 122 deletions(-)
arch/alpha/include/uapi/asm/socket.h +2 -0
index c6133a045352..3089e9a35a2b 100644
@@ -111,4 +111,6 @@
 
 #define SO_ZEROCOPY		60
 
+#define SO_LSMSEC		61
+
 #endif /* _UAPI_ASM_SOCKET_H */
arch/frv/include/uapi/asm/socket.h +2 -0
index 9abf02d6855a..77c671cd0b81 100644
@@ -104,5 +104,7 @@
 
 #define SO_ZEROCOPY		60
 
+#define SO_LSMSEC		61
+
 #endif /* _ASM_SOCKET_H */
 
arch/ia64/include/uapi/asm/socket.h +2 -0
index 002eb85a6941..6c0ebb0ff56e 100644
@@ -113,4 +113,6 @@
 
 #define SO_ZEROCOPY		60
 
+#define SO_LSMSEC		61
+
 #endif /* _ASM_IA64_SOCKET_H */
arch/m32r/include/uapi/asm/socket.h +2 -0
index e268e51a38d1..58e36a070ea2 100644
@@ -104,4 +104,6 @@
 
 #define SO_ZEROCOPY		60
 
+#define SO_LSMSEC		61
+
 #endif /* _ASM_M32R_SOCKET_H */
arch/mips/include/uapi/asm/socket.h +2 -0
index 6c755bc07975..d2c700015a8b 100644
@@ -122,4 +122,6 @@
 
 #define SO_ZEROCOPY		60
 
+#define SO_LSMSEC		61
+
 #endif /* _UAPI_ASM_SOCKET_H */
arch/mn10300/include/uapi/asm/socket.h +2 -0
index ac82a3f26dbf..4906db01d5db 100644
@@ -104,4 +104,6 @@
 
 #define SO_ZEROCOPY		60
 
+#define SO_LSMSEC		61
+
 #endif /* _ASM_SOCKET_H */
arch/parisc/include/uapi/asm/socket.h +2 -0
index 3b2bf7ae703b..54ba5e44ab89 100644
@@ -103,4 +103,6 @@
 
 #define SO_ZEROCOPY		0x4035
 
+#define SO_LSMSEC		0x4036
+
 #endif /* _UAPI_ASM_SOCKET_H */
arch/s390/include/uapi/asm/socket.h +2 -0
index a56916c83565..48b4e0b835df 100644
@@ -110,4 +110,6 @@
 
 #define SO_ZEROCOPY		60
 
+#define SO_LSMSEC		61
+
 #endif /* _ASM_SOCKET_H */
arch/sparc/include/uapi/asm/socket.h +2 -0
index b2f5c50d0947..d97aa57a5987 100644
@@ -100,6 +100,8 @@
 
 #define SO_ZEROCOPY		0x003e
 
+#define SO_LSMSEC		0x003f
+
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x5001
 #define SO_SECURITY_ENCRYPTION_TRANSPORT	0x5002
arch/xtensa/include/uapi/asm/socket.h +2 -0
index 220059999e74..6f3f257d6fdd 100644
@@ -115,4 +115,6 @@
 
 #define SO_ZEROCOPY		60
 
+#define SO_LSMSEC		61
+
 #endif	/* _XTENSA_SOCKET_H */
fs/xattr.c +1 -1
index 4424f7fecf14..61cd28ba25f3 100644
@@ -250,7 +250,7 @@ xattr_getsecurity(struct inode *inode, const char *name, void *value,
 	}
 	memcpy(value, buffer, len);
 out:
-	security_release_secctx(buffer, len);
+	kfree(buffer);
 out_noalloc:
 	return len;
 }
include/linux/security.h +27 -8
index 3a70b23a7dcc..8e06d9614736 100644
@@ -410,8 +410,10 @@ int security_setprocattr(const char *lsm, const char *name, void *value,
 			 size_t size);
 int security_netlink_send(struct sock *sk, struct sk_buff *skb);
 int security_ismaclabel(const char *name);
-int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
-int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
+int security_secid_to_secctx(const char *lsm, u32 secid, char **secdata,
+			     u32 *seclen);
+int security_secctx_to_secid(const char *lsm, const char *secdata, u32 seclen,
+			     u32 *secid);
 void security_release_secctx(char *secdata, u32 seclen);
 
 void security_inode_invalidate_secctx(struct inode *inode);
@@ -1185,14 +1187,14 @@ static inline int security_ismaclabel(const char *name)
 	return 0;
 }
 
-static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+static inline int security_secid_to_secctx(const char *lsm, u32 secid,
+					   char **secdata, u32 *seclen)
 {
 	return -EOPNOTSUPP;
 }
 
-static inline int security_secctx_to_secid(const char *secdata,
-					   u32 seclen,
-					   u32 *secid)
+static inline int security_secctx_to_secid(const char *lsm, const char *secdata,
+					   u32 seclen, u32 *secid)
 {
 	return -EOPNOTSUPP;
 }
@@ -1241,6 +1243,8 @@ int security_socket_shutdown(struct socket *sock, int how);
 int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb);
 int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
 				      int __user *optlen, unsigned len);
+int security_socket_passed_lsm(struct socket *sock, char __user *optval,
+				      unsigned int optlen);
 int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid);
 int security_sk_alloc(struct sock *sk, int family, gfp_t priority);
 void security_sk_free(struct sock *sk);
@@ -1263,6 +1267,7 @@ int security_tun_dev_create(void);
 int security_tun_dev_attach_queue(void *security);
 int security_tun_dev_attach(struct sock *sk, void *security);
 int security_tun_dev_open(void *security);
+char *security_socket_lsm(const struct sock *sk);
 
 #else	/* CONFIG_SECURITY_NETWORK */
 static inline int security_unix_stream_connect(struct sock *sock,
@@ -1362,12 +1367,21 @@ static inline int security_sock_rcv_skb(struct sock *sk,
 	return 0;
 }
 
-static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
-						    int __user *optlen, unsigned len)
+static inline int security_socket_getpeersec_stream(struct socket *sock,
+						    char __user *optval,
+						    int __user *optlen,
+						    unsigned len)
 {
 	return -ENOPROTOOPT;
 }
 
+static inline int security_socket_passed_lsm(struct socket *sock,
+					     char __user *optval,
+					     unsigned int optlen)
+{
+	return -EOPNOTSUPP;
+}
+
 static inline int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
 {
 	return -ENOPROTOOPT;
@@ -1455,6 +1469,11 @@ static inline int security_tun_dev_open(void *security)
 {
 	return 0;
 }
+
+static inline char *security_socket_lsm(const struct sock *sk)
+{
+	return NULL;
+}
 #endif	/* CONFIG_SECURITY_NETWORK */
 
 #ifdef CONFIG_SECURITY_INFINIBAND
include/net/scm.h +2 -1
index 142ea9e7a6d0..4783ba64773b 100644
@@ -95,7 +95,8 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
 	int err;
 
 	if (test_bit(SOCK_PASSSEC, &sock->flags)) {
-		err = security_secid_to_secctx(scm->secid, &secdata, &seclen);
+		err = security_secid_to_secctx(security_socket_lsm(sock->sk),
+						scm->secid, &secdata, &seclen);
 
 		if (!err) {
 			put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata);
include/uapi/asm-generic/socket.h +2 -0
index e47c9e436221..c5ed101d0be1 100644
@@ -106,4 +106,6 @@
 
 #define SO_ZEROCOPY		60
 
+#define SO_LSMSEC		61
+
 #endif /* __ASM_GENERIC_SOCKET_H */
kernel/audit.c +10 -6
index be1c28fd4d57..e4a016ce9580 100644
@@ -1374,7 +1374,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 	case AUDIT_SIGNAL_INFO:
 		len = 0;
 		if (audit_sig_sid) {
-			err = security_secid_to_secctx(audit_sig_sid, &ctx, &len);
+			err = security_secid_to_secctx(NULL, audit_sig_sid, &ctx, &len);
 			if (err)
 				return err;
 		}
@@ -2107,7 +2107,7 @@ void audit_log_name(struct audit_context *context, struct audit_names *n,
 	if (n->osid != 0) {
 		char *ctx = NULL;
 		u32 len;
-		if (security_secid_to_secctx(
+		if (security_secid_to_secctx(NULL,
 			n->osid, &ctx, &len)) {
 			audit_log_format(ab, " osid=%u", n->osid);
 			if (call_panic)
@@ -2153,7 +2153,7 @@ int audit_log_task_context(struct audit_buffer *ab)
 	if (!sid)
 		return 0;
 
-	error = security_secid_to_secctx(sid, &ctx, &len);
+	error = security_secid_to_secctx(NULL, sid, &ctx, &len);
 	if (error) {
 		if (error != -EINVAL)
 			goto error_path;
@@ -2339,21 +2339,25 @@ void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type,
 
 #ifdef CONFIG_SECURITY
 /**
- * audit_log_secctx - Converts and logs SELinux context
+ * audit_log_secctx - Converts and logs security context
  * @ab: audit_buffer
  * @secid: security number
  *
  * This is a helper function that calls security_secid_to_secctx to convert
- * secid to secctx and then adds the (converted) SELinux context to the audit
+ * secid to secctx and then adds the (converted) security context to the audit
  * log by calling audit_log_format, thus also preventing leak of internal secid
  * to userspace. If secid cannot be converted audit_panic is called.
+ *
+ * Note: There is not sufficient information in the input to
+ * determine which security module the caller is interested in
+ * in the multiple security module case.
  */
 void audit_log_secctx(struct audit_buffer *ab, u32 secid)
 {
 	u32 len;
 	char *secctx;
 
-	if (security_secid_to_secctx(secid, &secctx, &len)) {
+	if (security_secid_to_secctx(NULL, secid, &secctx, &len)) {
 		audit_panic("Cannot convert secid to context");
 	} else {
 		audit_log_format(ab, " obj=%s", secctx);
kernel/auditsc.c +2 -2
index ecc23e25c9eb..6427e1956345 100644
@@ -984,7 +984,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
 			 from_kuid(&init_user_ns, auid),
 			 from_kuid(&init_user_ns, uid), sessionid);
 	if (sid) {
-		if (security_secid_to_secctx(sid, &ctx, &len)) {
+		if (security_secid_to_secctx(NULL, sid, &ctx, &len)) {
 			audit_log_format(ab, " obj=(none)");
 			rc = 1;
 		} else {
@@ -1200,7 +1200,7 @@ static void show_special(struct audit_context *context, int *call_panic)
 		if (osid) {
 			char *ctx = NULL;
 			u32 len;
-			if (security_secid_to_secctx(osid, &ctx, &len)) {
+			if (security_secid_to_secctx(NULL, osid, &ctx, &len)) {
 				audit_log_format(ab, " osid=%u", osid);
 				*call_panic = 1;
 			} else {
kernel/cred.c +1 -1
index fa2061ee4955..f6b067259b6d 100644
@@ -671,7 +671,7 @@ int set_security_override_from_ctx(struct cred *new, const char *secctx)
 	u32 secid;
 	int ret;
 
-	ret = security_secctx_to_secid(secctx, strlen(secctx), &secid);
+	ret = security_secctx_to_secid(NULL, secctx, strlen(secctx), &secid);
 	if (ret < 0)
 		return ret;
 
net/core/sock.c +4 -0
index 9b7b6bbb2a23..f585833fe52d 100644
@@ -849,6 +849,10 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
 			clear_bit(SOCK_PASSCRED, &sock->flags);
 		break;
 
+	case SO_LSMSEC:
+		ret = security_socket_passed_lsm(sock, optval, optlen);
+		break;
+
 	case SO_TIMESTAMP:
 	case SO_TIMESTAMPNS:
 		if (valbool)  {
net/ipv4/ip_sockglue.c +5 -3
index a599aa83fdad..b8d6c519592f 100644
@@ -125,7 +125,8 @@ static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
 	put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum);
 }
 
-static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
+static void ip_cmsg_recv_security(const struct sock *sk, struct msghdr *msg,
+				  struct sk_buff *skb)
 {
 	char *secdata;
 	u32 seclen, secid;
@@ -135,7 +136,8 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
 	if (err)
 		return;
 
-	err = security_secid_to_secctx(secid, &secdata, &seclen);
+	err = security_secid_to_secctx(security_socket_lsm(sk),
+					secid, &secdata, &seclen);
 	if (err)
 		return;
 
@@ -213,7 +215,7 @@ void ip_cmsg_recv_offset(struct msghdr *msg, struct sock *sk,
 	}
 
 	if (flags & IP_CMSG_PASSSEC) {
-		ip_cmsg_recv_security(msg, skb);
+		ip_cmsg_recv_security(sk, msg, skb);
 
 		flags &= ~IP_CMSG_PASSSEC;
 		if (!flags)
net/netfilter/nf_conntrack_netlink.c +7 -2
index de4053d84364..c758f4b1f9c3 100644
@@ -316,7 +316,12 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
 	int len, ret;
 	char *secctx;
 
-	ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
+	if (skb && skb->sk)
+		ret = security_secid_to_secctx(security_socket_lsm(skb->sk),
+					ct->secmark, &secctx, &len);
+	else
+		ret = security_secid_to_secctx(NULL, ct->secmark, &secctx,
+						&len);
 	if (ret)
 		return 0;
 
@@ -564,7 +569,7 @@ static inline int ctnetlink_secctx_size(const struct nf_conn *ct)
 #ifdef CONFIG_NF_CONNTRACK_SECMARK
 	int len, ret;
 
-	ret = security_secid_to_secctx(ct->secmark, NULL, &len);
+	ret = security_secid_to_secctx(NULL, ct->secmark, NULL, &len);
 	if (ret)
 		return 0;
 
net/netfilter/nf_conntrack_standalone.c +1 -1
index 5a101caa3e12..b1760cb790ee 100644
@@ -182,7 +182,7 @@ static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
 	u32 len;
 	char *secctx;
 
-	ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
+	ret = security_secid_to_secctx(NULL, ct->secmark, &secctx, &len);
 	if (ret)
 		return;
 
net/netfilter/nfnetlink_queue.c +2 -1
index c9796629858f..8687a11dd0d7 100644
@@ -292,7 +292,8 @@ static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, char **secdata)
 	read_lock_bh(&skb->sk->sk_callback_lock);
 
 	if (skb->secmark)
-		security_secid_to_secctx(skb->secmark, secdata, &seclen);
+		security_secid_to_secctx(security_socket_lsm(skb->sk),
+						skb->secmark, secdata, &seclen);
 
 	read_unlock_bh(&skb->sk->sk_callback_lock);
 #endif
net/netfilter/xt_SECMARK.c +1 -1
index 9faf5e050b79..d2e1bf037111 100644
@@ -56,7 +56,7 @@ static int checkentry_lsm(struct xt_secmark_target_info *info)
 	info->secctx[SECMARK_SECCTX_MAX - 1] = '\0';
 	info->secid = 0;
 
-	err = security_secctx_to_secid(info->secctx, strlen(info->secctx),
+	err = security_secctx_to_secid(NULL, info->secctx, strlen(info->secctx),
 				       &info->secid);
 	if (err) {
 		if (err == -EINVAL)
net/netlabel/netlabel_unlabeled.c +6 -6
index 22dc1b9d6362..93a526d028c1 100644
@@ -451,7 +451,7 @@ int netlbl_unlhsh_add(struct net *net,
 unlhsh_add_return:
 	rcu_read_unlock();
 	if (audit_buf != NULL) {
-		if (security_secid_to_secctx(secid,
+		if (security_secid_to_secctx(NULL, secid,
 					     &secctx,
 					     &secctx_len) == 0) {
 			audit_log_format(audit_buf, " sec_obj=%s", secctx);
@@ -508,7 +508,7 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
 		if (dev != NULL)
 			dev_put(dev);
 		if (entry != NULL &&
-		    security_secid_to_secctx(entry->secid,
+		    security_secid_to_secctx(NULL, entry->secid,
 					     &secctx, &secctx_len) == 0) {
 			audit_log_format(audit_buf, " sec_obj=%s", secctx);
 			security_release_secctx(secctx, secctx_len);
@@ -569,7 +569,7 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
 		if (dev != NULL)
 			dev_put(dev);
 		if (entry != NULL &&
-		    security_secid_to_secctx(entry->secid,
+		    security_secid_to_secctx(NULL, entry->secid,
 					     &secctx, &secctx_len) == 0) {
 			audit_log_format(audit_buf, " sec_obj=%s", secctx);
 			security_release_secctx(secctx, secctx_len);
@@ -915,7 +915,7 @@ static int netlbl_unlabel_staticadd(struct sk_buff *skb,
 	if (ret_val != 0)
 		return ret_val;
 	dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);
-	ret_val = security_secctx_to_secid(
+	ret_val = security_secctx_to_secid(NULL,
 		                  nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
 				  nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
 				  &secid);
@@ -964,7 +964,7 @@ static int netlbl_unlabel_staticadddef(struct sk_buff *skb,
 	ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
 	if (ret_val != 0)
 		return ret_val;
-	ret_val = security_secctx_to_secid(
+	ret_val = security_secctx_to_secid(NULL,
 		                  nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
 				  nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
 				  &secid);
@@ -1141,7 +1141,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
 		secid = addr6->secid;
 	}
 
-	ret_val = security_secid_to_secctx(secid, &secctx, &secctx_len);
+	ret_val = security_secid_to_secctx(NULL, secid, &secctx, &secctx_len);
 	if (ret_val != 0)
 		goto list_cb_failure;
 	ret_val = nla_put(cb_arg->skb,
net/netlabel/netlabel_user.c +1 -1
index 58495f44c62a..45c9b3a192fd 100644
@@ -113,7 +113,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
 			 audit_info->sessionid);
 
 	if (audit_info->secid != 0 &&
-	    security_secid_to_secctx(audit_info->secid,
+	    security_secid_to_secctx(NULL, audit_info->secid,
 				     &secctx,
 				     &secctx_len) == 0) {
 		audit_log_format(audit_buf, " subj=%s", secctx);
security/Kconfig +11 -41

71 lines not on this page · raw message

security/security.c +333 -45

532 lines not on this page · raw message

security/selinux/hooks.c +4 -0
index 395fbfa7bfac..544fa3041592 100644
@@ -5928,10 +5928,12 @@ static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
 	return security_context_to_sid(secdata, seclen, secid, GFP_KERNEL);
 }
 
+#ifndef CONFIG_SECURITY_STACKING
 static void selinux_release_secctx(char *secdata, u32 seclen)
 {
 	kfree(secdata);
 }
+#endif
 
 static void selinux_inode_invalidate_secctx(struct inode *inode)
 {
@@ -6230,7 +6232,9 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 	LSM_HOOK_INIT(ismaclabel, selinux_ismaclabel),
 	LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
 	LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid),
+#ifndef CONFIG_SECURITY_STACKING
 	LSM_HOOK_INIT(release_secctx, selinux_release_secctx),
+#endif
 	LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx),
 	LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx),
 	LSM_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx),
security/smack/smack_lsm.c +16 -2
index 9fb9148cf4b5..d53ff04c49e1 100644
@@ -1421,7 +1421,10 @@ static int smack_inode_getsecurity(struct inode *inode,
 	if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
 		isp = smk_of_inode(inode);
 		ilen = strlen(isp->smk_known);
-		*buffer = isp->smk_known;
+		if (alloc)
+			*buffer = kstrdup(isp->smk_known, GFP_KERNEL);
+		else
+			*buffer = isp->smk_known;
 		return ilen;
 	}
 
@@ -1447,7 +1450,10 @@ static int smack_inode_getsecurity(struct inode *inode,
 
 	ilen = strlen(isp->smk_known);
 	if (rc == 0) {
-		*buffer = isp->smk_known;
+		if (alloc)
+			*buffer = kstrdup(isp->smk_known, GFP_KERNEL);
+		else
+			*buffer = isp->smk_known;
 		rc = ilen;
 	}
 
@@ -4361,8 +4367,16 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 {
 	struct smack_known *skp = smack_from_secid(secid);
 
+#ifdef CONFIG_SECURITY_STACKING
+	if (secdata) {
+		*secdata = kstrdup(skp->smk_known, GFP_KERNEL);
+		if (*secdata == NULL)
+			return -ENOMEM;
+	}
+#else
 	if (secdata)
 		*secdata = skp->smk_known;
+#endif
 	*seclen = strlen(skp->smk_known);
 	return 0;
 }

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#22 lore raw

cover LSM: Stacking for major security modules - Based on 4.14-rc2

In reply to Casey Schaufler
Quoted 1 line · Casey Schaufler

Subject: [PATCH 0/9] LSM: Stacking for major security modules - Based on 4.14-rc2

Would any distros expect to enable this?

Signature · 7 lines
James Morris
<[email protected]>

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
author maintainer
#23 lore raw

cover LSM: Stacking for major security modules - Based on 4.14-rc2

Check out Ubuntu 17.10

Quoted 5 lines · James Morris
Quoted 1 line · Casey Schaufler

Subject: [PATCH 0/9] LSM: Stacking for major security modules - Based on 4.14-rc2

Would any distros expect to enable this?

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

maintainer
#24 lore raw

cover LSM: Stacking for major security modules - Based on 4.14-rc2

In reply to James Morris
Quoted 6 lines · James Morris
Quoted 1 line · Casey Schaufler

Subject: [PATCH 0/9] LSM: Stacking for major security modules - Based on 4.14-rc2

Would any distros expect to enable this?

yes, its enabled as experiment in 17.10 with the goal of having truly enabled for the 18.04 LTS release --
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

maintainer
#25 lore raw

cover LSM: Stacking for major security modules - Based on 4.14-rc2

In reply to Casey Schaufler
Quoted 3 lines · Casey Schaufler

Subject: [PATCH 0/9] LSM: Stacking for major security modules - Based on 4.14-rc2

This patch set implements stacking for "major" security modules.

...

Quoted 5 lines

I have tested these patches in various configurations of Ubuntu and Fedora. Smack and SELinux together pass test suites with some exceptions. There are conflicts with the way the modules treat network configurations. These conflicts are under investigation, and changes to Smack (and possibly SELinux) to reconcile the worst of the issues are in development.

This remains my big concern, especially the network support. We've talked about this a lot in person, but until I see the code which deals with this I can't ack/nack this patchset.

Signature · 6 lines
paul moore
www.paul-moore.com
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
author maintainer
#26 lore raw

cover LSM: Stacking for major security modules - Based on 4.14-rc2

Quoted 6 lines · Paul Moore
Quoted 3 lines · Casey Schaufler

Subject: [PATCH 0/9] LSM: Stacking for major security modules - Based on 4.14-rc2

This patch set implements stacking for "major" security modules.

..

Quoted 8 lines
Quoted 5 lines

I have tested these patches in various configurations of Ubuntu and Fedora. Smack and SELinux together pass test suites with some exceptions. There are conflicts with the way the modules treat network configurations. These conflicts are under investigation, and changes to Smack (and possibly SELinux) to reconcile the worst of the issues are in development.

This remains my big concern, especially the network support. We've talked about this a lot in person, but until I see the code which deals with this I can't ack/nack this patchset.

That's well understood, and appreciated.

The LSM infrastructure is based on the system (e.g. vfs) code making calls to hooks when it is time to make a check. The netlabel system is based on the LSM making a call when it has information to present. The former makes coordination of multiple security modules relatively straight forward. The later requires holding on to data until such time as the end networking code needs it. Even if all the security modules made netlabel calls from exactly the same hooks (they don't) there's still no place to pull everything together. The solutions used to address the security_blah interfaces don't work with the networking implementation.

I'm on what I think is about my 5th approach to the netlabel problem. I have discovered all sorts of nasty little issues, some of which are artifacts of the IP stack, and some of which are the result of more general memory and object management.

I would be delighted if someone where inclined to point out an elegant way to approach the problem. Lacking that, I'll just keep plugging away with my 12 pound hammer and rusty crowbar.

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html