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 19/27] containers: Sample: request_key upcall handling
Date: Fri, 15 Feb 2019 16:10:30 +0000 [thread overview]
Message-ID: <155024703003.21651.3499235528404179500.stgit@warthog.procyon.org.uk> (raw)
In-Reply-To: <155024683432.21651.14153938339749694146.stgit@warthog.procyon.org.uk>
Implement a sample upcall handling.
Firstly, the test-container sample is modified to (a) create a staging
keyring and to (b) intercept request_key calls for user-type keys inside
the container and place the authentication keys into that rather than
invoking /sbin/request-key.
Secondly, a test-upcall sample is added that will monitor the keyring for
notifications and spawn /sbin/request-key instances for each of key added.
This is run as:
./test-upcall
to find a keyring called "upcall" in the session keyring (as created by the
./test-container program) and listen for additions to that, or it can be
run as:
./test-upcall <keyring-id>
to listen on a specific keyring.
Note that the test-upcall sample is designed to be run separately from
test-container so that its stdout can be observed.
Signed-off-by: David Howells <dhowells@redhat.com>
---
samples/vfs/Makefile | 6 +
samples/vfs/test-container.c | 16 +++
samples/vfs/test-upcall.c | 243 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 264 insertions(+), 1 deletion(-)
create mode 100644 samples/vfs/test-upcall.c
diff --git a/samples/vfs/Makefile b/samples/vfs/Makefile
index 25420919ee40..a8e9e1142ae3 100644
--- a/samples/vfs/Makefile
+++ b/samples/vfs/Makefile
@@ -5,7 +5,8 @@ hostprogs-$(CONFIG_SAMPLE_VFS) := \
test-fsmount \
test-mntinfo \
test-statx \
- test-container
+ test-container \
+ test-upcall
# Tell kbuild to always build the programs
always := $(hostprogs-y)
@@ -18,5 +19,8 @@ HOSTLDLIBS_test-mntinfo += -lm
HOSTCFLAGS_test-fs-query.o += -I$(objtree)/usr/include
HOSTCFLAGS_test-fsmount.o += -I$(objtree)/usr/include
HOSTCFLAGS_test-statx.o += -I$(objtree)/usr/include
+
HOSTCFLAGS_test-container.o += -I$(objtree)/usr/include
HOSTLDLIBS_test-container += -lkeyutils
+HOSTCFLAGS_test-upcall.o += -I$(objtree)/usr/include
+HOSTLDLIBS_test-upcall += -lkeyutils
diff --git a/samples/vfs/test-container.c b/samples/vfs/test-container.c
index 44ff57afb5a4..7dc9071399b2 100644
--- a/samples/vfs/test-container.c
+++ b/samples/vfs/test-container.c
@@ -20,6 +20,8 @@
#include <sys/stat.h>
#include <keyutils.h>
+#define KEYCTL_CONTAINER_INTERCEPT 31 /* Intercept upcalls inside a container */
+
/* Hope -1 isn't a syscall */
#ifndef __NR_fsopen
#define __NR_fsopen -1
@@ -187,6 +189,7 @@ void container_init(void)
*/
int main(int argc, char *argv[])
{
+ key_serial_t keyring;
pid_t pid;
int fsfd, mfd, cfd, ws;
@@ -259,6 +262,19 @@ int main(int argc, char *argv[])
E(close(fsfd));
E(close(mfd));
+ /* Create a keyring to catch upcalls. */
+ printf("Intercepting...\n");
+ keyring = add_key("keyring", "upcall", NULL, 0, KEY_SPEC_SESSION_KEYRING);
+ if (keyring == -1) {
+ perror("add_key/u");
+ exit(1);
+ }
+
+ if (keyctl(KEYCTL_CONTAINER_INTERCEPT, cfd, "user", 0, keyring) < 0) {
+ perror("keyctl_container_intercept");
+ exit(1);
+ }
+
/* Start the 'init' process. */
printf("Forking...\n");
switch ((pid = fork_into_container(cfd))) {
diff --git a/samples/vfs/test-upcall.c b/samples/vfs/test-upcall.c
new file mode 100644
index 000000000000..225fa0325d1b
--- /dev/null
+++ b/samples/vfs/test-upcall.c
@@ -0,0 +1,243 @@
+/* Container keyring upcall management test.
+ *
+ * Copyright (C) 2019 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <poll.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <keyutils.h>
+#include <linux/watch_queue.h>
+
+#define KEYCTL_WATCH_KEY 30 /* Watch a key or ring of keys for changes */
+#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 */
+
+struct keyctl_query_request_key_auth {
+ char operation[32]; /* Operation name, typically "create" */
+ uid_t fsuid; /* UID of requester */
+ gid_t fsgid; /* GID of requester */
+ key_serial_t target_key; /* The key being instantiated */
+ key_serial_t thread_keyring; /* The requester's thread keyring */
+ key_serial_t process_keyring; /* The requester's process keyring */
+ key_serial_t session_keyring; /* The requester's session keyring */
+ long long spare[1];
+};
+
+static void process_request(key_serial_t keyring, key_serial_t key)
+{
+ struct keyctl_query_request_key_auth info;
+ char target[32], uid[32], gid[32], thread[32], process[32], session[32];
+ void *callout;
+ long len;
+
+#if 0
+ key = keyctl(KEYCTL_FIND_LRU, keyring, ".request_key_auth");
+ if (key == -1) {
+ perror("keyctl/find");
+ exit(1);
+ }
+#endif
+
+ if (keyctl(KEYCTL_QUERY_REQUEST_KEY_AUTH, key, &info) == -1) {
+ perror("keyctl/query");
+ exit(1);
+ }
+
+ len = keyctl_read_alloc(key, &callout);
+ if (len == -1) {
+ perror("keyctl/read");
+ exit(1);
+ }
+
+ sprintf(target, "%d", info.target_key);
+ sprintf(uid, "%d", info.fsuid);
+ sprintf(gid, "%d", info.fsgid);
+ sprintf(thread, "%d", info.thread_keyring);
+ sprintf(process, "%d", info.process_keyring);
+ sprintf(session, "%d", info.session_keyring);
+
+ printf("Authentication key %d\n", key);
+ printf("- %s %s\n", info.operation, target);
+ printf("- uid=%s gid=%s\n", uid, gid);
+ printf("- rings=%s,%s,%s\n", thread, process, session);
+ printf("- callout='%s'\n", (char *)callout);
+
+ switch (fork()) {
+ case 0:
+ /* Only pass the auth token of interest onto /sbin/request-key */
+ if (keyctl(KEYCTL_MOVE, key, keyring, KEY_SPEC_THREAD_KEYRING) < 0) {
+ perror("keyctl_move/1");
+ exit(1);
+ }
+
+ if (keyctl_join_session_keyring(NULL) < 0) {
+ perror("keyctl_join");
+ exit(1);
+ }
+
+ if (keyctl(KEYCTL_MOVE, key,
+ KEY_SPEC_THREAD_KEYRING, KEY_SPEC_SESSION_KEYRING) < 0) {
+ perror("keyctl_move/2");
+ exit(1);
+ }
+
+ execl("/sbin/request-key",
+ "request-key", info.operation, target, uid, gid, thread, process, session,
+ NULL);
+ perror("execve");
+ exit(1);
+
+ case -1:
+ perror("fork");
+ exit(1);
+
+ default:
+ return;
+ }
+}
+
+/*
+ * We saw a change on the keyring.
+ */
+static void saw_key_change(struct watch_notification *n)
+{
+ struct key_notification *k = (struct key_notification *)n;
+ unsigned int len = n->info & WATCH_INFO_LENGTH;
+
+ if (len != sizeof(struct key_notification))
+ return;
+
+ printf("KEY %d change=%u aux=%d\n", k->key_id, n->subtype, k->aux);
+
+ process_request(k->key_id, k->aux);
+}
+
+/*
+ * Consume and display events.
+ */
+static int consumer(int fd, struct watch_queue_buffer *buf)
+{
+ struct watch_notification *n;
+ struct pollfd p[1];
+ unsigned int head, tail, mask = buf->meta.mask;
+
+ for (;;) {
+ p[0].fd = fd;
+ p[0].events = POLLIN | POLLERR;
+ p[0].revents = 0;
+
+ if (poll(p, 1, -1) == -1) {
+ perror("poll");
+ break;
+ }
+
+ printf("ptrs h=%x t=%x m=%x\n",
+ buf->meta.head, buf->meta.tail, buf->meta.mask);
+
+ while (head = __atomic_load_n(&buf->meta.head, __ATOMIC_ACQUIRE),
+ tail = buf->meta.tail,
+ tail != head
+ ) {
+ n = &buf->slots[tail & mask];
+ printf("NOTIFY[%08x-%08x] ty=%04x sy=%04x i=%08x\n",
+ head, tail, n->type, n->subtype, n->info);
+ if ((n->info & WATCH_INFO_LENGTH) == 0)
+ goto out;
+
+ switch (n->type) {
+ case WATCH_TYPE_META:
+ if (n->subtype == WATCH_META_REMOVAL_NOTIFICATION)
+ printf("REMOVAL of watchpoint %08x\n",
+ n->info & WATCH_INFO_ID);
+ break;
+ case WATCH_TYPE_KEY_NOTIFY:
+ saw_key_change(n);
+ break;
+ }
+
+ tail += (n->info & WATCH_INFO_LENGTH) >> WATCH_LENGTH_SHIFT;
+ __atomic_store_n(&buf->meta.tail, tail, __ATOMIC_RELEASE);
+ }
+ }
+
+out:
+ return 0;
+}
+
+/*
+ * We're only interested in key insertion events.
+ */
+static struct watch_notification_filter filter = {
+ .nr_filters = 1,
+ .filters = {
+ [0] = {
+ .type = WATCH_TYPE_KEY_NOTIFY,
+ .subtype_filter[0] = (1 << NOTIFY_KEY_LINKED),
+ },
+ }
+};
+
+int main(int argc, char *argv[])
+{
+ struct watch_queue_buffer *buf;
+ key_serial_t keyring;
+ size_t page_size = sysconf(_SC_PAGESIZE);
+ int fd;
+
+ if (argc == 1) {
+ keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring",
+ "upcall", 0);
+ if (keyring == -1) {
+ perror("keyctl_search");
+ exit(1);
+ }
+ } else if (argc == 2) {
+ keyring = strtoul(argv[1], NULL, 0);
+ } else {
+ fprintf(stderr, "Format: test-upcall [<keyring>]\n");
+ exit(2);
+ }
+
+ /* Create a watch on the keyring to detect the addition of keys. */
+ fd = open("/dev/watch_queue", O_RDWR | O_CLOEXEC);
+ if (fd == -1) {
+ perror("/dev/watch_queue");
+ exit(1);
+ }
+
+ if (ioctl(fd, IOC_WATCH_QUEUE_SET_SIZE, 1) == -1) {
+ perror("/dev/watch_queue(size)");
+ exit(1);
+ }
+
+ if (ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter) == -1) {
+ perror("/dev/watch_queue(filter)");
+ exit(1);
+ }
+
+ buf = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (buf == MAP_FAILED) {
+ perror("mmap");
+ exit(1);
+ }
+
+ if (keyctl(KEYCTL_WATCH_KEY, keyring, fd, 0x01) == -1) {
+ perror("keyctl");
+ exit(1);
+ }
+
+ return consumer(fd, buf);
+}
next prev parent reply other threads:[~2019-02-15 16:10 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 ` David Howells [this message]
2019-02-15 16:10 ` [RFC PATCH 20/27] container, keys: Add a container keyring David Howells
2019-02-15 21:46 ` 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=155024703003.21651.3499235528404179500.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).