Re: [PATCH] selinux-testsuite: Add key and key_socket tests

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

 



On Mon, 2019-09-16 at 13:58 -0400, Stephen Smalley wrote:
> On 9/9/19 9:17 AM, Richard Haines wrote:
> > Test all permissions associated with the key and key_socket
> > classes.
> > 
> > Note that kernel 5.3 commit keys: Fix request_key() lack of Link
> > perm
> > check on found key ("504b69eb3c95180bc59f1ae9096ad4b10bbbf254")
> > added an additional check for link perm on request_key(). The tests
> > will support earlier kernels.
> 
> I'm not sure why you coupled key and key_socket together; they don't 
> have anything to do with each other, and were introduced in very 
> different kernel and probably refpolicy releases.  I would recommend 
> splitting them.  SECCLASS_KEY and its permission checks were
> introduced 
> in Linux v2.6.18; SECCLASS_KEY_SOCKET was part of the original
> SELinux 
> merge for Linux 2.6.0.

I'll split them.

> 
> You only appear to be testing self access, not permission checks
> between 
> a process and a keyring created by another process in a different 
> security context.

Okay I'll add these tests
> 
> 1 test fails for me,
> keys/test ................... Failed KEYCTL_SESSION_TO_PARENT:
> Operation 
> not permitted
> keys/test ................... 1/13
> #   Failed test at keys/test line 38.
> # Looks like you failed 1 test of 13.
> keys/test ................... Dubious, test returned 1 (wstat 256,
> 0x100)

You must have systems that don't like my patches - I can't get this
fail. Using Fedora 30 and also Rawhide from a few weeks ago.

I don't know if this is of any interest (It works on Rawhide with
kernel from [1]):

I've been building 'key' tests to add the new permissions defined in
kernel-next [1].
To test these with new policy supporting the new perms + old policy
that does not, I added the kernel test patch below.
This patch handles security_key_permission() passing a single
permission, as checking the current keys code I only see it passing a
single permission at a time.

I've also an sepol patch + selinux-testsuite tests

[1] 
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/security/selinux?h=next-20190904&id=1f96e0f129eb2bea15a00c154eee8b85aa181d1a


diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 901cc052f..9c8f90648 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6502,7 +6502,7 @@ static int selinux_key_permission(key_ref_t
key_ref,
 {
 	struct key *key;
 	struct key_security_struct *ksec;
-	unsigned oldstyle_perm;
+	unsigned int key_perm = 0;
 	u32 sid;
 
 	/* if no specific permissions are requested, we skip the
@@ -6511,18 +6511,57 @@ static int selinux_key_permission(key_ref_t
key_ref,
 	if (perm == 0)
 		return 0;
 
-	oldstyle_perm = perm & (KEY_NEED_VIEW | KEY_NEED_READ |
KEY_NEED_WRITE |
-				KEY_NEED_SEARCH | KEY_NEED_LINK);
-	if (perm & KEY_NEED_SETSEC)
-		oldstyle_perm |= OLD_KEY_NEED_SETATTR;
-	if (perm & KEY_NEED_INVAL)
-		oldstyle_perm |= KEY_NEED_SEARCH;
-	if (perm & KEY_NEED_REVOKE && !(perm & OLD_KEY_NEED_SETATTR))
-		oldstyle_perm |= KEY_NEED_WRITE;
-	if (perm & KEY_NEED_JOIN)
-		oldstyle_perm |= KEY_NEED_SEARCH;
-	if (perm & KEY_NEED_CLEAR)
-		oldstyle_perm |= KEY_NEED_WRITE;
+	/* selinux_key_permission() is called with only one permission
set. */
+	switch (perm) {
+	case KEY_NEED_VIEW:
+		key_perm = KEY__VIEW;
+		break;
+	case KEY_NEED_READ:
+		key_perm = KEY__READ;
+		break;
+	case KEY_NEED_WRITE:
+		key_perm = KEY__WRITE;
+		break;
+	case KEY_NEED_SEARCH:
+		key_perm = KEY__SEARCH;
+		break;
+	case KEY_NEED_LINK:
+		key_perm = KEY__LINK;
+		break;
+	case KEY_NEED_SETSEC: /* Keep this as "setattr" in policy */
+		key_perm = KEY__SETATTR;
+		break;
+	case KEY_NEED_INVAL:
+		key_perm = KEY__INVAL;
+		break;
+	case KEY_NEED_REVOKE:
+		key_perm = KEY__REVOKE;
+		break;
+	case KEY_NEED_JOIN:
+		key_perm = KEY__JOIN;
+		break;
+	case KEY_NEED_CLEAR:
+		key_perm = KEY__CLEAR;
+		break;
+	}
+
+	/* If old policy, then reset new perms to orig. */
+	if (!selinux_policycap_key_perms()) {
+		switch (perm) {
+		case KEY_NEED_INVAL:
+			key_perm = KEY__SEARCH;
+			break;
+		case KEY_NEED_REVOKE:
+			key_perm = KEY__WRITE;
+			break;
+		case KEY_NEED_JOIN:
+			key_perm = KEY__SEARCH;
+			break;
+		case KEY_NEED_CLEAR:
+			key_perm = KEY__WRITE;
+			break;
+		}
+	}
 
 	sid = cred_sid(cred);
 
@@ -6530,7 +6569,7 @@ static int selinux_key_permission(key_ref_t
key_ref,
 	ksec = key->security;
 
 	return avc_has_perm(&selinux_state,
-			    sid, ksec->sid, SECCLASS_KEY,
oldstyle_perm, NULL);
+			    sid, ksec->sid, SECCLASS_KEY, key_perm,
NULL);
 }
 
 static int selinux_key_getsecurity(struct key *key, char **_buffer)
@@ -6555,7 +6594,7 @@ static int selinux_watch_key(struct key *key)
 	u32 sid = current_sid();
 
 	return avc_has_perm(&selinux_state,
-			    sid, ksec->sid, SECCLASS_KEY,
KEY_NEED_VIEW, NULL);
+			    sid, ksec->sid, SECCLASS_KEY, KEY__VIEW,
NULL);
 }
 #endif
 #endif
diff --git a/security/selinux/include/classmap.h
b/security/selinux/include/classmap.h
index 201f7e588..a51ab9bd9 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -158,7 +158,7 @@ struct security_class_mapping secclass_map[] = {
 	  { "send", "recv", "relabelto", "forward_in", "forward_out",
NULL } },
 	{ "key",
 	  { "view", "read", "write", "search", "link", "setattr",
"create",
-	    NULL } },
+	    "inval", "revoke", "join", "clear", NULL } },
 	{ "dccp_socket",
 	  { COMMON_SOCK_PERMS,
 	    "node_bind", "name_connect", NULL } },
diff --git a/security/selinux/include/security.h
b/security/selinux/include/security.h
index 111121281..a248eef75 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -78,6 +78,7 @@ enum {
 	POLICYDB_CAPABILITY_ALWAYSNETWORK,
 	POLICYDB_CAPABILITY_CGROUPSECLABEL,
 	POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION,
+	POLICYDB_CAPABILITY_KEYPERMS,
 	__POLICYDB_CAPABILITY_MAX
 };
 #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
@@ -177,6 +178,13 @@ static inline bool
selinux_policycap_nnp_nosuid_transition(void)
 	return state-
>policycap[POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION];
 }
 
+static inline bool selinux_policycap_key_perms(void)
+{
+	struct selinux_state *state = &selinux_state;
+
+	return state->policycap[POLICYDB_CAPABILITY_KEYPERMS];
+}
+
 int security_mls_enabled(struct selinux_state *state);
 int security_load_policy(struct selinux_state *state,
 			 void *data, size_t len);
diff --git a/security/selinux/ss/services.c
b/security/selinux/ss/services.c
index d61563a36..eb3949fc8 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -73,7 +73,8 @@ const char
*selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
 	"extended_socket_class",
 	"always_check_network",
 	"cgroup_seclabel",
-	"nnp_nosuid_transition"
+	"nnp_nosuid_transition",
+	"key_perms"
 };
 
 static struct selinux_ss selinux_ss;



> 
> > Signed-off-by: Richard Haines <richard_c_haines@xxxxxxxxxxxxxx>
> > ---
> >   README.md                   |   3 +-
> >   defconfig                   |   8 ++
> >   policy/Makefile             |   4 +
> >   policy/test_keys.te         | 161 ++++++++++++++++++++++++
> >   tests/Makefile              |   4 +
> >   tests/keys/.gitignore       |   3 +
> >   tests/keys/Makefile         |   8 ++
> >   tests/keys/key_sock.c       |  67 ++++++++++
> >   tests/keys/keyctl.c         | 241
> > ++++++++++++++++++++++++++++++++++++
> >   tests/keys/keyctl_relabel.c |  93 ++++++++++++++
> >   tests/keys/test             |  98 +++++++++++++++
> >   11 files changed, 689 insertions(+), 1 deletion(-)
> >   create mode 100644 policy/test_keys.te
> >   create mode 100644 tests/keys/.gitignore
> >   create mode 100644 tests/keys/Makefile
> >   create mode 100644 tests/keys/key_sock.c
> >   create mode 100644 tests/keys/keyctl.c
> >   create mode 100644 tests/keys/keyctl_relabel.c
> >   create mode 100755 tests/keys/test
> > 
> > diff --git a/README.md b/README.md
> > index 26784f8..fe72a91 100644
> > --- a/README.md
> > +++ b/README.md
> > @@ -65,7 +65,8 @@ following command:
> >   		netlabel_tools \
> >   		iptables \
> >   		lksctp-tools-devel \
> > -		attr
> > +		attr \
> > +		keyutils-libs-devel
> >   
> >   The testsuite requires a pre-existing base policy configuration
> > of SELinux,
> >   using either the old example policy or the reference policy as
> > the baseline.
> > diff --git a/defconfig b/defconfig
> > index d7f0ea5..c00e291 100644
> > --- a/defconfig
> > +++ b/defconfig
> > @@ -62,3 +62,11 @@ CONFIG_ANDROID_BINDER_IPC=y
> >   # This will configure the Dynamically Allocated Binder Devices
> > added
> >   # to 5.0+ kernels:
> >   CONFIG_ANDROID_BINDERFS=y
> > +
> > +# Key implementations.
> > +# These are enabled to test the key and key_socket controls in
> > +# tests/keys; they are not required for SELinux operation itself.
> > +CONFIG_KEYS=y
> > +CONFIG_KEYS_COMPAT=y
> > +CONFIG_KEY_DH_OPERATIONS=y
> > +CONFIG_NET_KEY=m
> > diff --git a/policy/Makefile b/policy/Makefile
> > index 305b572..9258a93 100644
> > --- a/policy/Makefile
> > +++ b/policy/Makefile
> > @@ -71,6 +71,10 @@ ifeq ($(shell grep -q
> > corenet_sctp_bind_all_nodes $(POLDEV)/include/kernel/coren
> >   TARGETS += test_sctp.te
> >   endif
> >   
> > +ifeq ($(shell grep -q key_socket
> > $(POLDEV)/include/support/all_perms.spt && echo true),true)
> > +TARGETS += test_keys.te
> > +endif
> > +
> >   ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6))
> >   TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te,
> > $(TARGETS))
> >   endif
> > diff --git a/policy/test_keys.te b/policy/test_keys.te
> > new file mode 100644
> > index 0000000..9c65ec8
> > --- /dev/null
> > +++ b/policy/test_keys.te
> > @@ -0,0 +1,161 @@
> > +#
> > +################# KEY selinux-testsuite policy module
> > ######################
> > +#
> > +attribute keydomain;
> > +
> > +#
> > +############################## Define Macro
> > ################################
> > +#
> > +# Do not use domain_type() macro as it has allow 'key { link
> > search }'
> > +# in base module so 'allow domain self:key ~{ link search };' will
> > not work
> > +# here. Add these instead to allow key perms to be controlled by
> > this module:
> > +#
> > +define(`key_domain_type',`
> > +	allow $1 proc_t:dir { search };
> > +	allow $1 proc_t:lnk_file { read };
> > +	allow $1 self:dir { search };
> > +	allow $1 self:file { open read write };
> > +')
> > +
> > +#
> > +####################### Main key class tests #####################
> > +#
> > +type test_key_t;
> > +key_domain_type(test_key_t)
> > +unconfined_runs_test(test_key_t)
> > +typeattribute test_key_t testdomain;
> > +typeattribute test_key_t keydomain;
> > +
> > +allow test_key_t self:process { setkeycreate };
> > +allow test_key_t self:key { create write search read view link
> > setattr };
> > +
> > +# Set new context on a keyring:
> > +type test_newcon_key_t;
> > +key_domain_type(test_newcon_key_t)
> > +unconfined_runs_test(test_newcon_key_t)
> > +typeattribute test_newcon_key_t testdomain;
> > +typeattribute test_newcon_key_t keydomain;
> > +
> > +allow test_key_t test_newcon_key_t:key { create write search view
> > };
> > +
> > +################# Deny process { setkeycreate }
> > #######################
> > +type test_no_setkeycreate_t;
> > +key_domain_type(test_no_setkeycreate_t)
> > +unconfined_runs_test(test_no_setkeycreate_t)
> > +typeattribute test_no_setkeycreate_t testdomain;
> > +typeattribute test_no_setkeycreate_t keydomain;
> > +
> > +###################### Deny key { create }
> > ###########################
> > +type test_key_no_create_t;
> > +key_domain_type(test_key_no_create_t)
> > +unconfined_runs_test(test_key_no_create_t)
> > +typeattribute test_key_no_create_t testdomain;
> > +typeattribute test_key_no_create_t keydomain;
> > +
> > +allow test_key_no_create_t self:process { setkeycreate };
> > +allow test_key_no_create_t self:key { write search read view link
> > setattr };
> > +
> > +###################### Deny key { write }
> > ###########################
> > +type test_key_no_write_t;
> > +key_domain_type(test_key_no_write_t)
> > +unconfined_runs_test(test_key_no_write_t)
> > +typeattribute test_key_no_write_t testdomain;
> > +typeattribute test_key_no_write_t keydomain;
> > +
> > +allow test_key_no_write_t self:process { setkeycreate };
> > +allow test_key_no_write_t self:key { create search read view link
> > setattr };
> > +
> > +###################### Deny key { search }
> > ###########################
> > +type test_key_no_search_t;
> > +key_domain_type(test_key_no_search_t)
> > +unconfined_runs_test(test_key_no_search_t)
> > +typeattribute test_key_no_search_t testdomain;
> > +typeattribute test_key_no_search_t keydomain;
> > +
> > +allow test_key_no_search_t self:process { setkeycreate };
> > +allow test_key_no_search_t self:key { create write read view link
> > setattr };
> > +
> > +###################### Deny key { view }
> > ###########################
> > +type test_key_no_view_t;
> > +key_domain_type(test_key_no_view_t)
> > +unconfined_runs_test(test_key_no_view_t)
> > +typeattribute test_key_no_view_t testdomain;
> > +typeattribute test_key_no_view_t keydomain;
> > +
> > +allow test_key_no_view_t self:process { setkeycreate };
> > +allow test_key_no_view_t self:key { create write search read link
> > setattr };
> > +
> > +###################### Deny key { read }
> > ###########################
> > +type test_key_no_read_t;
> > +key_domain_type(test_key_no_read_t)
> > +unconfined_runs_test(test_key_no_read_t)
> > +typeattribute test_key_no_read_t testdomain;
> > +typeattribute test_key_no_read_t keydomain;
> > +
> > +allow test_key_no_read_t self:process { setkeycreate };
> > +allow test_key_no_read_t self:key { create write search view link
> > setattr };
> > +
> > +###################### Deny key { link }
> > ###########################
> > +type test_key_no_link_t;
> > +key_domain_type(test_key_no_link_t)
> > +unconfined_runs_test(test_key_no_link_t)
> > +typeattribute test_key_no_link_t testdomain;
> > +typeattribute test_key_no_link_t keydomain;
> > +
> > +allow test_key_no_link_t self:process { setkeycreate };
> > +allow test_key_no_link_t self:key { create write search read view
> > setattr };
> > +
> > +###################### Deny key { setattr }
> > ###########################
> > +type test_key_no_setattr_t;
> > +key_domain_type(test_key_no_setattr_t)
> > +unconfined_runs_test(test_key_no_setattr_t)
> > +typeattribute test_key_no_setattr_t testdomain;
> > +typeattribute test_key_no_setattr_t keydomain;
> > +
> > +allow test_key_no_setattr_t self:process { setkeycreate };
> > +allow test_key_no_setattr_t self:key { create write search read
> > view link };
> > +
> > +#
> > +######################## Test key_socket class
> > ###########################
> > +#
> > +type test_key_sock_t;
> > +domain_type(test_key_sock_t)
> > +unconfined_runs_test(test_key_sock_t)
> > +typeattribute test_key_sock_t testdomain;
> > +typeattribute test_key_sock_t keydomain;
> > +
> > +# key_socket rules:
> > +allow test_key_sock_t self:rawip_socket { create };
> > +allow test_key_sock_t self:capability { net_admin };
> > +allow test_key_sock_t self:key_socket { create write };
> > +# For CONFIG_NET_KEY=m
> > +allow test_key_sock_t kernel_t:system { module_request };
> > +
> > +################## Deny capability { net_admin }
> > ##########################
> > +type test_key_sock_no_net_admin_t;
> > +domain_type(test_key_sock_no_net_admin_t)
> > +unconfined_runs_test(test_key_sock_no_net_admin_t)
> > +typeattribute test_key_sock_no_net_admin_t testdomain;
> > +typeattribute test_key_sock_no_net_admin_t keydomain;
> > +
> > +# key_socket rules:
> > +allow test_key_sock_no_net_admin_t self:rawip_socket { create };
> > +allow test_key_sock_no_net_admin_t self:key_socket { create write
> > };
> > +
> > +####################### Deny key_socket { create }
> > ##########################
> > +type test_key_sock_no_create_t;
> > +domain_type(test_key_sock_no_create_t)
> > +unconfined_runs_test(test_key_sock_no_create_t)
> > +typeattribute test_key_sock_no_create_t testdomain;
> > +typeattribute test_key_sock_no_create_t keydomain;
> > +
> > +# key_socket rules:
> > +allow test_key_sock_no_create_t self:rawip_socket { create };
> > +allow test_key_sock_no_create_t self:capability { net_admin };
> > +allow test_key_sock_no_create_t self:key_socket { write };
> > +
> > +#
> > +########### Allow these domains to be entered from sysadm domain
> > ############
> > +#
> > +miscfiles_domain_entry_test_files(keydomain)
> > +userdom_sysadm_entry_spec_domtrans_to(keydomain)
> > diff --git a/tests/Makefile b/tests/Makefile
> > index 63aa325..d1dbf38 100644
> > --- a/tests/Makefile
> > +++ b/tests/Makefile
> > @@ -42,6 +42,10 @@ ifeq ($(shell grep -q binder
> > $(POLDEV)/include/support/all_perms.spt && test -e
> >   SUBDIRS += binder
> >   endif
> >   
> > +ifeq ($(shell grep -q key_socket
> > $(POLDEV)/include/support/all_perms.spt && test -e
> > $(INCLUDEDIR)/keyutils.h && echo true),true)
> > +SUBDIRS += keys
> > +endif
> > +
> >   ifeq ($(shell grep "^SELINUX_INFINIBAND_ENDPORT_TEST="
> > infiniband_endport/ibendport_test.conf | cut -d'=' -f 2),1)
> >   SUBDIRS += infiniband_endport
> >   endif
> > diff --git a/tests/keys/.gitignore b/tests/keys/.gitignore
> > new file mode 100644
> > index 0000000..4a0a48d
> > --- /dev/null
> > +++ b/tests/keys/.gitignore
> > @@ -0,0 +1,3 @@
> > +keyctl
> > +keyctl_relabel
> > +key_sock
> > diff --git a/tests/keys/Makefile b/tests/keys/Makefile
> > new file mode 100644
> > index 0000000..3a00df5
> > --- /dev/null
> > +++ b/tests/keys/Makefile
> > @@ -0,0 +1,8 @@
> > +TARGETS = keyctl key_sock keyctl_relabel
> > +
> > +LDLIBS += -lselinux -lkeyutils
> > +
> > +all: $(TARGETS)
> > +
> > +clean:
> > +	rm -f $(TARGETS)
> > diff --git a/tests/keys/key_sock.c b/tests/keys/key_sock.c
> > new file mode 100644
> > index 0000000..8ac1f45
> > --- /dev/null
> > +++ b/tests/keys/key_sock.c
> > @@ -0,0 +1,67 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <stdbool.h>
> > +#include <sys/socket.h>
> > +#include <linux/pfkeyv2.h>
> > +#include <selinux/selinux.h>
> > +
> > +static void usage(char *progname)
> > +{
> > +	fprintf(stderr,
> > +		"usage:  %s [-v]\n"
> > +		"Where:\n\t"
> > +		"-v  Print information.\n", progname);
> > +	exit(-1);
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +	char *context;
> > +	int opt, sock, result;
> > +	bool verbose = false;
> > +
> > +	while ((opt = getopt(argc, argv, "v")) != -1) {
> > +		switch (opt) {
> > +		case 'v':
> > +			verbose = true;
> > +			break;
> > +		default:
> > +			usage(argv[0]);
> > +		}
> > +	}
> > +
> > +	result = getcon(&context);
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed to obtain process context\n");
> > +		exit(-1);
> > +	}
> > +	if (verbose)
> > +		printf("Process context: %s\n", context);
> > +
> > +	sock = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
> > +	if (sock < 0) {
> > +		fprintf(stderr, "Failed to open PF_KEY socket: %s\n",
> > +			strerror(errno));
> > +		exit(errno);
> > +	}
> > +	if (verbose)
> > +		printf("Opened PF_KEY socket\n");
> > +
> > +	/* Write nothing to socket for test, expect EMSGSIZE error */
> > +	result = write(sock, NULL, 0);
> > +	if (result < 0 && errno == EMSGSIZE) {
> > +		result = 0;
> > +		if (verbose)
> > +			printf("Written to PF_KEY socket\n");
> > +	} else if (result < 0 && errno != EMSGSIZE) {
> > +		result = -1;
> > +		fprintf(stderr, "Failed write to PF_KEY socket: %s\n",
> > +			strerror(errno));
> > +	}
> > +
> > +	close(sock);
> > +	return result;
> > +}
> > diff --git a/tests/keys/keyctl.c b/tests/keys/keyctl.c
> > new file mode 100644
> > index 0000000..6d85be7
> > --- /dev/null
> > +++ b/tests/keys/keyctl.c
> > @@ -0,0 +1,241 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <stdbool.h>
> > +#include <keyutils.h>
> > +#include <selinux/selinux.h>
> > +
> > +/* This is used as the payload for each add_key() */
> > +static const char payload[] =
> > +	" -----BEGIN PUBLIC KEY-----
> > \nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDN4FHsPjlJf03r9KfNt1Ma9/D6\
> > nQDEiR/cfhZrNUPgHRrC+E4dj52VJSonPFJ6HaLlUi5pZq2t1LqPNrMfFKCNn12m+\n
> > Ww4aduBJM7u1RUPSNxrlfDAJZkdtNALOO/ds3U93hZrxOYNetzbnjILDu5JT1nbI\n4
> > aC60SkdlCw1TxmvXwIDAQAB\n-----END PUBLIC KEY-----\n";
> > +
> > +static void usage(char *progname)
> > +{
> > +	fprintf(stderr,
> > +		"usage:  %s [-v]\n"
> > +		"Where:\n\t"
> > +		"-v  Print information.\n", progname);
> > +	exit(-1);
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +	int opt, result;
> > +	char *context, *keycreate_con;
> > +	char r_con[256];
> > +	bool verbose = false;
> > +	key_serial_t retrieved, search, link, compute, newring,
> > +		     private, prime, base, test_key;
> > +	struct keyctl_dh_params params;
> > +
> > +	while ((opt = getopt(argc, argv, "v")) != -1) {
> > +		switch (opt) {
> > +		case 'v':
> > +			verbose = true;
> > +			break;
> > +		default:
> > +			usage(argv[0]);
> > +		}
> > +	}
> > +
> > +	result = getcon(&context);
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed to obtain process context\n");
> > +		exit(1);
> > +	}
> > +	if (verbose)
> > +		printf("Process context: %s\n", context);
> > +
> > +	result = getkeycreatecon(&keycreate_con);
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed to obtain keycreate
> > context\n");
> > +		exit(2);
> > +	}
> > +	if (verbose)
> > +		printf("Current keycreate context: %s\n",
> > keycreate_con);
> > +	free(keycreate_con);
> > +
> > +	/* Set context requires process { setkeycreate } and key {
> > create } */
> > +	result = setkeycreatecon(context);
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed setkeycreatecon(): %s\n",
> > +			strerror(errno));
> > +		exit(3);
> > +	}
> > +	if (verbose)
> > +		printf("Set keycreate context: %s\n", context);
> > +	free(context);
> > +
> > +	result = getkeycreatecon(&keycreate_con);
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed to obtain keycreate
> > context\n");
> > +		exit(4);
> > +	}
> > +	if (verbose)
> > +		printf("New keycreate context: %s\n", keycreate_con);
> > +	free(keycreate_con);
> > +
> > +	/*
> > +	 * Add three keys as these will be required by the
> > +	 * keyctl(KEYCTL_DH_COMPUTE, ..) function.
> > +	 * These require key { create write } permissions.
> > +	 */
> > +	private = add_key("user", "private", payload, strlen(payload),
> > +			  KEY_SPEC_PROCESS_KEYRING);
> > +	if (private < 0) {
> > +		fprintf(stderr, "Failed add_key(private): %s\n",
> > +			strerror(errno));
> > +		exit(5);
> > +	}
> > +
> > +	prime = add_key("user", "prime", payload, strlen(payload),
> > +			KEY_SPEC_PROCESS_KEYRING);
> > +	if (prime < 0) {
> > +		fprintf(stderr, "Failed add_key(prime): %s\n",
> > +			strerror(errno));
> > +		exit(6);
> > +	}
> > +
> > +	base = add_key("user", "base", payload, strlen(payload),
> > +		       KEY_SPEC_PROCESS_KEYRING);
> > +	if (base < 0) {
> > +		fprintf(stderr, "Failed add_key(base): %s\n",
> > +			strerror(errno));
> > +		exit(7);
> > +	}
> > +
> > +	if (verbose) {
> > +		printf("Private key ID: 0x%x\n", private);
> > +		printf("Prime key ID:   0x%x\n", prime);
> > +		printf("Base key ID:    0x%x\n", base);
> > +	}
> > +
> > +	/* Requires key { search }. From kernel 5.3 also requires {
> > link } */
> > +	retrieved = request_key("user", "private", NULL,
> > +				KEY_SPEC_PROCESS_KEYRING);
> > +	if (retrieved < 0) {
> > +		fprintf(stderr, "Failed to request 'private' key:
> > %s\n",
> > +			strerror(errno));
> > +		exit(8);
> > +	}
> > +
> > +	/* Requires key { search } */
> > +	search = keyctl(KEYCTL_SEARCH, KEY_SPEC_PROCESS_KEYRING,
> > "user",
> > +			"base", 0);
> > +	if (search < 0) {
> > +		fprintf(stderr, "Failed to find 'base' key: %s\n",
> > +			strerror(errno));
> > +		exit(9);
> > +	}
> > +
> > +	/* Requires key { view } */
> > +	result = keyctl(KEYCTL_GET_SECURITY, search, r_con,
> > sizeof(r_con));
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed to obtain key context: %s\n",
> > +			strerror(errno));
> > +		exit(10);
> > +	}
> > +
> > +	if (verbose) {
> > +		printf("Requested 'private' key ID: 0x%x\n",
> > retrieved);
> > +		printf("Searched 'base' key ID:     0x%x\n", search);
> > +		printf("Searched 'base' key context:\n\t%s\n", r_con);
> > +	}
> > +
> > +	/* Compute DH key, only obtain the length for test, not the
> > key. */
> > +	params.priv = private;
> > +	params.prime = prime;
> > +	params.base = base;
> > +
> > +	/* Requires key { create read write } */
> > +	compute = keyctl(KEYCTL_DH_COMPUTE, &params, NULL, 0, 0);
> > +	if (compute < 0) {
> > +		fprintf(stderr, "Failed KEYCTL_DH_COMPUTE: %s\n",
> > +			strerror(errno));
> > +		exit(11);
> > +	}
> > +	if (verbose)
> > +		printf("KEYCTL_DH_COMPUTE key ID size: %d\n", compute);
> > +
> > +	/* To test key { link }, need to generate a new keyring ID
> > first */
> > +	newring = add_key("keyring", "my-keyring", NULL, 0,
> > +			  KEY_SPEC_THREAD_KEYRING);
> > +	if (newring < 0) {
> > +		fprintf(stderr, "Failed to add new keyring: %s\n",
> > +			strerror(errno));
> > +		exit(12);
> > +	}
> > +	if (verbose)
> > +		printf("New keyring ID: 0x%x\n", newring);
> > +
> > +	/* Requires key { write link } */
> > +	link = keyctl(KEYCTL_LINK, base, newring);
> > +	if (link < 0) {
> > +		fprintf(stderr, "Failed KEYCTL_LINK: %s\n",
> > +			strerror(errno));
> > +		exit(13);
> > +	}
> > +	if (verbose)
> > +		printf("Link key ID:    0x%x\n", newring);
> > +
> > +	/* Requires key { setattr } */
> > +	link = keyctl(KEYCTL_RESTRICT_KEYRING, newring, NULL, NULL);
> > +	if (link < 0) {
> > +		fprintf(stderr, "Failed KEYCTL_RESTRICT_KEYRING: %s\n",
> > +			strerror(errno));
> > +		exit(14);
> > +	}
> > +	if (verbose)
> > +		printf("Restricted keyring\n");
> > +
> > +	/* Requires key { search } from 5.X key { inval } */
> > +	test_key = keyctl(KEYCTL_INVALIDATE, private);
> > +	if (test_key < 0) {
> > +		fprintf(stderr, "Failed KEYCTL_INVALIDATE(private):
> > %s\n",
> > +			strerror(errno));
> > +		exit(15);
> > +	}
> > +	if (verbose)
> > +		printf("Invalidated 'private' key\n");
> > +
> > +	/* Requires key { write setattr } from 5.X key { revoke } */
> > +	test_key = keyctl(KEYCTL_REVOKE, prime);
> > +	if (test_key < 0) {
> > +		fprintf(stderr, "Failed KEYCTL_REVOKE(prime): %s\n",
> > +			strerror(errno));
> > +		exit(16);
> > +	}
> > +	if (verbose)
> > +		printf("Revoked 'prime' key\n");
> > +
> > +	/* Requires key { write } from 5.X key { clear } */
> > +	test_key = keyctl(KEYCTL_CLEAR, newring);
> > +	if (test_key < 0) {
> > +		fprintf(stderr, "Failed KEYCTL_CLEAR(newring): %s\n",
> > +			strerror(errno));
> > +		exit(17);
> > +	}
> > +	if (verbose)
> > +		printf("Cleared 'newring' keyring\n");
> > +
> > +	/* To test key { join }, need to join session first */
> > +	test_key = keyctl(KEYCTL_JOIN_SESSION_KEYRING, "user");
> > +	if (test_key < 0) {
> > +		fprintf(stderr, "Failed KEYCTL_JOIN_SESSION_KEYRING,:
> > %s\n",
> > +			strerror(errno));
> > +		exit(18);
> > +	}
> > +	/* Requires key { link } from 5.X key { join } */
> > +	test_key = keyctl(KEYCTL_SESSION_TO_PARENT);
> > +	if (test_key < 0) {
> > +		fprintf(stderr, "Failed KEYCTL_SESSION_TO_PARENT:
> > %s\n",
> > +			strerror(errno));
> > +		exit(19);
> > +	}
> > +	if (verbose)
> > +		printf("Joined session to parent\n");
> > +
> > +	return 0;
> > +}
> > diff --git a/tests/keys/keyctl_relabel.c
> > b/tests/keys/keyctl_relabel.c
> > new file mode 100644
> > index 0000000..0276c7a
> > --- /dev/null
> > +++ b/tests/keys/keyctl_relabel.c
> > @@ -0,0 +1,93 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <stdbool.h>
> > +#include <keyutils.h>
> > +#include <selinux/selinux.h>
> > +
> > +static void usage(char *progname)
> > +{
> > +	fprintf(stderr,
> > +		"usage:  %s [-v] newcon\n"
> > +		"Where:\n\t"
> > +		"-v      Print information.\n\t"
> > +		"newcon  New keyring context.\n", progname);
> > +	exit(-1);
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +	int opt, result;
> > +	char *context, *keycreate_con;
> > +	char r_con[256];
> > +	bool verbose = false;
> > +	key_serial_t newring;
> > +
> > +	while ((opt = getopt(argc, argv, "v")) != -1) {
> > +		switch (opt) {
> > +		case 'v':
> > +			verbose = true;
> > +			break;
> > +		default:
> > +			usage(argv[0]);
> > +		}
> > +	}
> > +
> > +	if (optind >= argc)
> > +		usage(argv[0]);
> > +
> > +	result = getcon(&context);
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed to obtain process context\n");
> > +		exit(1);
> > +	}
> > +	if (verbose)
> > +		printf("Process context: %s\n", context);
> > +	free(context);
> > +
> > +	result = setkeycreatecon(argv[optind]);
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed setkeycreatecon(): %s\n",
> > +			strerror(errno));
> > +		exit(2);
> > +	}
> > +
> > +	result = getkeycreatecon(&keycreate_con);
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed to obtain keycreate
> > context\n");
> > +		exit(3);
> > +	}
> > +	if (verbose)
> > +		printf("New keycreate context: %s\n", keycreate_con);
> > +	free(keycreate_con);
> > +
> > +	newring = add_key("keyring", "my-keyring", NULL, 0,
> > +			  KEY_SPEC_THREAD_KEYRING);
> > +	if (newring < 0) {
> > +		fprintf(stderr, "Failed to add new keyring: %s\n",
> > +			strerror(errno));
> > +		exit(4);
> > +	}
> > +
> > +	result = keyctl(KEYCTL_GET_SECURITY, newring, r_con,
> > sizeof(r_con));
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed to obtain key context: %s\n",
> > +			strerror(errno));
> > +		exit(5);
> > +	}
> > +
> > +	if (strcmp(argv[optind], r_con)) {
> > +		fprintf(stderr, "Relabel error - expected: %s got:
> > %s\n",
> > +			argv[optind], r_con);
> > +		exit(6);
> > +	}
> > +
> > +	if (verbose) {
> > +		printf("'my-keyring' key ID: 0x%x\n", newring);
> > +		printf("'my-keyring' context:\n\t%s\n", r_con);
> > +	}
> > +
> > +	return 0;
> > +}
> > diff --git a/tests/keys/test b/tests/keys/test
> > new file mode 100755
> > index 0000000..4916e7c
> > --- /dev/null
> > +++ b/tests/keys/test
> > @@ -0,0 +1,98 @@
> > +#!/usr/bin/perl
> > +use Test::More;
> > +
> > +BEGIN {
> > +    $basedir = $0;
> > +    $basedir =~ s|(.*)/[^/]*|$1|;
> > +
> > +    $test_count = 13;
> > +
> > +    # allow info to be shown during tests
> > +    $v = $ARGV[0];
> > +    if ($v) {
> > +        if ( $v ne "-v" ) {
> > +            plan skip_all => "Invalid option (use -v)";
> > +        }
> > +    }
> > +    else {
> > +        $v = " ";
> > +    }
> > +
> > +    # From kernel 5.3 request_key() requires additional check of
> > key { link }
> > +    $kvercur = `uname -r`;
> > +    chomp($kvercur);
> > +    $kverminstream = "5.3";
> > +    $test_link_53  = 0;
> > +
> > +    $result = `$basedir/../kvercmp $kvercur $kverminstream`;
> > +    if ( $result >= 0 ) {
> > +        $test_link_53 = 1;
> > +    }
> > +
> > +    plan tests => $test_count;
> > +}
> > +
> > +############ Test keyctl #############
> > +print "Test key class permissions\n";
> > +$result = system "runcon -t test_key_t $basedir/keyctl $v";
> > +ok( $result eq 0 );
> > +
> > +# Deny process { setkeycreate }
> > +$result = system "runcon -t test_no_setkeycreate_t $basedir/keyctl
> > $v 2>&1";
> > +ok( $result >> 8 eq 3 );
> > +
> > +# Deny key { create }
> > +$result = system "runcon -t test_key_no_create_t $basedir/keyctl
> > $v 2>&1";
> > +ok( $result >> 8 eq 3 );
> > +
> > +# Deny key { write }
> > +$result = system "runcon -t test_key_no_write_t $basedir/keyctl $v
> > 2>&1";
> > +ok( $result >> 8 eq 5 );
> > +
> > +# Deny key { search }
> > +$result = system "runcon -t test_key_no_search_t $basedir/keyctl
> > $v 2>&1";
> > +ok( $result >> 8 eq 8 );
> > +
> > +# Deny key { view }
> > +$result = system "runcon -t test_key_no_view_t $basedir/keyctl $v
> > 2>&1";
> > +ok( $result >> 8 eq 10 );
> > +
> > +# Deny key { read }
> > +$result = system "runcon -t test_key_no_read_t $basedir/keyctl $v
> > 2>&1";
> > +ok( $result >> 8 eq 11 );
> > +
> > +# Deny key { link }
> > +$result = system "runcon -t test_key_no_link_t $basedir/keyctl $v
> > 2>&1";
> > +if ($test_link_53) {
> > +    ok( $result >> 8 eq 8 );
> > +}
> > +else {
> > +    ok( $result >> 8 eq 13 );
> > +}
> > +
> > +# Deny key { setattr }
> > +$result = system "runcon -t test_key_no_setattr_t $basedir/keyctl
> > $v 2>&1";
> > +ok( $result >> 8 eq 14 );
> > +
> > +########### Change keyring context ##############
> > +print "Change keyring context\n";
> > +$result = system
> > +"runcon -t test_key_t $basedir/keyctl_relabel $v
> > system_u:system_r:test_newcon_key_t:s0";
> > +ok( $result eq 0 );
> > +
> > +############ Test key_socket #############
> > +print "Test key_socket class\n";
> > +$result = system "runcon -t test_key_sock_t $basedir/key_sock $v";
> > +ok( $result eq 0 );
> > +
> > +# Deny capability { net_admin } - EPERM
> > +$result =
> > +  system "runcon -t test_key_sock_no_net_admin_t $basedir/key_sock
> > $v 2>&1";
> > +ok( $result >> 8 eq 1 );
> > +
> > +# Deny key_socket { create } - EACCES
> > +$result =
> > +  system "runcon -t test_key_sock_no_create_t $basedir/key_sock $v
> > 2>&1";
> > +ok( $result >> 8 eq 13 );
> > +
> > +exit;
> > 




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

  Powered by Linux