Implement "keyctl control" for encrypted keys rather than trying to do this with the update method (which won't function correctly when add_key() tries to update an existing key).
Provide a command to change the master key: keyctl control <keyid> "encrypted change-master-key <m-key-id>" Signed-off-by: David Howells <dhowe...@redhat.com> --- security/keys/encrypted-keys/encrypted.c | 56 ++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 9e1e005c7596..f9e7b808fa47 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -884,6 +884,61 @@ out: } /* + * encrypted_control - control an encrypted key in a type-specific way + */ +static long encrypted_control(struct key *key, char *command, + char *reply, size_t reply_size) +{ + static const char expected_command[] = "encrypted change-master-key "; + struct encrypted_key_payload *epayload, *new_epayload; + char *new_master_desc = NULL; + const char *format = NULL; + size_t datalen; + int ret; + + if (memcmp(command, expected_command, sizeof(expected_command) - 1) != 0) + return -EINVAL; + command += sizeof(expected_command) - 1; + datalen = strlen(command); + + if (datalen <= 0 || datalen > 32767) + return -EINVAL; + + ret = datablob_parse(command, &format, &new_master_desc, NULL, NULL); + if (ret < 0) + return ret; + + down_write(&key->sem); + epayload = rcu_dereference_protected(key->payload.rcudata, &key->sem); + + ret = valid_master_desc(new_master_desc, epayload->master_desc); + if (ret < 0) { + up_write(&key->sem); + return ret; + } + + new_epayload = encrypted_key_alloc(key, epayload->format, + new_master_desc, epayload->datalen); + if (IS_ERR(new_epayload)) { + up_write(&key->sem); + return PTR_ERR(new_epayload); + } + + __ekey_init(new_epayload, epayload->format, new_master_desc, + epayload->datalen); + + memcpy(new_epayload->iv, epayload->iv, ivsize); + memcpy(new_epayload->payload_data, epayload->payload_data, + epayload->payload_datalen); + + rcu_assign_keypointer(key, new_epayload); + + up_write(&key->sem); + call_rcu(&epayload->rcu, encrypted_rcu_free); + return 0; +} + +/* * encrypted_read - format and copy the encrypted data to userspace * * The resulting datablob format is: @@ -974,6 +1029,7 @@ struct key_type key_type_encrypted = { .destroy = encrypted_destroy, .describe = user_describe, .read = encrypted_read, + .control = encrypted_control, }; EXPORT_SYMBOL_GPL(key_type_encrypted); -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/