eCryptfs: verify authentication tokens before their use
Authentication tokens content may change if another requestor calls the update() method of the corresponding key. The new function ecryptfs_verify_auth_tok_from_key() retrieves the authentication token from the provided key and verifies if it is still valid before being used to encrypt or decrypt an eCryptfs file. Signed-off-by: Roberto Sassu <roberto.sassu@polito.it> [tyhicks: Minor formatting changes] Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com>
This commit is contained in:
parent
7762e230fd
commit
0e1fc5ef47
|
@ -331,7 +331,6 @@ struct ecryptfs_global_auth_tok {
|
||||||
u32 flags;
|
u32 flags;
|
||||||
struct list_head mount_crypt_stat_list;
|
struct list_head mount_crypt_stat_list;
|
||||||
struct key *global_auth_tok_key;
|
struct key *global_auth_tok_key;
|
||||||
struct ecryptfs_auth_tok *global_auth_tok;
|
|
||||||
unsigned char sig[ECRYPTFS_SIG_SIZE_HEX + 1];
|
unsigned char sig[ECRYPTFS_SIG_SIZE_HEX + 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,24 @@ static int process_request_key_err(long err_code)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int process_find_global_auth_tok_for_sig_err(int err_code)
|
||||||
|
{
|
||||||
|
int rc = err_code;
|
||||||
|
|
||||||
|
switch (err_code) {
|
||||||
|
case -ENOENT:
|
||||||
|
ecryptfs_printk(KERN_WARNING, "Missing auth tok\n");
|
||||||
|
break;
|
||||||
|
case -EINVAL:
|
||||||
|
ecryptfs_printk(KERN_WARNING, "Invalid auth tok\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rc = process_request_key_err(err_code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ecryptfs_parse_packet_length
|
* ecryptfs_parse_packet_length
|
||||||
* @data: Pointer to memory containing length at offset
|
* @data: Pointer to memory containing length at offset
|
||||||
|
@ -403,27 +421,117 @@ out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ecryptfs_verify_version
|
||||||
|
* @version: The version number to confirm
|
||||||
|
*
|
||||||
|
* Returns zero on good version; non-zero otherwise
|
||||||
|
*/
|
||||||
|
static int ecryptfs_verify_version(u16 version)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
unsigned char major;
|
||||||
|
unsigned char minor;
|
||||||
|
|
||||||
|
major = ((version >> 8) & 0xFF);
|
||||||
|
minor = (version & 0xFF);
|
||||||
|
if (major != ECRYPTFS_VERSION_MAJOR) {
|
||||||
|
ecryptfs_printk(KERN_ERR, "Major version number mismatch. "
|
||||||
|
"Expected [%d]; got [%d]\n",
|
||||||
|
ECRYPTFS_VERSION_MAJOR, major);
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (minor != ECRYPTFS_VERSION_MINOR) {
|
||||||
|
ecryptfs_printk(KERN_ERR, "Minor version number mismatch. "
|
||||||
|
"Expected [%d]; got [%d]\n",
|
||||||
|
ECRYPTFS_VERSION_MINOR, minor);
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ecryptfs_verify_auth_tok_from_key
|
||||||
|
* @auth_tok_key: key containing the authentication token
|
||||||
|
* @auth_tok: authentication token
|
||||||
|
*
|
||||||
|
* Returns zero on valid auth tok; -EINVAL otherwise
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key,
|
||||||
|
struct ecryptfs_auth_tok **auth_tok)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
(*auth_tok) = ecryptfs_get_key_payload_data(auth_tok_key);
|
||||||
|
if (ecryptfs_verify_version((*auth_tok)->version)) {
|
||||||
|
printk(KERN_ERR "Data structure version mismatch. Userspace "
|
||||||
|
"tools must match eCryptfs kernel module with major "
|
||||||
|
"version [%d] and minor version [%d]\n",
|
||||||
|
ECRYPTFS_VERSION_MAJOR, ECRYPTFS_VERSION_MINOR);
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((*auth_tok)->token_type != ECRYPTFS_PASSWORD
|
||||||
|
&& (*auth_tok)->token_type != ECRYPTFS_PRIVATE_KEY) {
|
||||||
|
printk(KERN_ERR "Invalid auth_tok structure "
|
||||||
|
"returned from key query\n");
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ecryptfs_find_global_auth_tok_for_sig(
|
ecryptfs_find_global_auth_tok_for_sig(
|
||||||
struct ecryptfs_global_auth_tok **global_auth_tok,
|
struct key **auth_tok_key,
|
||||||
|
struct ecryptfs_auth_tok **auth_tok,
|
||||||
struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig)
|
struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig)
|
||||||
{
|
{
|
||||||
struct ecryptfs_global_auth_tok *walker;
|
struct ecryptfs_global_auth_tok *walker;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
(*global_auth_tok) = NULL;
|
(*auth_tok_key) = NULL;
|
||||||
|
(*auth_tok) = NULL;
|
||||||
mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex);
|
mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex);
|
||||||
list_for_each_entry(walker,
|
list_for_each_entry(walker,
|
||||||
&mount_crypt_stat->global_auth_tok_list,
|
&mount_crypt_stat->global_auth_tok_list,
|
||||||
mount_crypt_stat_list) {
|
mount_crypt_stat_list) {
|
||||||
if (memcmp(walker->sig, sig, ECRYPTFS_SIG_SIZE_HEX) == 0) {
|
if (memcmp(walker->sig, sig, ECRYPTFS_SIG_SIZE_HEX))
|
||||||
rc = key_validate(walker->global_auth_tok_key);
|
continue;
|
||||||
if (!rc)
|
|
||||||
(*global_auth_tok) = walker;
|
if (walker->flags & ECRYPTFS_AUTH_TOK_INVALID) {
|
||||||
|
rc = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc = key_validate(walker->global_auth_tok_key);
|
||||||
|
if (rc) {
|
||||||
|
if (rc == -EKEYEXPIRED)
|
||||||
|
goto out;
|
||||||
|
goto out_invalid_auth_tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ecryptfs_verify_auth_tok_from_key(
|
||||||
|
walker->global_auth_tok_key, auth_tok);
|
||||||
|
if (rc)
|
||||||
|
goto out_invalid_auth_tok;
|
||||||
|
|
||||||
|
(*auth_tok_key) = walker->global_auth_tok_key;
|
||||||
|
key_get(*auth_tok_key);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
rc = -EINVAL;
|
rc = -ENOENT;
|
||||||
|
goto out;
|
||||||
|
out_invalid_auth_tok:
|
||||||
|
printk(KERN_WARNING "Invalidating auth tok with sig = [%s]\n", sig);
|
||||||
|
walker->flags |= ECRYPTFS_AUTH_TOK_INVALID;
|
||||||
|
key_put(walker->global_auth_tok_key);
|
||||||
|
walker->global_auth_tok_key = NULL;
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);
|
mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -451,14 +559,11 @@ ecryptfs_find_auth_tok_for_sig(
|
||||||
struct ecryptfs_mount_crypt_stat *mount_crypt_stat,
|
struct ecryptfs_mount_crypt_stat *mount_crypt_stat,
|
||||||
char *sig)
|
char *sig)
|
||||||
{
|
{
|
||||||
struct ecryptfs_global_auth_tok *global_auth_tok;
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
(*auth_tok_key) = NULL;
|
rc = ecryptfs_find_global_auth_tok_for_sig(auth_tok_key, auth_tok,
|
||||||
(*auth_tok) = NULL;
|
mount_crypt_stat, sig);
|
||||||
if (ecryptfs_find_global_auth_tok_for_sig(&global_auth_tok,
|
if (rc == -ENOENT) {
|
||||||
mount_crypt_stat, sig)) {
|
|
||||||
|
|
||||||
/* if the flag ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY is set in the
|
/* if the flag ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY is set in the
|
||||||
* mount_crypt_stat structure, we prevent to use auth toks that
|
* mount_crypt_stat structure, we prevent to use auth toks that
|
||||||
* are not inserted through the ecryptfs_add_global_auth_tok
|
* are not inserted through the ecryptfs_add_global_auth_tok
|
||||||
|
@ -470,8 +575,7 @@ ecryptfs_find_auth_tok_for_sig(
|
||||||
|
|
||||||
rc = ecryptfs_keyring_auth_tok_for_sig(auth_tok_key, auth_tok,
|
rc = ecryptfs_keyring_auth_tok_for_sig(auth_tok_key, auth_tok,
|
||||||
sig);
|
sig);
|
||||||
} else
|
}
|
||||||
(*auth_tok) = global_auth_tok->global_auth_tok;
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1520,38 +1624,6 @@ out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ecryptfs_verify_version
|
|
||||||
* @version: The version number to confirm
|
|
||||||
*
|
|
||||||
* Returns zero on good version; non-zero otherwise
|
|
||||||
*/
|
|
||||||
static int ecryptfs_verify_version(u16 version)
|
|
||||||
{
|
|
||||||
int rc = 0;
|
|
||||||
unsigned char major;
|
|
||||||
unsigned char minor;
|
|
||||||
|
|
||||||
major = ((version >> 8) & 0xFF);
|
|
||||||
minor = (version & 0xFF);
|
|
||||||
if (major != ECRYPTFS_VERSION_MAJOR) {
|
|
||||||
ecryptfs_printk(KERN_ERR, "Major version number mismatch. "
|
|
||||||
"Expected [%d]; got [%d]\n",
|
|
||||||
ECRYPTFS_VERSION_MAJOR, major);
|
|
||||||
rc = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (minor != ECRYPTFS_VERSION_MINOR) {
|
|
||||||
ecryptfs_printk(KERN_ERR, "Minor version number mismatch. "
|
|
||||||
"Expected [%d]; got [%d]\n",
|
|
||||||
ECRYPTFS_VERSION_MINOR, minor);
|
|
||||||
rc = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key,
|
int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key,
|
||||||
struct ecryptfs_auth_tok **auth_tok,
|
struct ecryptfs_auth_tok **auth_tok,
|
||||||
char *sig)
|
char *sig)
|
||||||
|
@ -1566,29 +1638,12 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key,
|
||||||
(*auth_tok_key) = NULL;
|
(*auth_tok_key) = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
(*auth_tok) = ecryptfs_get_key_payload_data(*auth_tok_key);
|
|
||||||
if (ecryptfs_verify_version((*auth_tok)->version)) {
|
rc = ecryptfs_verify_auth_tok_from_key(*auth_tok_key, auth_tok);
|
||||||
printk(KERN_ERR
|
|
||||||
"Data structure version mismatch. "
|
|
||||||
"Userspace tools must match eCryptfs "
|
|
||||||
"kernel module with major version [%d] "
|
|
||||||
"and minor version [%d]\n",
|
|
||||||
ECRYPTFS_VERSION_MAJOR,
|
|
||||||
ECRYPTFS_VERSION_MINOR);
|
|
||||||
rc = -EINVAL;
|
|
||||||
goto out_release_key;
|
|
||||||
}
|
|
||||||
if ((*auth_tok)->token_type != ECRYPTFS_PASSWORD
|
|
||||||
&& (*auth_tok)->token_type != ECRYPTFS_PRIVATE_KEY) {
|
|
||||||
printk(KERN_ERR "Invalid auth_tok structure "
|
|
||||||
"returned from key query\n");
|
|
||||||
rc = -EINVAL;
|
|
||||||
goto out_release_key;
|
|
||||||
}
|
|
||||||
out_release_key:
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
key_put(*auth_tok_key);
|
key_put(*auth_tok_key);
|
||||||
(*auth_tok_key) = NULL;
|
(*auth_tok_key) = NULL;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -2325,7 +2380,7 @@ ecryptfs_generate_key_packet_set(char *dest_base,
|
||||||
size_t max)
|
size_t max)
|
||||||
{
|
{
|
||||||
struct ecryptfs_auth_tok *auth_tok;
|
struct ecryptfs_auth_tok *auth_tok;
|
||||||
struct ecryptfs_global_auth_tok *global_auth_tok;
|
struct key *auth_tok_key = NULL;
|
||||||
struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
|
struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
|
||||||
&ecryptfs_superblock_to_private(
|
&ecryptfs_superblock_to_private(
|
||||||
ecryptfs_dentry->d_sb)->mount_crypt_stat;
|
ecryptfs_dentry->d_sb)->mount_crypt_stat;
|
||||||
|
@ -2344,21 +2399,16 @@ ecryptfs_generate_key_packet_set(char *dest_base,
|
||||||
list_for_each_entry(key_sig, &crypt_stat->keysig_list,
|
list_for_each_entry(key_sig, &crypt_stat->keysig_list,
|
||||||
crypt_stat_list) {
|
crypt_stat_list) {
|
||||||
memset(key_rec, 0, sizeof(*key_rec));
|
memset(key_rec, 0, sizeof(*key_rec));
|
||||||
rc = ecryptfs_find_global_auth_tok_for_sig(&global_auth_tok,
|
rc = ecryptfs_find_global_auth_tok_for_sig(&auth_tok_key,
|
||||||
|
&auth_tok,
|
||||||
mount_crypt_stat,
|
mount_crypt_stat,
|
||||||
key_sig->keysig);
|
key_sig->keysig);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_ERR "Error attempting to get the global "
|
printk(KERN_WARNING "Unable to retrieve auth tok with "
|
||||||
"auth_tok; rc = [%d]\n", rc);
|
"sig = [%s]\n", key_sig->keysig);
|
||||||
|
rc = process_find_global_auth_tok_for_sig_err(rc);
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
if (global_auth_tok->flags & ECRYPTFS_AUTH_TOK_INVALID) {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"Skipping invalid auth tok with sig = [%s]\n",
|
|
||||||
global_auth_tok->sig);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auth_tok = global_auth_tok->global_auth_tok;
|
|
||||||
if (auth_tok->token_type == ECRYPTFS_PASSWORD) {
|
if (auth_tok->token_type == ECRYPTFS_PASSWORD) {
|
||||||
rc = write_tag_3_packet((dest_base + (*len)),
|
rc = write_tag_3_packet((dest_base + (*len)),
|
||||||
&max, auth_tok,
|
&max, auth_tok,
|
||||||
|
@ -2396,6 +2446,8 @@ ecryptfs_generate_key_packet_set(char *dest_base,
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
|
@ -2408,6 +2460,9 @@ out_free:
|
||||||
out:
|
out:
|
||||||
if (rc)
|
if (rc)
|
||||||
(*len) = 0;
|
(*len) = 0;
|
||||||
|
if (auth_tok_key)
|
||||||
|
key_put(auth_tok_key);
|
||||||
|
|
||||||
mutex_unlock(&crypt_stat->keysig_list_mutex);
|
mutex_unlock(&crypt_stat->keysig_list_mutex);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,14 +239,14 @@ static int ecryptfs_init_global_auth_toks(
|
||||||
struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
|
struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
|
||||||
{
|
{
|
||||||
struct ecryptfs_global_auth_tok *global_auth_tok;
|
struct ecryptfs_global_auth_tok *global_auth_tok;
|
||||||
|
struct ecryptfs_auth_tok *auth_tok;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
list_for_each_entry(global_auth_tok,
|
list_for_each_entry(global_auth_tok,
|
||||||
&mount_crypt_stat->global_auth_tok_list,
|
&mount_crypt_stat->global_auth_tok_list,
|
||||||
mount_crypt_stat_list) {
|
mount_crypt_stat_list) {
|
||||||
rc = ecryptfs_keyring_auth_tok_for_sig(
|
rc = ecryptfs_keyring_auth_tok_for_sig(
|
||||||
&global_auth_tok->global_auth_tok_key,
|
&global_auth_tok->global_auth_tok_key, &auth_tok,
|
||||||
&global_auth_tok->global_auth_tok,
|
|
||||||
global_auth_tok->sig);
|
global_auth_tok->sig);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_ERR "Could not find valid key in user "
|
printk(KERN_ERR "Could not find valid key in user "
|
||||||
|
|
Loading…
Reference in New Issue