All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC][PATCH] selinux: Introduce a policy capability and permission for NNP transitions
@ 2017-07-10 20:25 Stephen Smalley
  2017-07-11 19:52 ` Stephen Smalley
  2017-07-11 21:00 ` Paul Moore
  0 siblings, 2 replies; 32+ messages in thread
From: Stephen Smalley @ 2017-07-10 20:25 UTC (permalink / raw)
  To: selinux; +Cc: paul, Stephen Smalley

As systemd ramps up enabling NoNewPrivileges (either explicitly in
service unit files or as a side effect of other security-related
settings in service unit files), we're increasingly running afoul of
its interactions with SELinux.

The end result is bad for the security of both SELinux-disabled and
SELinux-enabled systems.  Packagers have to turn off these
options in the unit files to preserve SELinux domain transitions.  For
users who choose to disable SELinux, this means that they miss out on
at least having the systemd-supported protections.  For users who keep
SELinux enabled, they may still be missing out on some protections
because it isn't necessarily guaranteed that the SELinux policy for
that service provides the same protections in all cases.

Our options seem to be:

1) Just keep on the way we are now, i.e. packagers have to remove
default protection settings from upstream package unit files in order
to have them work with SELinux (and not just NoNewPrivileges=
itself; increasingly systemd is enabling NNP as a side effect of other
unit file options, even seemingly unrelated ones like PrivateDevices).
SELinux-disabled users lose entirely, SELinux-enabled users may lose
(depending on whether SELinux policy provides equivalent or
better guarantees).

2) Change systemd to automatically disable NNP on SELinux-enabled
systems.  Unit files can be left unmodified from upstream.  SELinux-
disabled users win.  SELinux-enabled users may lose.

3) Try to use typebounds, since we allow bounded transitions under NNP.
Unit files can be left unmodified from upstream. SELinux-disabled users
win.  SELinux-enabled users get to benefit from systemd-provided
protections.  However, this option is impractical to implement in policy
currently, since typebounds requires us to ensure that each domain is
allowed everything all of its descendant domains are allowed, and this
has to be repeated for the entire chain of domain transitions.  There is
no way to clone all allow rules from children to the parent in policy
currently, and it is doubtful that doing so would be desirable even if
it were practical, as it requires leaking permissions to objects and
operations into parent domains that could weaken their own security in
order to allow them to the children (e.g. if a child requires execmem
permission, then so does the parent; if a child requires read to a symbolic
link or temporary file that it can write, then so does the parent, ...).

4) Decouple NNP from SELinux transitions, so that we don't have to
make a choice between them. Introduce a new policy capability that
causes the ability to transition under NNP to be based on a new permission
check between the old and new contexts rather than typebounds.  Domain
transitions can then be allowed in policy without requiring the parent
to be a strict superset of all of its children.  The rationale for this
divergence from NNP behavior for capabilities is that SELinux permissions
are substantially broader than just capabilities (they express a full
access matrix, not just privileges) and can only be used to further
restrict capabilities, not grant them beyond what is already permitted.
Unit files can be left unmodified from upstream.  SELinux-disabled users
win.  SELinux-enabled users can benefit from systemd-provided protections
and policy won't need to radically change.

This change takes the last approach above, as it seems to be the
best option.

Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
---
 security/selinux/hooks.c            | 41 ++++++++++++++++++++++++-------------
 security/selinux/include/classmap.h |  2 +-
 security/selinux/include/security.h |  2 ++
 security/selinux/ss/services.c      |  7 ++++++-
 4 files changed, 36 insertions(+), 16 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3a06afb..f0c11c2 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2326,24 +2326,37 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
 		return 0; /* No change in credentials */
 
 	/*
-	 * The only transitions we permit under NNP or nosuid
-	 * are transitions to bounded SIDs, i.e. SIDs that are
-	 * guaranteed to only be allowed a subset of the permissions
-	 * of the current SID.
+	 * If the policy enables the nnp_transition policy capability,
+	 * then we permit transitions under NNP or nosuid if the
+	 * policy explicitly allows nnp_transition permission between
+	 * the old and new contexts.
 	 */
-	rc = security_bounded_transition(old_tsec->sid, new_tsec->sid);
-	if (rc) {
+	if (selinux_policycap_nnptransition) {
+		rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
+				  SECCLASS_PROCESS,
+				  PROCESS__NNP_TRANSITION, NULL);
+		if (!rc)
+			return 0;
+	} else {
 		/*
-		 * On failure, preserve the errno values for NNP vs nosuid.
-		 * NNP:  Operation not permitted for caller.
-		 * nosuid:  Permission denied to file.
+		 * Otherwise, the only transitions we permit under NNP or nosuid
+		 * are transitions to bounded SIDs, i.e. SIDs that are
+		 * guaranteed to only be allowed a subset of the permissions
+		 * of the current SID.
 		 */
-		if (nnp)
-			return -EPERM;
-		else
-			return -EACCES;
+		rc = security_bounded_transition(old_tsec->sid, new_tsec->sid);
+		if (!rc)
+			return 0;
 	}
-	return 0;
+
+	/*
+	 * On failure, preserve the errno values for NNP vs nosuid.
+	 * NNP:  Operation not permitted for caller.
+	 * nosuid:  Permission denied to file.
+	 */
+	if (nnp)
+		return -EPERM;
+	return -EACCES;
 }
 
 static int selinux_bprm_set_creds(struct linux_binprm *bprm)
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index b9fe343..7fde56d 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -47,7 +47,7 @@ struct security_class_mapping secclass_map[] = {
 	    "getattr", "setexec", "setfscreate", "noatsecure", "siginh",
 	    "setrlimit", "rlimitinh", "dyntransition", "setcurrent",
 	    "execmem", "execstack", "execheap", "setkeycreate",
-	    "setsockcreate", "getrlimit", NULL } },
+	    "setsockcreate", "getrlimit", "nnp_transition", NULL } },
 	{ "system",
 	  { "ipc_info", "syslog_read", "syslog_mod",
 	    "syslog_console", "module_request", "module_load", NULL } },
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index e91f08c..88efb1b 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -73,6 +73,7 @@ enum {
 	POLICYDB_CAPABILITY_EXTSOCKCLASS,
 	POLICYDB_CAPABILITY_ALWAYSNETWORK,
 	POLICYDB_CAPABILITY_CGROUPSECLABEL,
+	POLICYDB_CAPABILITY_NNPTRANSITION,
 	__POLICYDB_CAPABILITY_MAX
 };
 #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
@@ -84,6 +85,7 @@ extern int selinux_policycap_openperm;
 extern int selinux_policycap_extsockclass;
 extern int selinux_policycap_alwaysnetwork;
 extern int selinux_policycap_cgroupseclabel;
+extern int selinux_policycap_nnptransition;
 
 /*
  * type_datum properties
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 2f02fa6..2faf47a 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -76,7 +76,8 @@ char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
 	"open_perms",
 	"extended_socket_class",
 	"always_check_network",
-	"cgroup_seclabel"
+	"cgroup_seclabel",
+	"nnp_transition"
 };
 
 int selinux_policycap_netpeer;
@@ -84,6 +85,7 @@ int selinux_policycap_openperm;
 int selinux_policycap_extsockclass;
 int selinux_policycap_alwaysnetwork;
 int selinux_policycap_cgroupseclabel;
+int selinux_policycap_nnptransition;
 
 static DEFINE_RWLOCK(policy_rwlock);
 
@@ -2009,6 +2011,9 @@ static void security_load_policycaps(void)
 	selinux_policycap_cgroupseclabel =
 		ebitmap_get_bit(&policydb.policycaps,
 				POLICYDB_CAPABILITY_CGROUPSECLABEL);
+	selinux_policycap_nnptransition =
+		ebitmap_get_bit(&policydb.policycaps,
+				POLICYDB_CAPABILITY_NNPTRANSITION);
 
 	for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
 		pr_info("SELinux:  policy capability %s=%d\n",
-- 
2.9.4

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

end of thread, other threads:[~2017-07-14  6:43 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-10 20:25 [RFC][PATCH] selinux: Introduce a policy capability and permission for NNP transitions Stephen Smalley
2017-07-11 19:52 ` Stephen Smalley
2017-07-11 20:05   ` Dominick Grift
2017-07-11 20:10     ` Dominick Grift
2017-07-11 20:23       ` Stephen Smalley
2017-07-11 20:44         ` Dominick Grift
2017-07-12 13:01           ` Stephen Smalley
2017-07-12 13:30             ` Dominick Grift
2017-07-12 13:38               ` Dominick Grift
2017-07-12 13:42                 ` Dominick Grift
2017-07-12 13:52                   ` Stephen Smalley
2017-07-12 13:51                 ` Stephen Smalley
2017-07-11 21:00 ` Paul Moore
2017-07-12 13:26   ` Stephen Smalley
2017-07-12 21:38     ` Paul Moore
2017-07-13  0:27       ` Chris PeBenito
2017-07-13 12:44         ` Stephen Smalley
2017-07-13 13:25           ` Paul Moore
2017-07-13 15:48             ` Stephen Smalley
2017-07-13 15:59               ` Stephen Smalley
2017-07-13 16:55                 ` Dominick Grift
2017-07-13 18:13                   ` Stephen Smalley
2017-07-13 18:16                     ` Dominick Grift
2017-07-13 18:50                       ` Dominick Grift
2017-07-13 19:29                       ` Stephen Smalley
2017-07-13 19:28                         ` Dominick Grift
2017-07-13 19:43                           ` Dominick Grift
2017-07-13 19:59                             ` Stephen Smalley
2017-07-13 20:11                               ` Dominick Grift
2017-07-13 23:55                                 ` Chris PeBenito
2017-07-14  6:43                                   ` Dominick Grift
2017-07-13 20:15               ` Paul Moore

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.