@@ -857,6 +857,32 @@ The keyctl syscall functions are:
supported, error ENOKEY if the key could not be found, or error
EACCES if the key is not readable by the caller.
+ (*) Restrict keyring linkage
+
+ long keyctl(KEYCTL_RESTRICT_KEYRING, key_serial_t keyring,
+ char *restriction);
+
+ An existing keyring can restrict linkage of additional keys by evaluating
+ the contents of the key according to a restriction scheme.
+
+ "keyring" is the key ID for an existing keyring to apply a restriction
+ to. It may be empty or may already have keys linked. Existing linked keys
+ will remain in the keyring even if the new restriction would reject them.
+
+ "restriction" is a string describing how key linkage is to be restricted,
+ in the format:
+
+ "<type>:<options>"
+
+ "type" is a registered key type. "options" vary depending on the key type,
+ and are passed to the lookup_restrict() function for the requested type.
+ The options may specify a method and relevant data for the restriction
+ such as signature verification or constraints on key payload. If the
+ requested key type is unregistered, no keys may be added to the keyring.
+
+ To apply a keyring restriction the process must have Set Attribute
+ permission and the keyring must not be previously restricted.
+
===============
KERNEL SERVICES
===============
@@ -219,7 +219,7 @@ struct key {
/* This is set on a keyring to restrict the addition of a link to a key
* to it. If this structure isn't provided then it is assumed that the
* keyring is open to any addition. It is ignored for non-keyring
- * keys.
+ * keys. Only set this value using key_alloc() or keyring_restrict().
*
* This is intended for use with rings of trusted keys whereby addition
* to the keyring needs to be controlled. KEY_ALLOC_BYPASS_RESTRICTION
@@ -328,6 +328,8 @@ extern key_ref_t keyring_search(key_ref_t keyring,
extern int keyring_add_key(struct key *keyring,
struct key *key);
+extern int keyring_restrict(key_ref_t keyring, char *restriction);
+
extern struct key *key_lookup(key_serial_t id);
static inline key_serial_t key_serial(const struct key *key)
@@ -60,6 +60,7 @@
#define KEYCTL_INVALIDATE 21 /* invalidate a key */
#define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */
#define KEYCTL_DH_COMPUTE 23 /* Compute Diffie-Hellman values */
+#define KEYCTL_RESTRICT_KEYRING 29 /* Restrict keys allowed to link to a keyring */
/* keyctl structures */
struct keyctl_dh_params {
@@ -136,6 +136,9 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
return keyctl_dh_compute(compat_ptr(arg2), compat_ptr(arg3),
arg4, compat_ptr(arg5));
+ case KEYCTL_RESTRICT_KEYRING:
+ return keyctl_restrict_keyring(arg2, compat_ptr(arg3));
+
default:
return -EOPNOTSUPP;
}
@@ -250,6 +250,8 @@ struct iov_iter;
extern long keyctl_instantiate_key_common(key_serial_t,
struct iov_iter *,
key_serial_t);
+extern long keyctl_restrict_keyring(key_serial_t id,
+ const char __user *_restriction);
#ifdef CONFIG_PERSISTENT_KEYRINGS
extern long keyctl_get_persistent(uid_t, key_serial_t);
extern unsigned persistent_keyring_expiry;
@@ -1581,6 +1581,43 @@ long keyctl_session_to_parent(void)
}
/*
+ * Apply a restriction to a given keyring.
+ *
+ * The caller must have Setattr permission to change keyring restrictions.
+ *
+ * The requested restriction may be a NULL pointer, to reject all attempts
+ * to link to the keyring, or a string describing the restriction.
+ *
+ * Returns 0 if successful.
+ */
+long keyctl_restrict_keyring(key_serial_t id, const char __user *_restriction)
+{
+ key_ref_t key_ref;
+ char *restriction = NULL;
+ long ret;
+
+ key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR);
+ if (IS_ERR(key_ref))
+ return PTR_ERR(key_ref);
+
+ if (_restriction) {
+ restriction = strndup_user(_restriction, PAGE_SIZE);
+ if (IS_ERR(restriction)) {
+ ret = PTR_ERR(restriction);
+ goto error;
+ }
+ }
+
+ ret = keyring_restrict(key_ref, restriction);
+ kfree(restriction);
+
+error:
+ key_ref_put(key_ref);
+
+ return ret;
+}
+
+/*
* The key control system call
*/
SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
@@ -1691,6 +1728,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
(char __user *) arg3, (size_t) arg4,
(void __user *) arg5);
+ case KEYCTL_RESTRICT_KEYRING:
+ return keyctl_restrict_keyring((key_serial_t) arg2, (char __user *) arg3);
+
default:
return -EOPNOTSUPP;
}
@@ -949,6 +949,82 @@ key_ref_t keyring_search(key_ref_t keyring,
}
EXPORT_SYMBOL(keyring_search);
+static struct key_restriction *keyring_restriction_alloc(
+ key_restrict_link_func_t check)
+{
+ struct key_restriction *keyres =
+ kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
+
+ if (!keyres)
+ return ERR_PTR(-ENOMEM);
+
+ keyres->check = check;
+
+ return keyres;
+}
+
+/**
+ * keyring_restrict - Look up and apply a restriction to a keyring
+ *
+ * @keyring: The keyring to be restricted
+ * @restriction: The restriction options to apply to the keyring
+ */
+int keyring_restrict(key_ref_t keyring_ref, char *restriction)
+{
+ struct key *keyring;
+ char *type_name;
+ struct key_type *restrict_type = NULL;
+ struct key_restriction *restrict_link;
+ int ret;
+
+ keyring = key_ref_to_ptr(keyring_ref);
+ key_check(keyring);
+
+ if (keyring->type != &key_type_keyring)
+ return -ENOTDIR;
+
+ type_name = strsep(&restriction, ":");
+
+ if (!type_name) {
+ restrict_link = keyring_restriction_alloc(restrict_link_reject);
+ } else {
+ restrict_type = key_type_lookup(type_name);
+
+ if (IS_ERR(restrict_type))
+ return PTR_ERR(restrict_type);
+
+ if (!restrict_type->lookup_restrict) {
+ ret = -ENOENT;
+ goto error;
+ }
+
+ restrict_link = restrict_type->lookup_restrict(restriction);
+ if (IS_ERR(restrict_link)) {
+ ret = PTR_ERR(restrict_link);
+ goto error;
+ }
+ }
+
+ down_write(&keyring->sem);
+ if (!keyring->restrict_link) {
+ keyring->restrict_link = restrict_link;
+ ret = 0;
+ } else {
+ if (restrict_link->free_data)
+ restrict_link->free_data(restrict_link->data);
+
+ kfree(restrict_link);
+ ret = -EEXIST;
+ }
+ up_write(&keyring->sem);
+
+error:
+ key_type_put(restrict_type);
+
+ return ret;
+}
+EXPORT_SYMBOL(keyring_restrict);
+
/*
* Search the given keyring for a key that might be updated.
*
Keyrings recently gained restrict_link capabilities that allow individual keys to be validated prior to linking. This functionality was only available using internal kernel APIs. With the KEYCTL_RESTRICT_KEYRING command existing keyrings can be configured to check the content of keys before they are linked, and then allow or disallow linkage of that key to the keyring. To restrict a keyring, call: keyctl(KEYCTL_RESTRICT_KEYRING, key_serial_t keyring, char *restriction) where 'restriction' is a string of format: "<key type>[:<restriction options>]" The restriction option syntax is specific to each key type. Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> --- Documentation/security/keys.txt | 26 ++++++++++++++ include/linux/key.h | 4 ++- include/uapi/linux/keyctl.h | 1 + security/keys/compat.c | 3 ++ security/keys/internal.h | 2 ++ security/keys/keyctl.c | 40 ++++++++++++++++++++++ security/keys/keyring.c | 76 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 151 insertions(+), 1 deletion(-)