From a4e3b8d79a5c6d40f4a9703abf7fe3abcc6c3b8d Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Thu, 22 May 2014 14:02:23 -0400 Subject: KEYS: special dot prefixed keyring name bug fix Dot prefixed keyring names are supposed to be reserved for the kernel, but add_key() calls key_get_type_from_user(), which incorrectly verifies the 'type' field, not the 'description' field. This patch verifies the 'description' field isn't dot prefixed, when creating a new keyring, and removes the dot prefix test in key_get_type_from_user(). Changelog v6: - whitespace and other cleanup Changelog v5: - Only prevent userspace from creating a dot prefixed keyring, not regular keys - Dmitry Reported-by: Dmitry Kasatkin Signed-off-by: Mimi Zohar Acked-by: David Howells --- security/keys/keyctl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'security/keys') diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index cd5bd0cef25d..8a8c23357291 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -37,8 +37,6 @@ static int key_get_type_from_user(char *type, return ret; if (ret == 0 || ret >= len) return -EINVAL; - if (type[0] == '.') - return -EPERM; type[len - 1] = '\0'; return 0; } @@ -86,6 +84,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, if (!*description) { kfree(description); description = NULL; + } else if ((description[0] == '.') && + (strncmp(type, "keyring", 7) == 0)) { + ret = -EPERM; + goto error2; } } -- cgit v1.2.3 From 0c7774abb41bd00d5836d9ba098825a40fa94133 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 17 Jul 2014 20:45:08 +0100 Subject: KEYS: Allow special keys (eg. DNS results) to be invalidated by CAP_SYS_ADMIN Special kernel keys, such as those used to hold DNS results for AFS, CIFS and NFS and those used to hold idmapper results for NFS, used to be 'invalidateable' with key_revoke(). However, since the default permissions for keys were reduced: Commit: 96b5c8fea6c0861621051290d705ec2e971963f1 KEYS: Reduce initial permissions on keys it has become impossible to do this. Add a key flag (KEY_FLAG_ROOT_CAN_INVAL) that will permit a key to be invalidated by root. This should not be used for system keyrings as the garbage collector will try and remove any invalidate key. For system keyrings, KEY_FLAG_ROOT_CAN_CLEAR can be used instead. After this, from userspace, keyctl_invalidate() and "keyctl invalidate" can be used by any possessor of CAP_SYS_ADMIN (typically root) to invalidate DNS and idmapper keys. Invalidated keys are immediately garbage collected and will be immediately rerequested if needed again. Signed-off-by: David Howells Tested-by: Steve Dickson --- fs/nfs/idmap.c | 2 ++ include/linux/key.h | 1 + net/dns_resolver/dns_query.c | 1 + security/keys/keyctl.c | 15 ++++++++++++++- 4 files changed, 18 insertions(+), 1 deletion(-) (limited to 'security/keys') diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 567983d2c0eb..b7458d77f511 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -282,6 +282,8 @@ static struct key *nfs_idmap_request_key(const char *name, size_t namelen, desc, "", 0, idmap); mutex_unlock(&idmap->idmap_mutex); } + if (!IS_ERR(rkey)) + set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); kfree(desc); return rkey; diff --git a/include/linux/key.h b/include/linux/key.h index 017b0826642f..e37a4d807185 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -170,6 +170,7 @@ struct key { #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ #define KEY_FLAG_TRUSTED 8 /* set if key is trusted */ #define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */ +#define KEY_FLAG_ROOT_CAN_INVAL 11 /* set if key can be invalidated by root without permission */ /* the key type and key description string * - the desc is used to match a key against search criteria diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c index 9acec61f5433..9a32f55cf9b9 100644 --- a/net/dns_resolver/dns_query.c +++ b/net/dns_resolver/dns_query.c @@ -129,6 +129,7 @@ int dns_query(const char *type, const char *name, size_t namelen, } down_read(&rkey->sem); + set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); rkey->perm |= KEY_USR_VIEW; ret = key_validate(rkey); diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index cd5bd0cef25d..609f8d326ddc 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -404,12 +404,25 @@ long keyctl_invalidate_key(key_serial_t id) key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); + + /* Root is permitted to invalidate certain special keys */ + if (capable(CAP_SYS_ADMIN)) { + key_ref = lookup_user_key(id, 0, 0); + if (IS_ERR(key_ref)) + goto error; + if (test_bit(KEY_FLAG_ROOT_CAN_INVAL, + &key_ref_to_ptr(key_ref)->flags)) + goto invalidate; + goto error_put; + } + goto error; } +invalidate: key_invalidate(key_ref_to_ptr(key_ref)); ret = 0; - +error_put: key_ref_put(key_ref); error: kleave(" = %ld", ret); -- cgit v1.2.3 From 6a09d17bb66a533c165be81e8a4c3557f68e1a3b Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 18 Jul 2014 18:56:34 +0100 Subject: KEYS: Provide a generic instantiation function Provide a generic instantiation function for key types that use the preparse hook. This makes it easier to prereserve key quota before keyrings get locked to retain the new key. Signed-off-by: David Howells Acked-by: Steve Dickson Acked-by: Jeff Layton Reviewed-by: Sage Weil --- crypto/asymmetric_keys/asymmetric_type.c | 25 +------------------------ include/linux/key-type.h | 2 ++ security/keys/key.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 24 deletions(-) (limited to 'security/keys') diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index b77eb5304788..c1fe0fcee8e3 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -163,29 +163,6 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) kfree(prep->description); } -/* - * Instantiate a asymmetric_key defined key. The key was preparsed, so we just - * have to transfer the data here. - */ -static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep) -{ - int ret; - - pr_devel("==>%s()\n", __func__); - - ret = key_payload_reserve(key, prep->quotalen); - if (ret == 0) { - key->type_data.p[0] = prep->type_data[0]; - key->type_data.p[1] = prep->type_data[1]; - key->payload.data = prep->payload; - prep->type_data[0] = NULL; - prep->type_data[1] = NULL; - prep->payload = NULL; - } - pr_devel("<==%s() = %d\n", __func__, ret); - return ret; -} - /* * dispose of the data dangling from the corpse of a asymmetric key */ @@ -205,7 +182,7 @@ struct key_type key_type_asymmetric = { .name = "asymmetric", .preparse = asymmetric_key_preparse, .free_preparse = asymmetric_key_free_preparse, - .instantiate = asymmetric_key_instantiate, + .instantiate = generic_key_instantiate, .match = asymmetric_key_match, .destroy = asymmetric_key_destroy, .describe = asymmetric_key_describe, diff --git a/include/linux/key-type.h b/include/linux/key-type.h index a74c3a84dfdd..88503dca2a57 100644 --- a/include/linux/key-type.h +++ b/include/linux/key-type.h @@ -159,5 +159,7 @@ static inline int key_negate_and_link(struct key *key, return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey); } +extern int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep); + #endif /* CONFIG_KEYS */ #endif /* _LINUX_KEY_TYPE_H */ diff --git a/security/keys/key.c b/security/keys/key.c index 2048a110e7f1..7c9acbf106b6 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -1023,6 +1023,36 @@ void key_invalidate(struct key *key) } EXPORT_SYMBOL(key_invalidate); +/** + * generic_key_instantiate - Simple instantiation of a key from preparsed data + * @key: The key to be instantiated + * @prep: The preparsed data to load. + * + * Instantiate a key from preparsed data. We assume we can just copy the data + * in directly and clear the old pointers. + * + * This can be pointed to directly by the key type instantiate op pointer. + */ +int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep) +{ + int ret; + + pr_devel("==>%s()\n", __func__); + + ret = key_payload_reserve(key, prep->quotalen); + if (ret == 0) { + key->type_data.p[0] = prep->type_data[0]; + key->type_data.p[1] = prep->type_data[1]; + rcu_assign_keypointer(key, prep->payload); + prep->type_data[0] = NULL; + prep->type_data[1] = NULL; + prep->payload = NULL; + } + pr_devel("<==%s() = %d\n", __func__, ret); + return ret; +} +EXPORT_SYMBOL(generic_key_instantiate); + /** * register_key_type - Register a type of key. * @ktype: The new key type. -- cgit v1.2.3 From fc7c70e0b6b637bbf6cf8b9cee547d5ae83899c9 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 18 Jul 2014 18:56:34 +0100 Subject: KEYS: struct key_preparsed_payload should have two payload pointers struct key_preparsed_payload should have two payload pointers to correspond with those in struct key. Signed-off-by: David Howells Acked-by: Steve Dickson Acked-by: Jeff Layton Reviewed-by: Sage Weil --- crypto/asymmetric_keys/asymmetric_type.c | 2 +- crypto/asymmetric_keys/x509_public_key.c | 2 +- include/linux/key-type.h | 2 +- security/keys/encrypted-keys/encrypted.c | 2 +- security/keys/key.c | 6 ++++-- 5 files changed, 8 insertions(+), 6 deletions(-) (limited to 'security/keys') diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index c1fe0fcee8e3..21960a4e74e8 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -156,7 +156,7 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) pr_devel("==>%s()\n", __func__); if (subtype) { - subtype->destroy(prep->payload); + subtype->destroy(prep->payload[0]); module_put(subtype->owner); } kfree(prep->type_data[1]); diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 382ef0d2ff2e..3fc8a0634ed7 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -177,7 +177,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) __module_get(public_key_subtype.owner); prep->type_data[0] = &public_key_subtype; prep->type_data[1] = cert->fingerprint; - prep->payload = cert->pub; + prep->payload[0] = cert->pub; prep->description = desc; prep->quotalen = 100; diff --git a/include/linux/key-type.h b/include/linux/key-type.h index 88503dca2a57..d2b4845d74bf 100644 --- a/include/linux/key-type.h +++ b/include/linux/key-type.h @@ -41,7 +41,7 @@ struct key_construction { struct key_preparsed_payload { char *description; /* Proposed key description (or NULL) */ void *type_data[2]; /* Private key-type data */ - void *payload; /* Proposed payload */ + void *payload[2]; /* Proposed payload */ const void *data; /* Raw data */ size_t datalen; /* Raw datalen */ size_t quotalen; /* Quota length for proposed payload */ diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 5fe443d120af..d252c5704f8a 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -811,7 +811,7 @@ static int encrypted_instantiate(struct key *key, goto out; } - rcu_assign_keypointer(key, epayload); + prep->payload[0] = epayload; out: kfree(datablob); return ret; diff --git a/security/keys/key.c b/security/keys/key.c index 7c9acbf106b6..03620a35a4dc 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -1043,10 +1043,12 @@ int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep) if (ret == 0) { key->type_data.p[0] = prep->type_data[0]; key->type_data.p[1] = prep->type_data[1]; - rcu_assign_keypointer(key, prep->payload); + rcu_assign_keypointer(key, prep->payload[0]); + key->payload.data2[1] = prep->payload[1]; prep->type_data[0] = NULL; prep->type_data[1] = NULL; - prep->payload = NULL; + prep->payload[0] = NULL; + prep->payload[1] = NULL; } pr_devel("<==%s() = %d\n", __func__, ret); return ret; -- cgit v1.2.3 From 7dfa0ca6a95de65b7a7760630cdbd7d30f204bfa Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 18 Jul 2014 18:56:34 +0100 Subject: KEYS: Allow expiry time to be set when preparsing a key Allow a key type's preparsing routine to set the expiry time for a key. Signed-off-by: David Howells Acked-by: Steve Dickson Acked-by: Jeff Layton Reviewed-by: Sage Weil --- Documentation/security/keys.txt | 10 +++++++--- include/linux/key-type.h | 1 + security/keys/key.c | 8 ++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'security/keys') diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt index a4c33f1a7c6d..315cf96a41a2 100644 --- a/Documentation/security/keys.txt +++ b/Documentation/security/keys.txt @@ -1150,20 +1150,24 @@ The structure has a number of fields, some of which are mandatory: const void *data; size_t datalen; size_t quotalen; + time_t expiry; }; Before calling the method, the caller will fill in data and datalen with the payload blob parameters; quotalen will be filled in with the default - quota size from the key type and the rest will be cleared. + quota size from the key type; expiry will be set to TIME_T_MAX and the + rest will be cleared. If a description can be proposed from the payload contents, that should be attached as a string to the description field. This will be used for the key description if the caller of add_key() passes NULL or "". The method can attach anything it likes to type_data[] and payload. These - are merely passed along to the instantiate() or update() operations. + are merely passed along to the instantiate() or update() operations. If + set, the expiry time will be applied to the key if it is instantiated from + this data. - The method should return 0 if success ful or a negative error code + The method should return 0 if successful or a negative error code otherwise. diff --git a/include/linux/key-type.h b/include/linux/key-type.h index d2b4845d74bf..44792ee649de 100644 --- a/include/linux/key-type.h +++ b/include/linux/key-type.h @@ -45,6 +45,7 @@ struct key_preparsed_payload { const void *data; /* Raw data */ size_t datalen; /* Raw datalen */ size_t quotalen; /* Quota length for proposed payload */ + time_t expiry; /* Expiry time of key */ bool trusted; /* True if key is trusted */ }; diff --git a/security/keys/key.c b/security/keys/key.c index 03620a35a4dc..755fb02df5af 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -437,6 +437,11 @@ static int __key_instantiate_and_link(struct key *key, /* disable the authorisation key */ if (authkey) key_revoke(authkey); + + if (prep->expiry != TIME_T_MAX) { + key->expiry = prep->expiry; + key_schedule_gc(prep->expiry + key_gc_delay); + } } } @@ -479,6 +484,7 @@ int key_instantiate_and_link(struct key *key, prep.data = data; prep.datalen = datalen; prep.quotalen = key->type->def_datalen; + prep.expiry = TIME_T_MAX; if (key->type->preparse) { ret = key->type->preparse(&prep); if (ret < 0) @@ -811,6 +817,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, prep.datalen = plen; prep.quotalen = index_key.type->def_datalen; prep.trusted = flags & KEY_ALLOC_TRUSTED; + prep.expiry = TIME_T_MAX; if (index_key.type->preparse) { ret = index_key.type->preparse(&prep); if (ret < 0) { @@ -941,6 +948,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) prep.data = payload; prep.datalen = plen; prep.quotalen = key->type->def_datalen; + prep.expiry = TIME_T_MAX; if (key->type->preparse) { ret = key->type->preparse(&prep); if (ret < 0) -- cgit v1.2.3 From 4d8c0250b841159b128785f7a7efbaff40cc8501 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 18 Jul 2014 18:56:34 +0100 Subject: KEYS: Call ->free_preparse() even after ->preparse() returns an error Call the ->free_preparse() key type op even after ->preparse() returns an error as it does cleaning up type stuff. Signed-off-by: David Howells Acked-by: Steve Dickson Acked-by: Jeff Layton Reviewed-by: Sage Weil --- Documentation/security/keys.txt | 4 +++- security/keys/key.c | 9 ++++----- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'security/keys') diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt index 315cf96a41a2..8727c194ca16 100644 --- a/Documentation/security/keys.txt +++ b/Documentation/security/keys.txt @@ -1176,7 +1176,9 @@ The structure has a number of fields, some of which are mandatory: This method is only required if the preparse() method is provided, otherwise it is unused. It cleans up anything attached to the description, type_data and payload fields of the key_preparsed_payload - struct as filled in by the preparse() method. + struct as filled in by the preparse() method. It will always be called + after preparse() returns successfully, even if instantiate() or update() + succeed. (*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep); diff --git a/security/keys/key.c b/security/keys/key.c index 755fb02df5af..b90a68c4e2c4 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -494,7 +494,7 @@ int key_instantiate_and_link(struct key *key, if (keyring) { ret = __key_link_begin(keyring, &key->index_key, &edit); if (ret < 0) - goto error_free_preparse; + goto error; } ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit); @@ -502,10 +502,9 @@ int key_instantiate_and_link(struct key *key, if (keyring) __key_link_end(keyring, &key->index_key, edit); -error_free_preparse: +error: if (key->type->preparse) key->type->free_preparse(&prep); -error: return ret; } @@ -822,7 +821,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ret = index_key.type->preparse(&prep); if (ret < 0) { key_ref = ERR_PTR(ret); - goto error_put_type; + goto error_free_prep; } if (!index_key.description) index_key.description = prep.description; @@ -964,9 +963,9 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) up_write(&key->sem); +error: if (key->type->preparse) key->type->free_preparse(&prep); -error: return ret; } EXPORT_SYMBOL(key_update); -- cgit v1.2.3 From f9167789df53f22af771fb6690a3d36aa21d74c5 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 18 Jul 2014 18:56:35 +0100 Subject: KEYS: user: Use key preparsing Make use of key preparsing in user-defined and logon keys so that quota size determination can take place prior to keyring locking when a key is being added. Also the idmapper key types need to change to match as they use the user-defined key type routines. Signed-off-by: David Howells Acked-by: Steve Dickson Acked-by: Jeff Layton --- fs/nfs/idmap.c | 8 ++++++-- include/keys/user-type.h | 3 ++- security/keys/user_defined.c | 41 ++++++++++++++++++++++------------------- 3 files changed, 30 insertions(+), 22 deletions(-) (limited to 'security/keys') diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 567983d2c0eb..59b217a3266d 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -174,7 +174,9 @@ static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen) static struct key_type key_type_id_resolver = { .name = "id_resolver", - .instantiate = user_instantiate, + .preparse = user_preparse, + .free_preparse = user_free_preparse, + .instantiate = generic_key_instantiate, .match = user_match, .revoke = user_revoke, .destroy = user_destroy, @@ -394,7 +396,9 @@ static const struct rpc_pipe_ops idmap_upcall_ops = { static struct key_type key_type_id_resolver_legacy = { .name = "id_legacy", - .instantiate = user_instantiate, + .preparse = user_preparse, + .free_preparse = user_free_preparse, + .instantiate = generic_key_instantiate, .match = user_match, .revoke = user_revoke, .destroy = user_destroy, diff --git a/include/keys/user-type.h b/include/keys/user-type.h index 5e452c84f1e6..3ab1873a4bfa 100644 --- a/include/keys/user-type.h +++ b/include/keys/user-type.h @@ -37,7 +37,8 @@ extern struct key_type key_type_logon; struct key_preparsed_payload; -extern int user_instantiate(struct key *key, struct key_preparsed_payload *prep); +extern int user_preparse(struct key_preparsed_payload *prep); +extern void user_free_preparse(struct key_preparsed_payload *prep); extern int user_update(struct key *key, struct key_preparsed_payload *prep); extern int user_match(const struct key *key, const void *criterion); extern void user_revoke(struct key *key); diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index faa2caeb593f..eee340011f2b 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c @@ -27,7 +27,9 @@ static int logon_vet_description(const char *desc); struct key_type key_type_user = { .name = "user", .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, - .instantiate = user_instantiate, + .preparse = user_preparse, + .free_preparse = user_free_preparse, + .instantiate = generic_key_instantiate, .update = user_update, .match = user_match, .revoke = user_revoke, @@ -47,7 +49,9 @@ EXPORT_SYMBOL_GPL(key_type_user); struct key_type key_type_logon = { .name = "logon", .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, - .instantiate = user_instantiate, + .preparse = user_preparse, + .free_preparse = user_free_preparse, + .instantiate = generic_key_instantiate, .update = user_update, .match = user_match, .revoke = user_revoke, @@ -58,38 +62,37 @@ struct key_type key_type_logon = { EXPORT_SYMBOL_GPL(key_type_logon); /* - * instantiate a user defined key + * Preparse a user defined key payload */ -int user_instantiate(struct key *key, struct key_preparsed_payload *prep) +int user_preparse(struct key_preparsed_payload *prep) { struct user_key_payload *upayload; size_t datalen = prep->datalen; - int ret; - ret = -EINVAL; if (datalen <= 0 || datalen > 32767 || !prep->data) - goto error; - - ret = key_payload_reserve(key, datalen); - if (ret < 0) - goto error; + return -EINVAL; - ret = -ENOMEM; upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); if (!upayload) - goto error; + return -ENOMEM; /* attach the data */ + prep->quotalen = datalen; + prep->payload[0] = upayload; upayload->datalen = datalen; memcpy(upayload->data, prep->data, datalen); - rcu_assign_keypointer(key, upayload); - ret = 0; - -error: - return ret; + return 0; } +EXPORT_SYMBOL_GPL(user_preparse); -EXPORT_SYMBOL_GPL(user_instantiate); +/* + * Free a preparse of a user defined key payload + */ +void user_free_preparse(struct key_preparsed_payload *prep) +{ + kfree(prep->payload[0]); +} +EXPORT_SYMBOL_GPL(user_free_preparse); /* * update a user defined key -- cgit v1.2.3 From 002edaf76f09af658241029817f5ef66f6bef5e4 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 18 Jul 2014 18:56:36 +0100 Subject: KEYS: big_key: Use key preparsing Make use of key preparsing in the big key type so that quota size determination can take place prior to keyring locking when a key is being added. Signed-off-by: David Howells Acked-by: Steve Dickson --- include/keys/big_key-type.h | 3 ++- security/keys/big_key.c | 41 +++++++++++++++++++++++++---------------- 2 files changed, 27 insertions(+), 17 deletions(-) (limited to 'security/keys') diff --git a/include/keys/big_key-type.h b/include/keys/big_key-type.h index d69bc8af3292..e0970a578188 100644 --- a/include/keys/big_key-type.h +++ b/include/keys/big_key-type.h @@ -16,7 +16,8 @@ extern struct key_type key_type_big_key; -extern int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep); +extern int big_key_preparse(struct key_preparsed_payload *prep); +extern void big_key_free_preparse(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); diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 8137b27d641d..c2f91a0cf889 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c @@ -34,7 +34,9 @@ MODULE_LICENSE("GPL"); struct key_type key_type_big_key = { .name = "big_key", .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, - .instantiate = big_key_instantiate, + .preparse = big_key_preparse, + .free_preparse = big_key_free_preparse, + .instantiate = generic_key_instantiate, .match = user_match, .revoke = big_key_revoke, .destroy = big_key_destroy, @@ -43,11 +45,11 @@ struct key_type key_type_big_key = { }; /* - * Instantiate a big key + * Preparse a big key */ -int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) +int big_key_preparse(struct key_preparsed_payload *prep) { - struct path *path = (struct path *)&key->payload.data2; + struct path *path = (struct path *)&prep->payload; struct file *file; ssize_t written; size_t datalen = prep->datalen; @@ -58,11 +60,9 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) goto error; /* Set an arbitrary quota */ - ret = key_payload_reserve(key, 16); - if (ret < 0) - goto error; + prep->quotalen = 16; - key->type_data.x[1] = datalen; + prep->type_data[1] = (void *)(unsigned long)datalen; if (datalen > BIG_KEY_FILE_THRESHOLD) { /* Create a shmem file to store the data in. This will permit the data @@ -73,7 +73,7 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) file = shmem_kernel_file_setup("", datalen, 0); if (IS_ERR(file)) { ret = PTR_ERR(file); - goto err_quota; + goto error; } written = kernel_write(file, prep->data, prep->datalen, 0); @@ -93,23 +93,32 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) } else { /* Just store the data in a buffer */ void *data = kmalloc(datalen, GFP_KERNEL); - if (!data) { - ret = -ENOMEM; - goto err_quota; - } + if (!data) + return -ENOMEM; - key->payload.data = memcpy(data, prep->data, prep->datalen); + prep->payload[0] = memcpy(data, prep->data, prep->datalen); } return 0; err_fput: fput(file); -err_quota: - key_payload_reserve(key, 0); error: return ret; } +/* + * Clear preparsement. + */ +void big_key_free_preparse(struct key_preparsed_payload *prep) +{ + if (prep->datalen > BIG_KEY_FILE_THRESHOLD) { + struct path *path = (struct path *)&prep->payload; + path_put(path); + } else { + kfree(prep->payload[0]); + } +} + /* * dispose of the links from a revoked keyring * - called with the key sem write-locked -- cgit v1.2.3 From 5d19e20b534ff4c17dfba792f1f9e33e1378e3f9 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 18 Jul 2014 18:56:36 +0100 Subject: KEYS: keyring: Provide key preparsing Provide key preparsing in the keyring so that we can make preparsing mandatory. For keyrings, however, only an empty payload is permitted. Signed-off-by: David Howells Acked-by: Steve Dickson Acked-by: Jeff Layton --- security/keys/keyring.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) (limited to 'security/keys') diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 9cf2575f0d97..8314a7d2104d 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -73,6 +73,8 @@ static inline unsigned keyring_hash(const char *desc) * can be treated as ordinary keys in addition to having their own special * operations. */ +static int keyring_preparse(struct key_preparsed_payload *prep); +static void keyring_free_preparse(struct key_preparsed_payload *prep); static int keyring_instantiate(struct key *keyring, struct key_preparsed_payload *prep); static void keyring_revoke(struct key *keyring); @@ -84,6 +86,8 @@ static long keyring_read(const struct key *keyring, struct key_type key_type_keyring = { .name = "keyring", .def_datalen = 0, + .preparse = keyring_preparse, + .free_preparse = keyring_free_preparse, .instantiate = keyring_instantiate, .match = user_match, .revoke = keyring_revoke, @@ -122,6 +126,21 @@ static void keyring_publish_name(struct key *keyring) } } +/* + * Preparse a keyring payload + */ +static int keyring_preparse(struct key_preparsed_payload *prep) +{ + return prep->datalen != 0 ? -EINVAL : 0; +} + +/* + * Free a preparse of a user defined key payload + */ +static void keyring_free_preparse(struct key_preparsed_payload *prep) +{ +} + /* * Initialise a keyring. * @@ -130,17 +149,10 @@ static void keyring_publish_name(struct key *keyring) static int keyring_instantiate(struct key *keyring, struct key_preparsed_payload *prep) { - int ret; - - ret = -EINVAL; - if (prep->datalen == 0) { - assoc_array_init(&keyring->keys); - /* make the keyring available by name if it has one */ - keyring_publish_name(keyring); - ret = 0; - } - - return ret; + assoc_array_init(&keyring->keys); + /* make the keyring available by name if it has one */ + keyring_publish_name(keyring); + return 0; } /* -- cgit v1.2.3 From f1dcde91a3503f68ef209667a8798ead2b50b02a Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 18 Jul 2014 18:56:36 +0100 Subject: KEYS: request_key_auth: Provide key preparsing Provide key preparsing for the request_key_auth key type so that we can make preparsing mandatory. This does nothing as this type can only be set up internally to the kernel. Signed-off-by: David Howells Acked-by: Steve Dickson Acked-by: Jeff Layton --- security/keys/request_key_auth.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'security/keys') diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 7495a93b4b90..842e6f410d50 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c @@ -20,6 +20,8 @@ #include "internal.h" #include +static int request_key_auth_preparse(struct key_preparsed_payload *); +static void request_key_auth_free_preparse(struct key_preparsed_payload *); static int request_key_auth_instantiate(struct key *, struct key_preparsed_payload *); static void request_key_auth_describe(const struct key *, struct seq_file *); @@ -33,6 +35,8 @@ static long request_key_auth_read(const struct key *, char __user *, size_t); struct key_type key_type_request_key_auth = { .name = ".request_key_auth", .def_datalen = sizeof(struct request_key_auth), + .preparse = request_key_auth_preparse, + .free_preparse = request_key_auth_free_preparse, .instantiate = request_key_auth_instantiate, .describe = request_key_auth_describe, .revoke = request_key_auth_revoke, @@ -40,6 +44,15 @@ struct key_type key_type_request_key_auth = { .read = request_key_auth_read, }; +int request_key_auth_preparse(struct key_preparsed_payload *prep) +{ + return 0; +} + +void request_key_auth_free_preparse(struct key_preparsed_payload *prep) +{ +} + /* * Instantiate a request-key authorisation key. */ -- cgit v1.2.3 From b64cc5fb85f38ae7ca3c67a8fea9ad8c0d068bfa Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Sat, 26 Jul 2014 23:21:02 -0400 Subject: KEYS: revert encrypted key change Commit fc7c70e "KEYS: struct key_preparsed_payload should have two payload pointers" erroneously modified encrypted-keys. This patch reverts the change to that file. Signed-off-by: Mimi Zohar Signed-off-by: David Howells --- security/keys/encrypted-keys/encrypted.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security/keys') diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index d252c5704f8a..5fe443d120af 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -811,7 +811,7 @@ static int encrypted_instantiate(struct key *key, goto out; } - prep->payload[0] = epayload; + rcu_assign_keypointer(key, epayload); out: kfree(datablob); return ret; -- cgit v1.2.3