linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: David Howells <dhowells@redhat.com>
To: keyrings@vger.kernel.org, trond.myklebust@hammerspace.com,
	sfrench@samba.org
Cc: linux-security-module@vger.kernel.org, linux-nfs@vger.kernel.org,
	linux-cifs@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	rgb@redhat.com, dhowells@redhat.com,
	linux-kernel@vger.kernel.org
Subject: [RFC PATCH 20/27] container, keys: Add a container keyring
Date: Fri, 15 Feb 2019 16:10:45 +0000	[thread overview]
Message-ID: <155024704568.21651.12664692449080180818.stgit@warthog.procyon.org.uk> (raw)
In-Reply-To: <155024683432.21651.14153938339749694146.stgit@warthog.procyon.org.uk>

Allow a container manager to attach keyrings to a container such that the
keys contained therein are searched by request_key() in addition to a
process's normal keyrings.  This allows the manager to install keys to
support filesystem decryption and authentication for superblocks inside the
container without requiring any active role being played by processes
inside of the container.

So, for example, a container could be created, a keyring added and then an
rxrpc-type key added to the keyring such that a container's root filesystem
and data filesystems can be brought in from secure AFS volumes.  It would
also be possible to put filesystem crypto keys in there such that Ext4
encrypted files could be decrypted - without the need to share the key
between other containers or let the key leak into the container.

Because the container manager retains control of the keyring, it can update
the contained keys as necessary to prevent expiration.  Note that the
keyring and keys in the keyring must grant Search permission directly to
the container object.

[!] Note that NFS, CIFS and other filesystems wishing to make use of this
    would have to get the token to use by calling request_key() on entry to
    its VFS methods and retain it in its file struct.

[!] Note that request_key() called from userspace does not look in the
    container keyring.

[!] Note that keys are now tagged with a tag that identifies the network
    namespace (or other domain of operation).  This allows keys to be
    provided in one keyring that allow the same thing but in different
    network namespaces.

The keyring should be created by the container manager and then set using:

	keyctl(KEYCTL_SET_CONTAINER_KEYRING, int containerfd,
	       key_serial_t keyring);

With this, request_key() inside the kernel searches:

	thread-keyring, process-keyring, session-keyring, container-keyring

[!] It may be worth setting a flag on a mountpoint to indicate whether to
    search the container keyring first or last.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 include/linux/container.h    |    1 +
 include/uapi/linux/keyctl.h  |    1 +
 kernel/container.c           |    1 +
 samples/vfs/test-container.c |   14 +++++++++++++
 security/keys/compat.c       |    2 ++
 security/keys/container.c    |   44 ++++++++++++++++++++++++++++++++++++++++++
 security/keys/internal.h     |    1 +
 security/keys/keyctl.c       |    2 ++
 security/keys/process_keys.c |   23 ++++++++++++++++++++++
 9 files changed, 89 insertions(+)

diff --git a/include/linux/container.h b/include/linux/container.h
index a8cac800ce75..7424f7fb5560 100644
--- a/include/linux/container.h
+++ b/include/linux/container.h
@@ -33,6 +33,7 @@ struct container {
 	refcount_t		usage;
 	int			exit_code;	/* The exit code of 'init' */
 	const struct cred	*cred;		/* Creds for this container, including userns */
+	struct key		*keyring;	/* Externally managed container keyring */
 	struct nsproxy		*ns;		/* This container's namespaces */
 	struct path		root;		/* The root of the container's fs namespace */
 	struct task_struct	*init;		/* The 'init' task for this container */
diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index 5b792303a05b..a2afb4512f34 100644
--- a/include/uapi/linux/keyctl.h
+++ b/include/uapi/linux/keyctl.h
@@ -72,6 +72,7 @@
 #define KEYCTL_QUERY_REQUEST_KEY_AUTH	32	/* Query a request_key_auth key */
 #define KEYCTL_MOVE			33	/* Move keys between keyrings */
 #define KEYCTL_FIND_LRU			34	/* Find the least-recently used key in a keyring */
+#define KEYCTL_SET_CONTAINER_KEYRING	35	/* Attach a keyring to a container */
 
 /* keyctl structures */
 struct keyctl_dh_params {
diff --git a/kernel/container.c b/kernel/container.c
index 33e41fe5050b..f2706a45f364 100644
--- a/kernel/container.c
+++ b/kernel/container.c
@@ -71,6 +71,7 @@ void put_container(struct container *c)
 
 		if (c->cred)
 			put_cred(c->cred);
+		key_put(c->keyring);
 		security_container_free(c);
 		kfree(c);
 		c = parent;
diff --git a/samples/vfs/test-container.c b/samples/vfs/test-container.c
index 7dc9071399b2..e24048fdbe33 100644
--- a/samples/vfs/test-container.c
+++ b/samples/vfs/test-container.c
@@ -21,6 +21,7 @@
 #include <keyutils.h>
 
 #define KEYCTL_CONTAINER_INTERCEPT	31	/* Intercept upcalls inside a container */
+#define KEYCTL_SET_CONTAINER_KEYRING	35	/* Attach a keyring to a container */
 
 /* Hope -1 isn't a syscall */
 #ifndef __NR_fsopen
@@ -262,6 +263,19 @@ int main(int argc, char *argv[])
 	E(close(fsfd));
 	E(close(mfd));
 
+	/* Create a container keyring. */
+	printf("Container keyring...\n");
+	keyring = add_key("keyring", "_container", NULL, 0, KEY_SPEC_SESSION_KEYRING);
+	if (keyring == -1) {
+		perror("add_key/c");
+		exit(1);
+	}
+
+	if (keyctl(KEYCTL_SET_CONTAINER_KEYRING, cfd, keyring) < 0) {
+		perror("keyctl_set_container_keyring");
+		exit(1);
+	}
+
 	/* Create a keyring to catch upcalls. */
 	printf("Intercepting...\n");
 	keyring = add_key("keyring", "upcall", NULL, 0, KEY_SPEC_SESSION_KEYRING);
diff --git a/security/keys/compat.c b/security/keys/compat.c
index 160fb7b37352..7990ec026237 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -168,6 +168,8 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
 		return keyctl_query_request_key_auth(arg2, compat_ptr(arg3));
 	case KEYCTL_FIND_LRU:
 		return keyctl_find_lru(arg2, compat_ptr(arg3));
+	case KEYCTL_SET_CONTAINER_KEYRING:
+		return keyctl_set_container_keyring(arg2, arg3);
 #endif
 
 	case KEYCTL_MOVE:
diff --git a/security/keys/container.c b/security/keys/container.c
index 8e6b3c8710e2..720600f6a318 100644
--- a/security/keys/container.c
+++ b/security/keys/container.c
@@ -373,3 +373,47 @@ long keyctl_find_lru(key_serial_t _keyring, const char __user *type_name)
 	key_ref_put(keyring_ref);
 	return ret;
 }
+
+/*
+ * Attach a keyring to a container as the container key, to be searched by
+ * request_key() after thread, process and session keyrings.  This is only
+ * permitted once per container.
+ */
+long keyctl_set_container_keyring(int containerfd, key_serial_t _keyring)
+{
+	struct container *c;
+	struct fd f;
+	key_ref_t keyring_ref = NULL;
+	long ret;
+
+	if (containerfd < 0 || _keyring <= 0)
+		return -EINVAL;
+
+	f = fdget(containerfd);
+	if (!f.file)
+		return -EBADF;
+	ret = -EINVAL;
+	if (!is_container_file(f.file))
+		goto out_fd;
+
+	c = f.file->private_data;
+
+	keyring_ref = lookup_user_key(_keyring, 0, KEY_NEED_SEARCH);
+	if (IS_ERR(keyring_ref)) {
+		ret = PTR_ERR(keyring_ref);
+		goto out_fd;
+	}
+
+	ret = -EBUSY;
+	spin_lock(&c->lock);
+	if (!c->keyring) {
+		c->keyring = key_get(key_ref_to_ptr(keyring_ref));
+		ret = 0;
+	}
+	spin_unlock(&c->lock);
+
+	key_ref_put(keyring_ref);
+out_fd:
+	fdput(f);
+	return ret;
+}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index fe4a4da1ff17..6be76caee874 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -366,6 +366,7 @@ extern long keyctl_container_intercept(int, const char __user *, unsigned int, k
 extern long keyctl_query_request_key_auth(key_serial_t,
 					  struct keyctl_query_request_key_auth __user *);
 extern long keyctl_find_lru(key_serial_t, const char __user *);
+extern long keyctl_set_container_keyring(int, key_serial_t);
 #endif
 
 /*
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 1446bc52e369..a25799249b8a 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1919,6 +1919,8 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
 	case KEYCTL_FIND_LRU:
 		return keyctl_find_lru((key_serial_t)arg2,
 				       (const char __user *)arg3);
+	case KEYCTL_SET_CONTAINER_KEYRING:
+		return keyctl_set_container_keyring((int)arg2, (key_serial_t)arg3);
 #endif
 
 	case KEYCTL_MOVE:
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 0e0b9ccad2f8..39d3cbac920c 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -17,6 +17,7 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/security.h>
+#include <linux/container.h>
 #include <linux/user_namespace.h>
 #include <linux/uaccess.h>
 #include <keys/request_key_auth-type.h>
@@ -433,6 +434,28 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
 		}
 	}
 
+	/* Search any container keyring on the end. */
+#ifdef CONFIG_CONTAINERS
+	if (current->container->keyring) {
+		key_ref = keyring_search_aux(
+			make_key_ref(current->container->keyring, 1), ctx);
+		if (!IS_ERR(key_ref))
+			goto found;
+
+		switch (PTR_ERR(key_ref)) {
+		case -EAGAIN: /* no key */
+			if (ret)
+				break;
+		case -ENOKEY: /* negative key */
+			ret = key_ref;
+			break;
+		default:
+			err = key_ref;
+			break;
+		}
+	}
+#endif
+
 	/* no key - decide on the error we're going to go for */
 	key_ref = ret ? ret : err;
 


  parent reply	other threads:[~2019-02-15 16:11 UTC|newest]

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-02-15 16:07 [RFC PATCH 00/27] Containers and using authenticated filesystems David Howells
2019-02-15 16:07 ` [RFC PATCH 01/27] containers: Rename linux/container.h to linux/container_dev.h David Howells
2019-02-15 16:07 ` [RFC PATCH 02/27] containers: Implement containers as kernel objects David Howells
2019-02-17 18:57   ` Trond Myklebust
2019-02-17 19:39   ` James Bottomley
2019-02-19 16:56   ` Eric W. Biederman
2019-02-19 23:03   ` David Howells
2019-02-20 14:23     ` Trond Myklebust
2019-02-19 23:06   ` David Howells
2019-02-20  2:20     ` James Bottomley
2019-02-20  3:04       ` Ian Kent
2019-02-20  3:46         ` James Bottomley
2019-02-20  4:42           ` Ian Kent
2019-02-20  6:57           ` Paul Moore
2019-02-19 23:13   ` David Howells
2019-02-19 23:55   ` Tycho Andersen
2019-02-20  2:46   ` Ian Kent
2019-02-20 13:26     ` Christian Brauner
2019-02-21 10:39       ` Ian Kent
2019-02-15 16:07 ` [RFC PATCH 03/27] containers: Provide /proc/containers David Howells
2019-02-15 16:07 ` [RFC PATCH 04/27] containers: Allow a process to be forked into a container David Howells
2019-02-15 17:39   ` Stephen Smalley
2019-02-19 16:39   ` Eric W. Biederman
2019-02-19 23:16   ` David Howells
2019-02-15 16:07 ` [RFC PATCH 05/27] containers: Open a socket inside " David Howells
2019-02-19 16:41   ` Eric W. Biederman
2019-02-15 16:08 ` [RFC PATCH 06/27] containers, vfs: Allow syscall dirfd arguments to take a container fd David Howells
2019-02-19 16:45   ` Eric W. Biederman
2019-02-19 23:24   ` David Howells
2019-02-15 16:08 ` [RFC PATCH 07/27] containers: Make fsopen() able to create a superblock in a container David Howells
2019-02-15 16:08 ` [RFC PATCH 08/27] containers, vfs: Honour CONTAINER_NEW_EMPTY_FS_NS David Howells
2019-02-17  0:11   ` Al Viro
2019-02-15 16:08 ` [RFC PATCH 09/27] vfs: Allow mounting to other namespaces David Howells
2019-02-17  0:14   ` Al Viro
2019-02-15 16:08 ` [RFC PATCH 10/27] containers: Provide fs_context op for container setting David Howells
2019-02-15 16:09 ` [RFC PATCH 11/27] containers: Sample program for driving container objects David Howells
2019-02-15 16:09 ` [RFC PATCH 12/27] containers: Allow a daemon to intercept request_key upcalls in a container David Howells
2019-02-15 16:09 ` [RFC PATCH 13/27] keys: Provide a keyctl to query a request_key authentication key David Howells
2019-02-15 16:09 ` [RFC PATCH 14/27] keys: Break bits out of key_unlink() David Howells
2019-02-15 16:09 ` [RFC PATCH 15/27] keys: Make __key_link_begin() handle lockdep nesting David Howells
2019-02-15 16:09 ` [RFC PATCH 16/27] keys: Grant Link permission to possessers of request_key auth keys David Howells
2019-02-15 16:10 ` [RFC PATCH 17/27] keys: Add a keyctl to move a key between keyrings David Howells
2019-02-15 16:10 ` [RFC PATCH 18/27] keys: Find the least-recently used unseen key in a keyring David Howells
2019-02-15 16:10 ` [RFC PATCH 19/27] containers: Sample: request_key upcall handling David Howells
2019-02-15 16:10 ` David Howells [this message]
2019-02-15 21:46   ` [RFC PATCH 20/27] container, keys: Add a container keyring Eric Biggers
2019-02-15 16:11 ` [RFC PATCH 21/27] keys: Fix request_key() lack of Link perm check on found key David Howells
2019-02-15 16:11 ` [RFC PATCH 22/27] KEYS: Replace uid/gid/perm permissions checking with an ACL David Howells
2019-02-15 17:32   ` Stephen Smalley
2019-02-15 17:39   ` David Howells
2019-02-15 16:11 ` [RFC PATCH 23/27] KEYS: Provide KEYCTL_GRANT_PERMISSION David Howells
2019-02-15 16:11 ` [RFC PATCH 24/27] keys: Allow a container to be specified as a subject in a key's ACL David Howells
2019-02-15 16:11 ` [RFC PATCH 25/27] keys: Provide a way to ask for the container keyring David Howells
2019-02-15 16:12 ` [RFC PATCH 26/27] keys: Allow containers to be included in key ACLs by name David Howells
2019-02-15 16:12 ` [RFC PATCH 27/27] containers: Sample to grant access to a key in a container David Howells
2019-02-15 22:36 ` [RFC PATCH 00/27] Containers and using authenticated filesystems James Morris
2019-02-19 16:35 ` Eric W. Biederman
2019-02-20 14:18   ` Christian Brauner
2019-02-19 23:42 ` David Howells
2019-02-20  7:00   ` Paul Moore
2019-02-20 18:54   ` Steve French

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=155024704568.21651.12664692449080180818.stgit@warthog.procyon.org.uk \
    --to=dhowells@redhat.com \
    --cc=keyrings@vger.kernel.org \
    --cc=linux-cifs@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=rgb@redhat.com \
    --cc=sfrench@samba.org \
    --cc=trond.myklebust@hammerspace.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).