Linux v3.12-11097-ga5d6e63
- Drop all the keys-* patches because they were merged upstream. Yay!
This commit is contained in:
parent
464a3b8218
commit
4ef7d96463
@ -20,12 +20,6 @@ https://dev.openwrt.org/browser/trunk/package/mac80211/patches/552-ath9k_rx_dma_
|
||||
- Fedora secure boot support.
|
||||
- Dear Matthew, this is your fault. Run sed already and get a new set out.
|
||||
|
||||
* keys-expand-keyring.patch
|
||||
* keys-krb-support.patch
|
||||
* keys-x509-improv.patch
|
||||
* keyring-quota.patch
|
||||
- I believe these are all now queued for 3.13 in James Morris' tree.
|
||||
|
||||
**** Other stuff that should go upstream (in decreasing likelyhood) ************
|
||||
|
||||
* defaults-acpi-video.patch
|
||||
|
@ -2247,6 +2247,8 @@ CONFIG_TIFM_7XX1=m
|
||||
CONFIG_TCG_TPM=m
|
||||
CONFIG_TCG_TIS=m
|
||||
# CONFIG_TCG_TIS_I2C_INFINEON is not set
|
||||
# CONFIG_TCG_TIS_I2C_ATMEL is not set
|
||||
# CONFIG_TCG_TIS_I2C_NUVOTON is not set
|
||||
CONFIG_TCG_NSC=m
|
||||
CONFIG_TCG_ATMEL=m
|
||||
# CONFIG_TCG_INFINEON is not set
|
||||
|
18
kernel.spec
18
kernel.spec
@ -95,7 +95,7 @@ Summary: The Linux kernel
|
||||
# The rc snapshot level
|
||||
%define rcrev 0
|
||||
# The git snapshot level
|
||||
%define gitrev 10
|
||||
%define gitrev 11
|
||||
# Set rpm version accordingly
|
||||
%define rpmversion 3.%{upstream_sublevel}.0
|
||||
%endif
|
||||
@ -634,12 +634,6 @@ Patch800: crash-driver.patch
|
||||
|
||||
# crypto/
|
||||
|
||||
# keys
|
||||
Patch900: keys-expand-keyring.patch
|
||||
Patch901: keys-krb-support.patch
|
||||
Patch902: keys-x509-improv.patch
|
||||
Patch903: keyring-quota.patch
|
||||
|
||||
# secure boot
|
||||
Patch1000: secure-modules.patch
|
||||
Patch1001: modsign-uefi.patch
|
||||
@ -1337,12 +1331,6 @@ ApplyPatch crash-driver.patch
|
||||
|
||||
# crypto/
|
||||
|
||||
# keys
|
||||
ApplyPatch keys-expand-keyring.patch
|
||||
ApplyPatch keys-krb-support.patch
|
||||
ApplyPatch keys-x509-improv.patch
|
||||
ApplyPatch keyring-quota.patch
|
||||
|
||||
# secure boot
|
||||
ApplyPatch secure-modules.patch
|
||||
ApplyPatch modsign-uefi.patch
|
||||
@ -2210,6 +2198,10 @@ fi
|
||||
# ||----w |
|
||||
# || ||
|
||||
%changelog
|
||||
* Fri Nov 22 2013 Josh Boyer <jwboyer@fedoraproject.org> - 3.13.0-0.rc0.git11.1
|
||||
- Linux v3.12-11097-ga5d6e63
|
||||
- Drop all the keys-* patches because they were merged upstream. Yay!
|
||||
|
||||
* Thu Nov 21 2013 Peter Robinson <pbrobinson@fedoraproject.org>
|
||||
- Some minor ARM config updates
|
||||
|
||||
|
@ -1,104 +0,0 @@
|
||||
commit cb3bd4d9775d833501826832fd1562af19f8182d
|
||||
Author: David Howells <dhowells@redhat.com>
|
||||
Date: Fri Oct 18 17:30:30 2013 +0100
|
||||
|
||||
KEYS: Fix keyring quota misaccounting on key replacement and unlink
|
||||
|
||||
If a key is displaced from a keyring by a matching one, then four more bytes
|
||||
of quota are allocated to the keyring - despite the fact that the keyring does
|
||||
not change in size.
|
||||
|
||||
Further, when a key is unlinked from a keyring, the four bytes of quota
|
||||
allocated the link isn't recovered and returned to the user's pool.
|
||||
|
||||
The first can be tested by repeating:
|
||||
|
||||
keyctl add big_key a fred @s
|
||||
cat /proc/key-users
|
||||
|
||||
(Don't put it in a shell loop otherwise the garbage collector won't have time
|
||||
to clear the displaced keys, thus affecting the result).
|
||||
|
||||
This was causing the kerberos keyring to run out of room fairly quickly.
|
||||
|
||||
The second can be tested by:
|
||||
|
||||
cat /proc/key-users
|
||||
a=`keyctl add user a a @s`
|
||||
cat /proc/key-users
|
||||
keyctl unlink $a
|
||||
sleep 1 # Give RCU a chance to delete the key
|
||||
cat /proc/key-users
|
||||
|
||||
assuming no system activity that otherwise adds/removes keys, the amount of
|
||||
key data allocated should go up (say 40/20000 -> 47/20000) and then return to
|
||||
the original value at the end.
|
||||
|
||||
Reported-by: Stephen Gallagher <sgallagh@redhat.com>
|
||||
Signed-off-by: David Howells <dhowells@redhat.com>
|
||||
|
||||
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
|
||||
index 8c05ebd..d80311e 100644
|
||||
--- a/security/keys/keyring.c
|
||||
+++ b/security/keys/keyring.c
|
||||
@@ -1063,12 +1063,6 @@ int __key_link_begin(struct key *keyring,
|
||||
if (index_key->type == &key_type_keyring)
|
||||
down_write(&keyring_serialise_link_sem);
|
||||
|
||||
- /* check that we aren't going to overrun the user's quota */
|
||||
- ret = key_payload_reserve(keyring,
|
||||
- keyring->datalen + KEYQUOTA_LINK_BYTES);
|
||||
- if (ret < 0)
|
||||
- goto error_sem;
|
||||
-
|
||||
/* Create an edit script that will insert/replace the key in the
|
||||
* keyring tree.
|
||||
*/
|
||||
@@ -1078,17 +1072,25 @@ int __key_link_begin(struct key *keyring,
|
||||
NULL);
|
||||
if (IS_ERR(edit)) {
|
||||
ret = PTR_ERR(edit);
|
||||
- goto error_quota;
|
||||
+ goto error_sem;
|
||||
+ }
|
||||
+
|
||||
+ /* If we're not replacing a link in-place then we're going to need some
|
||||
+ * extra quota.
|
||||
+ */
|
||||
+ if (!edit->dead_leaf) {
|
||||
+ ret = key_payload_reserve(keyring,
|
||||
+ keyring->datalen + KEYQUOTA_LINK_BYTES);
|
||||
+ if (ret < 0)
|
||||
+ goto error_cancel;
|
||||
}
|
||||
|
||||
*_edit = edit;
|
||||
kleave(" = 0");
|
||||
return 0;
|
||||
|
||||
-error_quota:
|
||||
- /* undo the quota changes */
|
||||
- key_payload_reserve(keyring,
|
||||
- keyring->datalen - KEYQUOTA_LINK_BYTES);
|
||||
+error_cancel:
|
||||
+ assoc_array_cancel_edit(edit);
|
||||
error_sem:
|
||||
if (index_key->type == &key_type_keyring)
|
||||
up_write(&keyring_serialise_link_sem);
|
||||
@@ -1146,7 +1148,7 @@ void __key_link_end(struct key *keyring,
|
||||
if (index_key->type == &key_type_keyring)
|
||||
up_write(&keyring_serialise_link_sem);
|
||||
|
||||
- if (edit) {
|
||||
+ if (edit && !edit->dead_leaf) {
|
||||
key_payload_reserve(keyring,
|
||||
keyring->datalen - KEYQUOTA_LINK_BYTES);
|
||||
assoc_array_cancel_edit(edit);
|
||||
@@ -1243,6 +1245,7 @@ int key_unlink(struct key *keyring, struct key *key)
|
||||
goto error;
|
||||
|
||||
assoc_array_apply_edit(edit);
|
||||
+ key_payload_reserve(keyring, keyring->datalen - KEYQUOTA_LINK_BYTES);
|
||||
ret = 0;
|
||||
|
||||
error:
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user