forked from rpms/kernel
		
	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. |   - Fedora secure boot support. | ||||||
|   - Dear Matthew, this is your fault.  Run sed already and get a new set out. |   - 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) ************ | **** Other stuff that should go upstream (in decreasing likelyhood) ************ | ||||||
| 
 | 
 | ||||||
| * defaults-acpi-video.patch | * defaults-acpi-video.patch | ||||||
|  | |||||||
| @ -2247,6 +2247,8 @@ CONFIG_TIFM_7XX1=m | |||||||
| CONFIG_TCG_TPM=m | CONFIG_TCG_TPM=m | ||||||
| CONFIG_TCG_TIS=m | CONFIG_TCG_TIS=m | ||||||
| # CONFIG_TCG_TIS_I2C_INFINEON is not set | # 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_NSC=m | ||||||
| CONFIG_TCG_ATMEL=m | CONFIG_TCG_ATMEL=m | ||||||
| # CONFIG_TCG_INFINEON is not set | # CONFIG_TCG_INFINEON is not set | ||||||
|  | |||||||
							
								
								
									
										18
									
								
								kernel.spec
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								kernel.spec
									
									
									
									
									
								
							| @ -95,7 +95,7 @@ Summary: The Linux kernel | |||||||
| # The rc snapshot level | # The rc snapshot level | ||||||
| %define rcrev 0 | %define rcrev 0 | ||||||
| # The git snapshot level | # The git snapshot level | ||||||
| %define gitrev 10 | %define gitrev 11 | ||||||
| # Set rpm version accordingly | # Set rpm version accordingly | ||||||
| %define rpmversion 3.%{upstream_sublevel}.0 | %define rpmversion 3.%{upstream_sublevel}.0 | ||||||
| %endif | %endif | ||||||
| @ -634,12 +634,6 @@ Patch800: crash-driver.patch | |||||||
| 
 | 
 | ||||||
| # crypto/ | # crypto/ | ||||||
| 
 | 
 | ||||||
| # keys |  | ||||||
| Patch900: keys-expand-keyring.patch |  | ||||||
| Patch901: keys-krb-support.patch |  | ||||||
| Patch902: keys-x509-improv.patch |  | ||||||
| Patch903: keyring-quota.patch |  | ||||||
| 
 |  | ||||||
| # secure boot | # secure boot | ||||||
| Patch1000: secure-modules.patch | Patch1000: secure-modules.patch | ||||||
| Patch1001: modsign-uefi.patch | Patch1001: modsign-uefi.patch | ||||||
| @ -1337,12 +1331,6 @@ ApplyPatch crash-driver.patch | |||||||
| 
 | 
 | ||||||
| # crypto/ | # crypto/ | ||||||
| 
 | 
 | ||||||
| # keys |  | ||||||
| ApplyPatch keys-expand-keyring.patch |  | ||||||
| ApplyPatch keys-krb-support.patch |  | ||||||
| ApplyPatch keys-x509-improv.patch |  | ||||||
| ApplyPatch keyring-quota.patch |  | ||||||
| 
 |  | ||||||
| # secure boot | # secure boot | ||||||
| ApplyPatch secure-modules.patch | ApplyPatch secure-modules.patch | ||||||
| ApplyPatch modsign-uefi.patch | ApplyPatch modsign-uefi.patch | ||||||
| @ -2210,6 +2198,10 @@ fi | |||||||
| #                                    ||----w | | #                                    ||----w | | ||||||
| #                                    ||     || | #                                    ||     || | ||||||
| %changelog | %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> | * Thu Nov 21 2013 Peter Robinson <pbrobinson@fedoraproject.org> | ||||||
| - Some minor ARM config updates | - 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