|
@@ -412,8 +412,7 @@ EXPORT_SYMBOL(key_payload_reserve);
|
|
|
* key_construction_mutex.
|
|
|
*/
|
|
|
static int __key_instantiate_and_link(struct key *key,
|
|
|
- const void *data,
|
|
|
- size_t datalen,
|
|
|
+ struct key_preparsed_payload *prep,
|
|
|
struct key *keyring,
|
|
|
struct key *authkey,
|
|
|
unsigned long *_prealloc)
|
|
@@ -431,7 +430,7 @@ static int __key_instantiate_and_link(struct key *key,
|
|
|
/* can't instantiate twice */
|
|
|
if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
|
|
|
/* instantiate the key */
|
|
|
- ret = key->type->instantiate(key, data, datalen);
|
|
|
+ ret = key->type->instantiate(key, prep);
|
|
|
|
|
|
if (ret == 0) {
|
|
|
/* mark the key as being instantiated */
|
|
@@ -482,22 +481,37 @@ int key_instantiate_and_link(struct key *key,
|
|
|
struct key *keyring,
|
|
|
struct key *authkey)
|
|
|
{
|
|
|
+ struct key_preparsed_payload prep;
|
|
|
unsigned long prealloc;
|
|
|
int ret;
|
|
|
|
|
|
+ memset(&prep, 0, sizeof(prep));
|
|
|
+ prep.data = data;
|
|
|
+ prep.datalen = datalen;
|
|
|
+ prep.quotalen = key->type->def_datalen;
|
|
|
+ if (key->type->preparse) {
|
|
|
+ ret = key->type->preparse(&prep);
|
|
|
+ if (ret < 0)
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
if (keyring) {
|
|
|
ret = __key_link_begin(keyring, key->type, key->description,
|
|
|
&prealloc);
|
|
|
if (ret < 0)
|
|
|
- return ret;
|
|
|
+ goto error_free_preparse;
|
|
|
}
|
|
|
|
|
|
- ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey,
|
|
|
+ ret = __key_instantiate_and_link(key, &prep, keyring, authkey,
|
|
|
&prealloc);
|
|
|
|
|
|
if (keyring)
|
|
|
__key_link_end(keyring, key->type, prealloc);
|
|
|
|
|
|
+error_free_preparse:
|
|
|
+ if (key->type->preparse)
|
|
|
+ key->type->free_preparse(&prep);
|
|
|
+error:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -706,7 +720,7 @@ void key_type_put(struct key_type *ktype)
|
|
|
* if we get an error.
|
|
|
*/
|
|
|
static inline key_ref_t __key_update(key_ref_t key_ref,
|
|
|
- const void *payload, size_t plen)
|
|
|
+ struct key_preparsed_payload *prep)
|
|
|
{
|
|
|
struct key *key = key_ref_to_ptr(key_ref);
|
|
|
int ret;
|
|
@@ -722,7 +736,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
|
|
|
|
|
|
down_write(&key->sem);
|
|
|
|
|
|
- ret = key->type->update(key, payload, plen);
|
|
|
+ ret = key->type->update(key, prep);
|
|
|
if (ret == 0)
|
|
|
/* updating a negative key instantiates it */
|
|
|
clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
|
|
@@ -774,6 +788,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
|
|
unsigned long flags)
|
|
|
{
|
|
|
unsigned long prealloc;
|
|
|
+ struct key_preparsed_payload prep;
|
|
|
const struct cred *cred = current_cred();
|
|
|
struct key_type *ktype;
|
|
|
struct key *keyring, *key = NULL;
|
|
@@ -789,8 +804,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
|
|
}
|
|
|
|
|
|
key_ref = ERR_PTR(-EINVAL);
|
|
|
- if (!ktype->match || !ktype->instantiate)
|
|
|
- goto error_2;
|
|
|
+ if (!ktype->match || !ktype->instantiate ||
|
|
|
+ (!description && !ktype->preparse))
|
|
|
+ goto error_put_type;
|
|
|
|
|
|
keyring = key_ref_to_ptr(keyring_ref);
|
|
|
|
|
@@ -798,18 +814,37 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
|
|
|
|
|
key_ref = ERR_PTR(-ENOTDIR);
|
|
|
if (keyring->type != &key_type_keyring)
|
|
|
- goto error_2;
|
|
|
+ goto error_put_type;
|
|
|
+
|
|
|
+ memset(&prep, 0, sizeof(prep));
|
|
|
+ prep.data = payload;
|
|
|
+ prep.datalen = plen;
|
|
|
+ prep.quotalen = ktype->def_datalen;
|
|
|
+ if (ktype->preparse) {
|
|
|
+ ret = ktype->preparse(&prep);
|
|
|
+ if (ret < 0) {
|
|
|
+ key_ref = ERR_PTR(ret);
|
|
|
+ goto error_put_type;
|
|
|
+ }
|
|
|
+ if (!description)
|
|
|
+ description = prep.description;
|
|
|
+ key_ref = ERR_PTR(-EINVAL);
|
|
|
+ if (!description)
|
|
|
+ goto error_free_prep;
|
|
|
+ }
|
|
|
|
|
|
ret = __key_link_begin(keyring, ktype, description, &prealloc);
|
|
|
- if (ret < 0)
|
|
|
- goto error_2;
|
|
|
+ if (ret < 0) {
|
|
|
+ key_ref = ERR_PTR(ret);
|
|
|
+ goto error_free_prep;
|
|
|
+ }
|
|
|
|
|
|
/* if we're going to allocate a new key, we're going to have
|
|
|
* to modify the keyring */
|
|
|
ret = key_permission(keyring_ref, KEY_WRITE);
|
|
|
if (ret < 0) {
|
|
|
key_ref = ERR_PTR(ret);
|
|
|
- goto error_3;
|
|
|
+ goto error_link_end;
|
|
|
}
|
|
|
|
|
|
/* if it's possible to update this type of key, search for an existing
|
|
@@ -840,25 +875,27 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
|
|
perm, flags);
|
|
|
if (IS_ERR(key)) {
|
|
|
key_ref = ERR_CAST(key);
|
|
|
- goto error_3;
|
|
|
+ goto error_link_end;
|
|
|
}
|
|
|
|
|
|
/* instantiate it and link it into the target keyring */
|
|
|
- ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL,
|
|
|
- &prealloc);
|
|
|
+ ret = __key_instantiate_and_link(key, &prep, keyring, NULL, &prealloc);
|
|
|
if (ret < 0) {
|
|
|
key_put(key);
|
|
|
key_ref = ERR_PTR(ret);
|
|
|
- goto error_3;
|
|
|
+ goto error_link_end;
|
|
|
}
|
|
|
|
|
|
key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
|
|
|
|
|
|
- error_3:
|
|
|
+error_link_end:
|
|
|
__key_link_end(keyring, ktype, prealloc);
|
|
|
- error_2:
|
|
|
+error_free_prep:
|
|
|
+ if (ktype->preparse)
|
|
|
+ ktype->free_preparse(&prep);
|
|
|
+error_put_type:
|
|
|
key_type_put(ktype);
|
|
|
- error:
|
|
|
+error:
|
|
|
return key_ref;
|
|
|
|
|
|
found_matching_key:
|
|
@@ -866,10 +903,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
|
|
* - we can drop the locks first as we have the key pinned
|
|
|
*/
|
|
|
__key_link_end(keyring, ktype, prealloc);
|
|
|
- key_type_put(ktype);
|
|
|
|
|
|
- key_ref = __key_update(key_ref, payload, plen);
|
|
|
- goto error;
|
|
|
+ key_ref = __key_update(key_ref, &prep);
|
|
|
+ goto error_free_prep;
|
|
|
}
|
|
|
EXPORT_SYMBOL(key_create_or_update);
|
|
|
|
|
@@ -888,6 +924,7 @@ EXPORT_SYMBOL(key_create_or_update);
|
|
|
*/
|
|
|
int key_update(key_ref_t key_ref, const void *payload, size_t plen)
|
|
|
{
|
|
|
+ struct key_preparsed_payload prep;
|
|
|
struct key *key = key_ref_to_ptr(key_ref);
|
|
|
int ret;
|
|
|
|
|
@@ -900,18 +937,31 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
|
|
|
|
|
|
/* attempt to update it if supported */
|
|
|
ret = -EOPNOTSUPP;
|
|
|
- if (key->type->update) {
|
|
|
- down_write(&key->sem);
|
|
|
-
|
|
|
- ret = key->type->update(key, payload, plen);
|
|
|
- if (ret == 0)
|
|
|
- /* updating a negative key instantiates it */
|
|
|
- clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
|
|
|
+ if (!key->type->update)
|
|
|
+ goto error;
|
|
|
|
|
|
- up_write(&key->sem);
|
|
|
+ memset(&prep, 0, sizeof(prep));
|
|
|
+ prep.data = payload;
|
|
|
+ prep.datalen = plen;
|
|
|
+ prep.quotalen = key->type->def_datalen;
|
|
|
+ if (key->type->preparse) {
|
|
|
+ ret = key->type->preparse(&prep);
|
|
|
+ if (ret < 0)
|
|
|
+ goto error;
|
|
|
}
|
|
|
|
|
|
- error:
|
|
|
+ down_write(&key->sem);
|
|
|
+
|
|
|
+ ret = key->type->update(key, &prep);
|
|
|
+ if (ret == 0)
|
|
|
+ /* updating a negative key instantiates it */
|
|
|
+ clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
|
|
|
+
|
|
|
+ up_write(&key->sem);
|
|
|
+
|
|
|
+ if (key->type->preparse)
|
|
|
+ key->type->free_preparse(&prep);
|
|
|
+error:
|
|
|
return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL(key_update);
|