eCryptfs: Unlock keys needed by ecryptfsd
Fixes a regression caused by b5695d0463
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 <tyhicks@linux.vnet.ibm.com>
Acked-by: Roberto Sassu <roberto.sassu@polito.it>
Tested-by: Roberto Sassu <roberto.sassu@polito.it>
Tested-by: Alexis Hafner1 <haf@zurich.ibm.com>
Cc: <stable@kernel.org> [2.6.39+]
This commit is contained in:
parent
55f9c40ff6
commit
b2987a5e05
|
@ -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. */
|
* just one will be sufficient to decrypt to get the FEK. */
|
||||||
find_next_matching_auth_tok:
|
find_next_matching_auth_tok:
|
||||||
found_auth_tok = 0;
|
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) {
|
list_for_each_entry(auth_tok_list_item, &auth_tok_list, list) {
|
||||||
candidate_auth_tok = &auth_tok_list_item->auth_tok;
|
candidate_auth_tok = &auth_tok_list_item->auth_tok;
|
||||||
if (unlikely(ecryptfs_verbosity > 0)) {
|
if (unlikely(ecryptfs_verbosity > 0)) {
|
||||||
|
@ -1912,14 +1907,22 @@ found_matching_auth_tok:
|
||||||
memcpy(&(candidate_auth_tok->token.private_key),
|
memcpy(&(candidate_auth_tok->token.private_key),
|
||||||
&(matching_auth_tok->token.private_key),
|
&(matching_auth_tok->token.private_key),
|
||||||
sizeof(struct ecryptfs_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,
|
rc = decrypt_pki_encrypted_session_key(candidate_auth_tok,
|
||||||
crypt_stat);
|
crypt_stat);
|
||||||
} else if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD) {
|
} else if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD) {
|
||||||
memcpy(&(candidate_auth_tok->token.password),
|
memcpy(&(candidate_auth_tok->token.password),
|
||||||
&(matching_auth_tok->token.password),
|
&(matching_auth_tok->token.password),
|
||||||
sizeof(struct ecryptfs_password));
|
sizeof(struct ecryptfs_password));
|
||||||
|
up_write(&(auth_tok_key->sem));
|
||||||
|
key_put(auth_tok_key);
|
||||||
rc = decrypt_passphrase_encrypted_session_key(
|
rc = decrypt_passphrase_encrypted_session_key(
|
||||||
candidate_auth_tok, crypt_stat);
|
candidate_auth_tok, crypt_stat);
|
||||||
|
} else {
|
||||||
|
up_write(&(auth_tok_key->sem));
|
||||||
|
key_put(auth_tok_key);
|
||||||
|
rc = -EINVAL;
|
||||||
}
|
}
|
||||||
if (rc) {
|
if (rc) {
|
||||||
struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp;
|
struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp;
|
||||||
|
@ -1959,15 +1962,12 @@ found_matching_auth_tok:
|
||||||
out_wipe_list:
|
out_wipe_list:
|
||||||
wipe_auth_tok_list(&auth_tok_list);
|
wipe_auth_tok_list(&auth_tok_list);
|
||||||
out:
|
out:
|
||||||
if (auth_tok_key) {
|
|
||||||
up_write(&(auth_tok_key->sem));
|
|
||||||
key_put(auth_tok_key);
|
|
||||||
}
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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_crypt_stat *crypt_stat,
|
||||||
struct ecryptfs_key_record *key_rec)
|
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->cipher,
|
||||||
crypt_stat->key_size),
|
crypt_stat->key_size),
|
||||||
crypt_stat, &payload, &payload_len);
|
crypt_stat, &payload, &payload_len);
|
||||||
|
up_write(&(auth_tok_key->sem));
|
||||||
|
key_put(auth_tok_key);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet\n");
|
ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet\n");
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -2011,6 +2013,8 @@ out:
|
||||||
* write_tag_1_packet - Write an RFC2440-compatible tag 1 (public key) packet
|
* write_tag_1_packet - Write an RFC2440-compatible tag 1 (public key) packet
|
||||||
* @dest: Buffer into which to write the packet
|
* @dest: Buffer into which to write the packet
|
||||||
* @remaining_bytes: Maximum number of bytes that can be writtn
|
* @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
|
* @auth_tok: The authentication token used for generating the tag 1 packet
|
||||||
* @crypt_stat: The cryptographic context
|
* @crypt_stat: The cryptographic context
|
||||||
* @key_rec: The key record struct for the tag 1 packet
|
* @key_rec: The key record struct for the tag 1 packet
|
||||||
|
@ -2021,7 +2025,7 @@ out:
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
write_tag_1_packet(char *dest, size_t *remaining_bytes,
|
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_crypt_stat *crypt_stat,
|
||||||
struct ecryptfs_key_record *key_rec, size_t *packet_size)
|
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,
|
memcpy(key_rec->enc_key,
|
||||||
auth_tok->session_key.encrypted_key,
|
auth_tok->session_key.encrypted_key,
|
||||||
auth_tok->session_key.encrypted_key_size);
|
auth_tok->session_key.encrypted_key_size);
|
||||||
|
up_write(&(auth_tok_key->sem));
|
||||||
|
key_put(auth_tok_key);
|
||||||
goto encrypted_session_key_set;
|
goto encrypted_session_key_set;
|
||||||
}
|
}
|
||||||
if (auth_tok->session_key.encrypted_key_size == 0)
|
if (auth_tok->session_key.encrypted_key_size == 0)
|
||||||
auth_tok->session_key.encrypted_key_size =
|
auth_tok->session_key.encrypted_key_size =
|
||||||
auth_tok->token.private_key.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) {
|
if (rc) {
|
||||||
printk(KERN_ERR "Failed to encrypt session key via a key "
|
printk(KERN_ERR "Failed to encrypt session key via a key "
|
||||||
"module; rc = [%d]\n", rc);
|
"module; rc = [%d]\n", rc);
|
||||||
|
@ -2424,6 +2431,8 @@ ecryptfs_generate_key_packet_set(char *dest_base,
|
||||||
&max, auth_tok,
|
&max, auth_tok,
|
||||||
crypt_stat, key_rec,
|
crypt_stat, key_rec,
|
||||||
&written);
|
&written);
|
||||||
|
up_write(&(auth_tok_key->sem));
|
||||||
|
key_put(auth_tok_key);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
ecryptfs_printk(KERN_WARNING, "Error "
|
ecryptfs_printk(KERN_WARNING, "Error "
|
||||||
"writing tag 3 packet\n");
|
"writing tag 3 packet\n");
|
||||||
|
@ -2441,8 +2450,8 @@ ecryptfs_generate_key_packet_set(char *dest_base,
|
||||||
}
|
}
|
||||||
(*len) += written;
|
(*len) += written;
|
||||||
} else if (auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) {
|
} else if (auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) {
|
||||||
rc = write_tag_1_packet(dest_base + (*len),
|
rc = write_tag_1_packet(dest_base + (*len), &max,
|
||||||
&max, auth_tok,
|
auth_tok_key, auth_tok,
|
||||||
crypt_stat, key_rec, &written);
|
crypt_stat, key_rec, &written);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
ecryptfs_printk(KERN_WARNING, "Error "
|
ecryptfs_printk(KERN_WARNING, "Error "
|
||||||
|
@ -2451,14 +2460,13 @@ ecryptfs_generate_key_packet_set(char *dest_base,
|
||||||
}
|
}
|
||||||
(*len) += written;
|
(*len) += written;
|
||||||
} else {
|
} else {
|
||||||
|
up_write(&(auth_tok_key->sem));
|
||||||
|
key_put(auth_tok_key);
|
||||||
ecryptfs_printk(KERN_WARNING, "Unsupported "
|
ecryptfs_printk(KERN_WARNING, "Unsupported "
|
||||||
"authentication token type\n");
|
"authentication token type\n");
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
up_write(&(auth_tok_key->sem));
|
|
||||||
key_put(auth_tok_key);
|
|
||||||
auth_tok_key = NULL;
|
|
||||||
}
|
}
|
||||||
if (likely(max > 0)) {
|
if (likely(max > 0)) {
|
||||||
dest_base[(*len)] = 0x00;
|
dest_base[(*len)] = 0x00;
|
||||||
|
@ -2471,11 +2479,6 @@ out_free:
|
||||||
out:
|
out:
|
||||||
if (rc)
|
if (rc)
|
||||||
(*len) = 0;
|
(*len) = 0;
|
||||||
if (auth_tok_key) {
|
|
||||||
up_write(&(auth_tok_key->sem));
|
|
||||||
key_put(auth_tok_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&crypt_stat->keysig_list_mutex);
|
mutex_unlock(&crypt_stat->keysig_list_mutex);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue