diff options
author | Josh Boyer <jwboyer@fedoraproject.org> | 2013-11-22 10:48:04 -0500 |
---|---|---|
committer | Josh Boyer <jwboyer@fedoraproject.org> | 2013-11-22 10:48:04 -0500 |
commit | 4ef7d96463ed96314e05a7d706a3e217246e28a5 (patch) | |
tree | 71a55913019a62af5b31f8d54acb917d5987cc97 /keys-krb-support.patch | |
parent | 464a3b821827ab828737b633ebb9964e1c71e910 (diff) | |
download | kernel-4ef7d96463ed96314e05a7d706a3e217246e28a5.tar.gz kernel-4ef7d96463ed96314e05a7d706a3e217246e28a5.tar.xz kernel-4ef7d96463ed96314e05a7d706a3e217246e28a5.zip |
Linux v3.12-11097-ga5d6e63
- Drop all the keys-* patches because they were merged upstream. Yay!
Diffstat (limited to 'keys-krb-support.patch')
-rw-r--r-- | keys-krb-support.patch | 748 |
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 - |