summaryrefslogtreecommitdiffstats
path: root/keys-krb-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'keys-krb-support.patch')
-rw-r--r--keys-krb-support.patch748
1 files changed, 0 insertions, 748 deletions
diff --git a/keys-krb-support.patch b/keys-krb-support.patch
deleted file mode 100644
index aa4752c78..000000000
--- a/keys-krb-support.patch
+++ /dev/null
@@ -1,748 +0,0 @@
-From d7ccdaa17aab12a49f5e9e327b55167c4af26bf8 Mon Sep 17 00:00:00 2001
-From: David Howells <dhowells@redhat.com>
-Date: Fri, 30 Aug 2013 15:37:54 +0100
-Subject: [PATCH 1/2] KEYS: Implement a big key type that can save to tmpfs
-
-Implement a big key type that can save its contents to tmpfs and thus
-swapspace when memory is tight. This is useful for Kerberos ticket caches.
-
-Signed-off-by: David Howells <dhowells@redhat.com>
-Tested-by: Simo Sorce <simo@redhat.com>
----
- include/keys/big_key-type.h | 25 ++++++
- include/linux/key.h | 1 +
- security/keys/Kconfig | 11 +++
- security/keys/Makefile | 1 +
- security/keys/big_key.c | 204 ++++++++++++++++++++++++++++++++++++++++++++
- 5 files changed, 242 insertions(+)
- create mode 100644 include/keys/big_key-type.h
- create mode 100644 security/keys/big_key.c
-
-diff --git a/include/keys/big_key-type.h b/include/keys/big_key-type.h
-new file mode 100644
-index 0000000..d69bc8a
---- /dev/null
-+++ b/include/keys/big_key-type.h
-@@ -0,0 +1,25 @@
-+/* Big capacity key type.
-+ *
-+ * Copyright (C) 2013 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 License
-+ * as published by the Free Software Foundation; either version
-+ * 2 of the License, or (at your option) any later version.
-+ */
-+
-+#ifndef _KEYS_BIG_KEY_TYPE_H
-+#define _KEYS_BIG_KEY_TYPE_H
-+
-+#include <linux/key-type.h>
-+
-+extern struct key_type key_type_big_key;
-+
-+extern int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep);
-+extern void big_key_revoke(struct key *key);
-+extern void big_key_destroy(struct key *key);
-+extern void big_key_describe(const struct key *big_key, struct seq_file *m);
-+extern long big_key_read(const struct key *key, char __user *buffer, size_t buflen);
-+
-+#endif /* _KEYS_BIG_KEY_TYPE_H */
-diff --git a/include/linux/key.h b/include/linux/key.h
-index 2417f78..010dbb6 100644
---- a/include/linux/key.h
-+++ b/include/linux/key.h
-@@ -201,6 +201,7 @@ struct key {
- unsigned long value;
- void __rcu *rcudata;
- void *data;
-+ void *data2[2];
- } payload;
- struct assoc_array keys;
- };
-diff --git a/security/keys/Kconfig b/security/keys/Kconfig
-index 15e0dfe..b563622 100644
---- a/security/keys/Kconfig
-+++ b/security/keys/Kconfig
-@@ -20,6 +20,17 @@ config KEYS
-
- If you are unsure as to whether this is required, answer N.
-
-+config BIG_KEYS
-+ tristate "Large payload keys"
-+ depends on KEYS
-+ depends on TMPFS
-+ help
-+ This option provides support for holding large keys within the kernel
-+ (for example Kerberos ticket caches). The data may be stored out to
-+ swapspace by tmpfs.
-+
-+ If you are unsure as to whether this is required, answer N.
-+
- config TRUSTED_KEYS
- tristate "TRUSTED KEYS"
- depends on KEYS && TCG_TPM
-diff --git a/security/keys/Makefile b/security/keys/Makefile
-index 504aaa0..c487c77 100644
---- a/security/keys/Makefile
-+++ b/security/keys/Makefile
-@@ -22,5 +22,6 @@ obj-$(CONFIG_SYSCTL) += sysctl.o
- #
- # Key types
- #
-+obj-$(CONFIG_BIG_KEYS) += big_key.o
- obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
- obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/
-diff --git a/security/keys/big_key.c b/security/keys/big_key.c
-new file mode 100644
-index 0000000..5f9defc
---- /dev/null
-+++ b/security/keys/big_key.c
-@@ -0,0 +1,204 @@
-+/* Large capacity key type
-+ *
-+ * Copyright (C) 2013 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 <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/seq_file.h>
-+#include <linux/file.h>
-+#include <linux/shmem_fs.h>
-+#include <linux/err.h>
-+#include <keys/user-type.h>
-+#include <keys/big_key-type.h>
-+
-+MODULE_LICENSE("GPL");
-+
-+/*
-+ * If the data is under this limit, there's no point creating a shm file to
-+ * hold it as the permanently resident metadata for the shmem fs will be at
-+ * least as large as the data.
-+ */
-+#define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry))
-+
-+/*
-+ * big_key defined keys take an arbitrary string as the description and an
-+ * arbitrary blob of data as the payload
-+ */
-+struct key_type key_type_big_key = {
-+ .name = "big_key",
-+ .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
-+ .instantiate = big_key_instantiate,
-+ .match = user_match,
-+ .revoke = big_key_revoke,
-+ .destroy = big_key_destroy,
-+ .describe = big_key_describe,
-+ .read = big_key_read,
-+};
-+
-+/*
-+ * Instantiate a big key
-+ */
-+int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
-+{
-+ struct path *path = (struct path *)&key->payload.data2;
-+ struct file *file;
-+ ssize_t written;
-+ size_t datalen = prep->datalen;
-+ int ret;
-+
-+ ret = -EINVAL;
-+ if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data)
-+ goto error;
-+
-+ /* Set an arbitrary quota */
-+ ret = key_payload_reserve(key, 16);
-+ if (ret < 0)
-+ goto error;
-+
-+ key->type_data.x[1] = datalen;
-+
-+ if (datalen > BIG_KEY_FILE_THRESHOLD) {
-+ /* Create a shmem file to store the data in. This will permit the data
-+ * to be swapped out if needed.
-+ *
-+ * TODO: Encrypt the stored data with a temporary key.
-+ */
-+ file = shmem_file_setup("", datalen, 0);
-+ if (IS_ERR(file))
-+ goto err_quota;
-+
-+ written = kernel_write(file, prep->data, prep->datalen, 0);
-+ if (written != datalen) {
-+ if (written >= 0)
-+ ret = -ENOMEM;
-+ goto err_fput;
-+ }
-+
-+ /* Pin the mount and dentry to the key so that we can open it again
-+ * later
-+ */
-+ *path = file->f_path;
-+ path_get(path);
-+ fput(file);
-+ } else {
-+ /* Just store the data in a buffer */
-+ void *data = kmalloc(datalen, GFP_KERNEL);
-+ if (!data) {
-+ ret = -ENOMEM;
-+ goto err_quota;
-+ }
-+
-+ key->payload.data = memcpy(data, prep->data, prep->datalen);
-+ }
-+ return 0;
-+
-+err_fput:
-+ fput(file);
-+err_quota:
-+ key_payload_reserve(key, 0);
-+error:
-+ return ret;
-+}
-+
-+/*
-+ * dispose of the links from a revoked keyring
-+ * - called with the key sem write-locked
-+ */
-+void big_key_revoke(struct key *key)
-+{
-+ struct path *path = (struct path *)&key->payload.data2;
-+
-+ /* clear the quota */
-+ key_payload_reserve(key, 0);
-+ if (key_is_instantiated(key) && key->type_data.x[1] > BIG_KEY_FILE_THRESHOLD)
-+ vfs_truncate(path, 0);
-+}
-+
-+/*
-+ * dispose of the data dangling from the corpse of a big_key key
-+ */
-+void big_key_destroy(struct key *key)
-+{
-+ if (key->type_data.x[1] > BIG_KEY_FILE_THRESHOLD) {
-+ struct path *path = (struct path *)&key->payload.data2;
-+ path_put(path);
-+ path->mnt = NULL;
-+ path->dentry = NULL;
-+ } else {
-+ kfree(key->payload.data);
-+ key->payload.data = NULL;
-+ }
-+}
-+
-+/*
-+ * describe the big_key key
-+ */
-+void big_key_describe(const struct key *key, struct seq_file *m)
-+{
-+ unsigned long datalen = key->type_data.x[1];
-+
-+ seq_puts(m, key->description);
-+
-+ if (key_is_instantiated(key))
-+ seq_printf(m, ": %lu [%s]",
-+ datalen,
-+ datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
-+}
-+
-+/*
-+ * read the key data
-+ * - the key's semaphore is read-locked
-+ */
-+long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
-+{
-+ unsigned long datalen = key->type_data.x[1];
-+ long ret;
-+
-+ if (!buffer || buflen < datalen)
-+ return datalen;
-+
-+ if (datalen > BIG_KEY_FILE_THRESHOLD) {
-+ struct path *path = (struct path *)&key->payload.data2;
-+ struct file *file;
-+ loff_t pos;
-+
-+ file = dentry_open(path, O_RDONLY, current_cred());
-+ if (IS_ERR(file))
-+ return PTR_ERR(file);
-+
-+ pos = 0;
-+ ret = vfs_read(file, buffer, datalen, &pos);
-+ fput(file);
-+ if (ret >= 0 && ret != datalen)
-+ ret = -EIO;
-+ } else {
-+ ret = datalen;
-+ if (copy_to_user(buffer, key->payload.data, datalen) != 0)
-+ ret = -EFAULT;
-+ }
-+
-+ return ret;
-+}
-+
-+/*
-+ * Module stuff
-+ */
-+static int __init big_key_init(void)
-+{
-+ return register_key_type(&key_type_big_key);
-+}
-+
-+static void __exit big_key_cleanup(void)
-+{
-+ unregister_key_type(&key_type_big_key);
-+}
-+
-+module_init(big_key_init);
-+module_exit(big_key_cleanup);
---
-1.8.3.1
-
-
-From 862e98313b10123fa4352117b0b0c0f5a530cefb Mon Sep 17 00:00:00 2001
-From: David Howells <dhowells@redhat.com>
-Date: Fri, 30 Aug 2013 15:37:54 +0100
-Subject: [PATCH 2/2] KEYS: Add per-user_namespace registers for persistent
- per-UID kerberos caches
-
-Add support for per-user_namespace registers of persistent per-UID kerberos
-caches held within the kernel.
-
-This allows the kerberos cache to be retained beyond the life of all a user's
-processes so that the user's cron jobs can work.
-
-The kerberos cache is envisioned as a keyring/key tree looking something like:
-
- struct user_namespace
- \___ .krb_cache keyring - The register
- \___ _krb.0 keyring - Root's Kerberos cache
- \___ _krb.5000 keyring - User 5000's Kerberos cache
- \___ _krb.5001 keyring - User 5001's Kerberos cache
- \___ tkt785 big_key - A ccache blob
- \___ tkt12345 big_key - Another ccache blob
-
-Or possibly:
-
- struct user_namespace
- \___ .krb_cache keyring - The register
- \___ _krb.0 keyring - Root's Kerberos cache
- \___ _krb.5000 keyring - User 5000's Kerberos cache
- \___ _krb.5001 keyring - User 5001's Kerberos cache
- \___ tkt785 keyring - A ccache
- \___ krbtgt/REDHAT.COM@REDHAT.COM big_key
- \___ http/REDHAT.COM@REDHAT.COM user
- \___ afs/REDHAT.COM@REDHAT.COM user
- \___ nfs/REDHAT.COM@REDHAT.COM user
- \___ krbtgt/KERNEL.ORG@KERNEL.ORG big_key
- \___ http/KERNEL.ORG@KERNEL.ORG big_key
-
-What goes into a particular Kerberos cache is entirely up to userspace. Kernel
-support is limited to giving you the Kerberos cache keyring that you want.
-
-The user asks for their Kerberos cache by:
-
- krb_cache = keyctl_get_krbcache(uid, dest_keyring);
-
-The uid is -1 or the user's own UID for the user's own cache or the uid of some
-other user's cache (requires CAP_SETUID). This permits rpc.gssd or whatever to
-mess with the cache.
-
-The cache returned is a keyring named "_krb.<uid>" that the possessor can read,
-search, clear, invalidate, unlink from and add links to. Active LSMs get a
-chance to rule on whether the caller is permitted to make a link.
-
-Each uid's cache keyring is created when it first accessed and is given a
-timeout that is extended each time this function is called so that the keyring
-goes away after a while. The timeout is configurable by sysctl but defaults to
-three days.
-
-Each user_namespace struct gets a lazily-created keyring that serves as the
-register. The cache keyrings are added to it. This means that standard key
-search and garbage collection facilities are available.
-
-The user_namespace struct's register goes away when it does and anything left
-in it is then automatically gc'd.
-
-Signed-off-by: David Howells <dhowells@redhat.com>
-Tested-by: Simo Sorce <simo@redhat.com>
-cc: Serge E. Hallyn <serge.hallyn@ubuntu.com>
-cc: Eric W. Biederman <ebiederm@xmission.com>
----
- include/linux/user_namespace.h | 7 ++
- include/uapi/linux/keyctl.h | 1 +
- kernel/user.c | 4 +
- kernel/user_namespace.c | 6 ++
- security/keys/Kconfig | 17 +++++
- security/keys/Makefile | 1 +
- security/keys/compat.c | 3 +
- security/keys/internal.h | 9 +++
- security/keys/keyctl.c | 3 +
- security/keys/persistent.c | 169 +++++++++++++++++++++++++++++++++++++++++
- security/keys/sysctl.c | 11 +++
- 11 files changed, 231 insertions(+)
- create mode 100644 security/keys/persistent.c
-
-diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
-index 4db2985..bb0639d 100644
---- a/include/linux/user_namespace.h
-+++ b/include/linux/user_namespace.h
-@@ -27,6 +27,13 @@ struct user_namespace {
- kuid_t owner;
- kgid_t group;
- unsigned int proc_inum;
-+
-+ /* Register of per-UID persistent keyrings for this namespace */
-+#ifdef CONFIG_PERSISTENT_KEYRINGS
-+ struct key *persistent_keyring_register;
-+ struct rw_semaphore persistent_keyring_register_sem;
-+#endif
-+
- };
-
- extern struct user_namespace init_user_ns;
-diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
-index c9b7f4fa..840cb99 100644
---- a/include/uapi/linux/keyctl.h
-+++ b/include/uapi/linux/keyctl.h
-@@ -56,5 +56,6 @@
- #define KEYCTL_REJECT 19 /* reject a partially constructed key */
- #define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */
- #define KEYCTL_INVALIDATE 21 /* invalidate a key */
-+#define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */
-
- #endif /* _LINUX_KEYCTL_H */
-diff --git a/kernel/user.c b/kernel/user.c
-index 5bbb919..a3a0dbf 100644
---- a/kernel/user.c
-+++ b/kernel/user.c
-@@ -51,6 +51,10 @@ struct user_namespace init_user_ns = {
- .owner = GLOBAL_ROOT_UID,
- .group = GLOBAL_ROOT_GID,
- .proc_inum = PROC_USER_INIT_INO,
-+#ifdef CONFIG_KEYS_KERBEROS_CACHE
-+ .krb_cache_register_sem =
-+ __RWSEM_INITIALIZER(init_user_ns.krb_cache_register_sem),
-+#endif
- };
- EXPORT_SYMBOL_GPL(init_user_ns);
-
-diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
-index 13fb113..2dbc299 100644
---- a/kernel/user_namespace.c
-+++ b/kernel/user_namespace.c
-@@ -101,6 +101,9 @@ int create_user_ns(struct cred *new)
-
- set_cred_user_ns(new, ns);
-
-+#ifdef CONFIG_PERSISTENT_KEYRINGS
-+ init_rwsem(&ns->persistent_keyring_register_sem);
-+#endif
- return 0;
- }
-
-@@ -130,6 +133,9 @@ void free_user_ns(struct user_namespace *ns)
-
- do {
- parent = ns->parent;
-+#ifdef CONFIG_PERSISTENT_KEYRINGS
-+ key_put(ns->persistent_keyring_register);
-+#endif
- proc_free_inum(ns->proc_inum);
- kmem_cache_free(user_ns_cachep, ns);
- ns = parent;
-diff --git a/security/keys/Kconfig b/security/keys/Kconfig
-index b563622..53d8748 100644
---- a/security/keys/Kconfig
-+++ b/security/keys/Kconfig
-@@ -20,6 +20,23 @@ config KEYS
-
- If you are unsure as to whether this is required, answer N.
-
-+config PERSISTENT_KEYRINGS
-+ bool "Enable register of persistent per-UID keyrings"
-+ depends on KEYS
-+ help
-+ This option provides a register of persistent per-UID keyrings,
-+ primarily aimed at Kerberos key storage. The keyrings are persistent
-+ in the sense that they stay around after all processes of that UID
-+ have exited, not that they survive the machine being rebooted.
-+
-+ A particular keyring may be accessed by either the user whose keyring
-+ it is or by a process with administrative privileges. The active
-+ LSMs gets to rule on which admin-level processes get to access the
-+ cache.
-+
-+ Keyrings are created and added into the register upon demand and get
-+ removed if they expire (a default timeout is set upon creation).
-+
- config BIG_KEYS
- tristate "Large payload keys"
- depends on KEYS
-diff --git a/security/keys/Makefile b/security/keys/Makefile
-index c487c77..dfb3a7b 100644
---- a/security/keys/Makefile
-+++ b/security/keys/Makefile
-@@ -18,6 +18,7 @@ obj-y := \
- obj-$(CONFIG_KEYS_COMPAT) += compat.o
- obj-$(CONFIG_PROC_FS) += proc.o
- obj-$(CONFIG_SYSCTL) += sysctl.o
-+obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o
-
- #
- # Key types
-diff --git a/security/keys/compat.c b/security/keys/compat.c
-index d65fa7f..bbd32c7 100644
---- a/security/keys/compat.c
-+++ b/security/keys/compat.c
-@@ -138,6 +138,9 @@ asmlinkage long compat_sys_keyctl(u32 option,
- case KEYCTL_INVALIDATE:
- return keyctl_invalidate_key(arg2);
-
-+ case KEYCTL_GET_PERSISTENT:
-+ return keyctl_get_persistent(arg2, arg3);
-+
- default:
- return -EOPNOTSUPP;
- }
-diff --git a/security/keys/internal.h b/security/keys/internal.h
-index 581c6f6..80b2aac 100644
---- a/security/keys/internal.h
-+++ b/security/keys/internal.h
-@@ -255,6 +255,15 @@ extern long keyctl_invalidate_key(key_serial_t);
- extern long keyctl_instantiate_key_common(key_serial_t,
- const struct iovec *,
- unsigned, size_t, key_serial_t);
-+#ifdef CONFIG_PERSISTENT_KEYRINGS
-+extern long keyctl_get_persistent(uid_t, key_serial_t);
-+extern unsigned persistent_keyring_expiry;
-+#else
-+static inline long keyctl_get_persistent(uid_t uid, key_serial_t destring)
-+{
-+ return -EOPNOTSUPP;
-+}
-+#endif
-
- /*
- * Debugging key validation
-diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
-index 33cfd27..cee72ce 100644
---- a/security/keys/keyctl.c
-+++ b/security/keys/keyctl.c
-@@ -1667,6 +1667,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
- case KEYCTL_INVALIDATE:
- return keyctl_invalidate_key((key_serial_t) arg2);
-
-+ case KEYCTL_GET_PERSISTENT:
-+ return keyctl_get_persistent((uid_t)arg2, (key_serial_t)arg3);
-+
- default:
- return -EOPNOTSUPP;
- }
-diff --git a/security/keys/persistent.c b/security/keys/persistent.c
-new file mode 100644
-index 0000000..631a022
---- /dev/null
-+++ b/security/keys/persistent.c
-@@ -0,0 +1,169 @@
-+/* General persistent per-UID keyrings register
-+ *
-+ * Copyright (C) 2013 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 <linux/user_namespace.h>
-+#include "internal.h"
-+
-+unsigned persistent_keyring_expiry = 3 * 24 * 3600; /* Expire after 3 days of non-use */
-+
-+/*
-+ * Create the persistent keyring register for the current user namespace.
-+ *
-+ * Called with the namespace's sem locked for writing.
-+ */
-+static int key_create_persistent_register(struct user_namespace *ns)
-+{
-+ struct key *reg = keyring_alloc(".persistent_register",
-+ KUIDT_INIT(0), KGIDT_INIT(0),
-+ current_cred(),
-+ ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
-+ KEY_USR_VIEW | KEY_USR_READ),
-+ KEY_ALLOC_NOT_IN_QUOTA, NULL);
-+ if (IS_ERR(reg))
-+ return PTR_ERR(reg);
-+
-+ ns->persistent_keyring_register = reg;
-+ return 0;
-+}
-+
-+/*
-+ * Create the persistent keyring for the specified user.
-+ *
-+ * Called with the namespace's sem locked for writing.
-+ */
-+static key_ref_t key_create_persistent(struct user_namespace *ns, kuid_t uid,
-+ struct keyring_index_key *index_key)
-+{
-+ struct key *persistent;
-+ key_ref_t reg_ref, persistent_ref;
-+
-+ if (!ns->persistent_keyring_register) {
-+ long err = key_create_persistent_register(ns);
-+ if (err < 0)
-+ return ERR_PTR(err);
-+ } else {
-+ reg_ref = make_key_ref(ns->persistent_keyring_register, true);
-+ persistent_ref = find_key_to_update(reg_ref, index_key);
-+ if (persistent_ref)
-+ return persistent_ref;
-+ }
-+
-+ persistent = keyring_alloc(index_key->description,
-+ uid, INVALID_GID, current_cred(),
-+ ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
-+ KEY_USR_VIEW | KEY_USR_READ),
-+ KEY_ALLOC_NOT_IN_QUOTA,
-+ ns->persistent_keyring_register);
-+ if (IS_ERR(persistent))
-+ return ERR_CAST(persistent);
-+
-+ return make_key_ref(persistent, true);
-+}
-+
-+/*
-+ * Get the persistent keyring for a specific UID and link it to the nominated
-+ * keyring.
-+ */
-+static long key_get_persistent(struct user_namespace *ns, kuid_t uid,
-+ key_ref_t dest_ref)
-+{
-+ struct keyring_index_key index_key;
-+ struct key *persistent;
-+ key_ref_t reg_ref, persistent_ref;
-+ char buf[32];
-+ long ret;
-+
-+ /* Look in the register if it exists */
-+ index_key.type = &key_type_keyring;
-+ index_key.description = buf;
-+ index_key.desc_len = sprintf(buf, "_persistent.%u", from_kuid(ns, uid));
-+
-+ if (ns->persistent_keyring_register) {
-+ reg_ref = make_key_ref(ns->persistent_keyring_register, true);
-+ down_read(&ns->persistent_keyring_register_sem);
-+ persistent_ref = find_key_to_update(reg_ref, &index_key);
-+ up_read(&ns->persistent_keyring_register_sem);
-+
-+ if (persistent_ref)
-+ goto found;
-+ }
-+
-+ /* It wasn't in the register, so we'll need to create it. We might
-+ * also need to create the register.
-+ */
-+ down_write(&ns->persistent_keyring_register_sem);
-+ persistent_ref = key_create_persistent(ns, uid, &index_key);
-+ up_write(&ns->persistent_keyring_register_sem);
-+ if (!IS_ERR(persistent_ref))
-+ goto found;
-+
-+ return PTR_ERR(persistent_ref);
-+
-+found:
-+ ret = key_task_permission(persistent_ref, current_cred(), KEY_LINK);
-+ if (ret == 0) {
-+ persistent = key_ref_to_ptr(persistent_ref);
-+ ret = key_link(key_ref_to_ptr(dest_ref), persistent);
-+ if (ret == 0) {
-+ key_set_timeout(persistent, persistent_keyring_expiry);
-+ ret = persistent->serial;
-+ }
-+ }
-+
-+ key_ref_put(persistent_ref);
-+ return ret;
-+}
-+
-+/*
-+ * Get the persistent keyring for a specific UID and link it to the nominated
-+ * keyring.
-+ */
-+long keyctl_get_persistent(uid_t _uid, key_serial_t destid)
-+{
-+ struct user_namespace *ns = current_user_ns();
-+ key_ref_t dest_ref;
-+ kuid_t uid;
-+ long ret;
-+
-+ /* -1 indicates the current user */
-+ if (_uid == (uid_t)-1) {
-+ uid = current_uid();
-+ } else {
-+ uid = make_kuid(ns, _uid);
-+ if (!uid_valid(uid))
-+ return -EINVAL;
-+
-+ /* You can only see your own persistent cache if you're not
-+ * sufficiently privileged.
-+ */
-+ if (!uid_eq(uid, current_uid()) &&
-+ /* uid_eq(uid, current_suid()) && */
-+ !uid_eq(uid, current_euid()) &&
-+ /* uid_eq(uid, current_fsuid()) && */
-+ !ns_capable(ns, CAP_SETUID))
-+ return -EPERM;
-+ }
-+
-+ /* There must be a destination keyring */
-+ dest_ref = lookup_user_key(destid, KEY_LOOKUP_CREATE, KEY_WRITE);
-+ if (IS_ERR(dest_ref))
-+ return PTR_ERR(dest_ref);
-+ if (key_ref_to_ptr(dest_ref)->type != &key_type_keyring) {
-+ ret = -ENOTDIR;
-+ goto out_put_dest;
-+ }
-+
-+ ret = key_get_persistent(ns, uid, dest_ref);
-+
-+out_put_dest:
-+ key_ref_put(dest_ref);
-+ return ret;
-+}
-diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c
-index ee32d18..8c0af08 100644
---- a/security/keys/sysctl.c
-+++ b/security/keys/sysctl.c
-@@ -61,5 +61,16 @@ ctl_table key_sysctls[] = {
- .extra1 = (void *) &zero,
- .extra2 = (void *) &max,
- },
-+#ifdef CONFIG_PERSISTENT_KEYRINGS
-+ {
-+ .procname = "persistent_keyring_expiry",
-+ .data = &persistent_keyring_expiry,
-+ .maxlen = sizeof(unsigned),
-+ .mode = 0644,
-+ .proc_handler = proc_dointvec_minmax,
-+ .extra1 = (void *) &zero,
-+ .extra2 = (void *) &max,
-+ },
-+#endif
- { }
- };
---
-1.8.3.1
-