[RFC PATCH v1] selinux: add transitions for kernel keys

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Unfortunately, experience has shown that transitions are necessary for
keys stored in the kernel's keyring; inheriting labels from the
creating process has shown to result in keys with unpredictable labels
as the different kernel keyring users race to create new keys.  While
setkeycreatecon() does exist to allow applications to set the security
label of newly created keys, it is impractical to modify all keyring
users to use the SELinux API.  As with several other kernel resources,
a policy driven transition is the most practical solution.

This patch adds the necessary transition call and protects it via the
newly created "keytrans" policy capability.  The policy capability is
necessary to ensure compatibility with existing policies as the default
transition behavior is to inherit the target's type information which
is not the current, or desired, behavior.  For similar reasons, the
uninitialized behavior of security_compute_sid() has been updated such
that key objects inherit the subject's label.

As one might expect, this patch does require an updated userspace to
create a policy to use this new functionality.  Userspace changes
would require the addition of the new "keytrans" policy capability and
most likely a change to the way type transitions are applied to the
key object class, see below:

  default_type key source;

... this would ensure that newly created keys would inherit the type
information of the calling process in case a type transition was not
explicitly defined in policy.  This leads to the SELinux type
transition statement for the key object class, see below:

  type_transition <domain> kernel_t:key <new_key_type>

... in the case of the key object class, the target type is always the
kernel's security label, which in the case of the Reference Policy is
"kernel_t".

Signed-off-by: XXX
---
 security/selinux/hooks.c            |   21 ++++++++++++++-------
 security/selinux/include/security.h |    2 ++
 security/selinux/ss/services.c      |    4 ++++
 3 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 57b0b49..3ea05b6 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5682,18 +5682,25 @@ static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
 static int selinux_key_alloc(struct key *k, const struct cred *cred,
 			     unsigned long flags)
 {
-	const struct task_security_struct *tsec;
+	int rc;
+	const struct task_security_struct *tsec = current_security();
 	struct key_security_struct *ksec;
+	u32 sid;
+
+	if (tsec->keycreate_sid)
+		sid = tsec->keycreate_sid;
+	else if (selinux_policycap_keytrans) {
+		rc = security_transition_sid(tsec->sid, SECINITSID_KERNEL,
+					     SECCLASS_KEY, NULL, &sid);
+		if (rc)
+			return rc;
+	} else
+		sid = tsec->sid;
 
 	ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
 	if (!ksec)
 		return -ENOMEM;
-
-	tsec = cred->security;
-	if (tsec->keycreate_sid)
-		ksec->sid = tsec->keycreate_sid;
-	else
-		ksec->sid = tsec->sid;
+	ksec->sid = sid;
 
 	k->security = ksec;
 	return 0;
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index fe341ae..8460217 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -71,6 +71,7 @@ enum {
 	POLICYDB_CAPABILITY_OPENPERM,
 	POLICYDB_CAPABILITY_REDHAT1,
 	POLICYDB_CAPABILITY_ALWAYSNETWORK,
+	POLICYDB_CAPABILITY_KEYTRANS,
 	__POLICYDB_CAPABILITY_MAX
 };
 #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
@@ -78,6 +79,7 @@ enum {
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
 extern int selinux_policycap_alwaysnetwork;
+extern int selinux_policycap_keytrans;
 
 /*
  * type_datum properties
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index d106733..4f57007 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -73,6 +73,7 @@
 int selinux_policycap_netpeer;
 int selinux_policycap_openperm;
 int selinux_policycap_alwaysnetwork;
+int selinux_policycap_keytrans;
 
 static DEFINE_RWLOCK(policy_rwlock);
 
@@ -1404,6 +1405,7 @@ static int security_compute_sid(u32 ssid,
 
 	if (!ss_initialized) {
 		switch (orig_tclass) {
+		case SECCLASS_KEY:
 		case SECCLASS_PROCESS: /* kernel value */
 			*out_sid = ssid;
 			break;
@@ -1815,6 +1817,8 @@ static void security_load_policycaps(void)
 						  POLICYDB_CAPABILITY_OPENPERM);
 	selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps,
 						  POLICYDB_CAPABILITY_ALWAYSNETWORK);
+	selinux_policycap_keytrans = ebitmap_get_bit(&policydb.policycaps,
+						  POLICYDB_CAPABILITY_KEYTRANS);
 }
 
 static int security_preserve_bools(struct policydb *p);

_______________________________________________
Selinux mailing list
Selinux@xxxxxxxxxxxxx
To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx.
To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.




[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux