From b2987a5e05ec7a1af7ca42e5d5349d7a22753031 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Tue, 26 Jul 2011 19:47:08 -0500 Subject: [PATCH] eCryptfs: Unlock keys needed by ecryptfsd Fixes a regression caused by b5695d04634fa4ccca7dcbc05bb4a66522f02e0b Kernel keyring keys containing eCryptfs authentication tokens should not be write locked when calling out to ecryptfsd to wrap and unwrap file encryption keys. The eCryptfs kernel code can not hold the key's write lock because ecryptfsd needs to request the key after receiving such a request from the kernel. Without this fix, all file opens and creates will timeout and fail when using the eCryptfs PKI infrastructure. This is not an issue when using passphrase-based mount keys, which is the most widely deployed eCryptfs configuration. Signed-off-by: Tyler Hicks Acked-by: Roberto Sassu Tested-by: Roberto Sassu Tested-by: Alexis Hafner1 Cc: [2.6.39+] --- fs/ecryptfs/keystore.c | 47 ++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index c47253350123..08a2b52bf565 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -1871,11 +1871,6 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, * just one will be sufficient to decrypt to get the FEK. */ find_next_matching_auth_tok: found_auth_tok = 0; - if (auth_tok_key) { - up_write(&(auth_tok_key->sem)); - key_put(auth_tok_key); - auth_tok_key = NULL; - } list_for_each_entry(auth_tok_list_item, &auth_tok_list, list) { candidate_auth_tok = &auth_tok_list_item->auth_tok; if (unlikely(ecryptfs_verbosity > 0)) { @@ -1912,14 +1907,22 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, memcpy(&(candidate_auth_tok->token.private_key), &(matching_auth_tok->token.private_key), sizeof(struct ecryptfs_private_key)); + up_write(&(auth_tok_key->sem)); + key_put(auth_tok_key); rc = decrypt_pki_encrypted_session_key(candidate_auth_tok, crypt_stat); } else if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD) { memcpy(&(candidate_auth_tok->token.password), &(matching_auth_tok->token.password), sizeof(struct ecryptfs_password)); + up_write(&(auth_tok_key->sem)); + key_put(auth_tok_key); rc = decrypt_passphrase_encrypted_session_key( candidate_auth_tok, crypt_stat); + } else { + up_write(&(auth_tok_key->sem)); + key_put(auth_tok_key); + rc = -EINVAL; } if (rc) { struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp; @@ -1959,15 +1962,12 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, out_wipe_list: wipe_auth_tok_list(&auth_tok_list); out: - if (auth_tok_key) { - up_write(&(auth_tok_key->sem)); - key_put(auth_tok_key); - } return rc; } static int -pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok, +pki_encrypt_session_key(struct key *auth_tok_key, + struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_key_record *key_rec) { @@ -1982,6 +1982,8 @@ pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok, crypt_stat->cipher, crypt_stat->key_size), crypt_stat, &payload, &payload_len); + up_write(&(auth_tok_key->sem)); + key_put(auth_tok_key); if (rc) { ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet\n"); goto out; @@ -2011,6 +2013,8 @@ pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok, * write_tag_1_packet - Write an RFC2440-compatible tag 1 (public key) packet * @dest: Buffer into which to write the packet * @remaining_bytes: Maximum number of bytes that can be writtn + * @auth_tok_key: The authentication token key to unlock and put when done with + * @auth_tok * @auth_tok: The authentication token used for generating the tag 1 packet * @crypt_stat: The cryptographic context * @key_rec: The key record struct for the tag 1 packet @@ -2021,7 +2025,7 @@ pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok, */ static int write_tag_1_packet(char *dest, size_t *remaining_bytes, - struct ecryptfs_auth_tok *auth_tok, + struct key *auth_tok_key, struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_key_record *key_rec, size_t *packet_size) { @@ -2042,12 +2046,15 @@ write_tag_1_packet(char *dest, size_t *remaining_bytes, memcpy(key_rec->enc_key, auth_tok->session_key.encrypted_key, auth_tok->session_key.encrypted_key_size); + up_write(&(auth_tok_key->sem)); + key_put(auth_tok_key); goto encrypted_session_key_set; } if (auth_tok->session_key.encrypted_key_size == 0) auth_tok->session_key.encrypted_key_size = auth_tok->token.private_key.key_size; - rc = pki_encrypt_session_key(auth_tok, crypt_stat, key_rec); + rc = pki_encrypt_session_key(auth_tok_key, auth_tok, crypt_stat, + key_rec); if (rc) { printk(KERN_ERR "Failed to encrypt session key via a key " "module; rc = [%d]\n", rc); @@ -2424,6 +2431,8 @@ ecryptfs_generate_key_packet_set(char *dest_base, &max, auth_tok, crypt_stat, key_rec, &written); + up_write(&(auth_tok_key->sem)); + key_put(auth_tok_key); if (rc) { ecryptfs_printk(KERN_WARNING, "Error " "writing tag 3 packet\n"); @@ -2441,8 +2450,8 @@ ecryptfs_generate_key_packet_set(char *dest_base, } (*len) += written; } else if (auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) { - rc = write_tag_1_packet(dest_base + (*len), - &max, auth_tok, + rc = write_tag_1_packet(dest_base + (*len), &max, + auth_tok_key, auth_tok, crypt_stat, key_rec, &written); if (rc) { ecryptfs_printk(KERN_WARNING, "Error " @@ -2451,14 +2460,13 @@ ecryptfs_generate_key_packet_set(char *dest_base, } (*len) += written; } else { + up_write(&(auth_tok_key->sem)); + key_put(auth_tok_key); ecryptfs_printk(KERN_WARNING, "Unsupported " "authentication token type\n"); rc = -EINVAL; goto out_free; } - up_write(&(auth_tok_key->sem)); - key_put(auth_tok_key); - auth_tok_key = NULL; } if (likely(max > 0)) { dest_base[(*len)] = 0x00; @@ -2471,11 +2479,6 @@ ecryptfs_generate_key_packet_set(char *dest_base, out: if (rc) (*len) = 0; - if (auth_tok_key) { - up_write(&(auth_tok_key->sem)); - key_put(auth_tok_key); - } - mutex_unlock(&crypt_stat->keysig_list_mutex); return rc; }