eCryptfs: add key list structure; search keyring

Add support structures for handling multiple keys.  The list in crypt_stat
contains the key identifiers for all of the keys that should be used for
encrypting each file's File Encryption Key (FEK).  For now, each inode
inherits this list from the mount-wide crypt_stat struct, via the
ecryptfs_copy_mount_wide_sigs_to_inode_sigs() function.

This patch also removes the global key tfm from the mount-wide crypt_stat
struct, instead keeping a list of tfm's meant for dealing with the various
inode FEK's.  eCryptfs will now search the user's keyring for FEK's parsed
from the existing file metadata, so the user can make keys available at any
time before or after mounting.

Now that multiple FEK packets can be written to the file metadata, we need to
be more meticulous about size limits.  The updates to the code for writing out
packets to the file metadata makes sizes and limits more explicit, uniformly
expressed, and (hopefully) easier to follow.

Signed-off-by: Michael Halcrow <mhalcrow@us.ibm.com>
Cc: "Serge E. Hallyn" <serge@hallyn.com>
Cc: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Michael Halcrow 2007-10-16 01:27:53 -07:00 committed by Linus Torvalds
parent cce76f9b96
commit f4aad16adf
4 changed files with 742 additions and 401 deletions

View file

@ -204,6 +204,8 @@ void
ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
{ {
memset((void *)crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat)); memset((void *)crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
INIT_LIST_HEAD(&crypt_stat->keysig_list);
mutex_init(&crypt_stat->keysig_list_mutex);
mutex_init(&crypt_stat->cs_mutex); mutex_init(&crypt_stat->cs_mutex);
mutex_init(&crypt_stat->cs_tfm_mutex); mutex_init(&crypt_stat->cs_tfm_mutex);
mutex_init(&crypt_stat->cs_hash_tfm_mutex); mutex_init(&crypt_stat->cs_hash_tfm_mutex);
@ -218,20 +220,41 @@ ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
*/ */
void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
{ {
struct ecryptfs_key_sig *key_sig, *key_sig_tmp;
if (crypt_stat->tfm) if (crypt_stat->tfm)
crypto_free_blkcipher(crypt_stat->tfm); crypto_free_blkcipher(crypt_stat->tfm);
if (crypt_stat->hash_tfm) if (crypt_stat->hash_tfm)
crypto_free_hash(crypt_stat->hash_tfm); crypto_free_hash(crypt_stat->hash_tfm);
mutex_lock(&crypt_stat->keysig_list_mutex);
list_for_each_entry_safe(key_sig, key_sig_tmp,
&crypt_stat->keysig_list, crypt_stat_list) {
list_del(&key_sig->crypt_stat_list);
kmem_cache_free(ecryptfs_key_sig_cache, key_sig);
}
mutex_unlock(&crypt_stat->keysig_list_mutex);
memset(crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat)); memset(crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
} }
void ecryptfs_destruct_mount_crypt_stat( void ecryptfs_destruct_mount_crypt_stat(
struct ecryptfs_mount_crypt_stat *mount_crypt_stat) struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
{ {
if (mount_crypt_stat->global_auth_tok_key) struct ecryptfs_global_auth_tok *auth_tok, *auth_tok_tmp;
key_put(mount_crypt_stat->global_auth_tok_key);
if (mount_crypt_stat->global_key_tfm) if (!(mount_crypt_stat->flags & ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED))
crypto_free_blkcipher(mount_crypt_stat->global_key_tfm); return;
mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex);
list_for_each_entry_safe(auth_tok, auth_tok_tmp,
&mount_crypt_stat->global_auth_tok_list,
mount_crypt_stat_list) {
list_del(&auth_tok->mount_crypt_stat_list);
mount_crypt_stat->num_global_auth_toks--;
if (auth_tok->global_auth_tok_key
&& !(auth_tok->flags & ECRYPTFS_AUTH_TOK_INVALID))
key_put(auth_tok->global_auth_tok_key);
kmem_cache_free(ecryptfs_global_auth_tok_cache, auth_tok);
}
mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);
memset(mount_crypt_stat, 0, sizeof(struct ecryptfs_mount_crypt_stat)); memset(mount_crypt_stat, 0, sizeof(struct ecryptfs_mount_crypt_stat));
} }
@ -931,6 +954,30 @@ static void ecryptfs_copy_mount_wide_flags_to_inode_flags(
crypt_stat->flags |= ECRYPTFS_VIEW_AS_ENCRYPTED; crypt_stat->flags |= ECRYPTFS_VIEW_AS_ENCRYPTED;
} }
static int ecryptfs_copy_mount_wide_sigs_to_inode_sigs(
struct ecryptfs_crypt_stat *crypt_stat,
struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
{
struct ecryptfs_global_auth_tok *global_auth_tok;
int rc = 0;
mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex);
list_for_each_entry(global_auth_tok,
&mount_crypt_stat->global_auth_tok_list,
mount_crypt_stat_list) {
rc = ecryptfs_add_keysig(crypt_stat, global_auth_tok->sig);
if (rc) {
printk(KERN_ERR "Error adding keysig; rc = [%d]\n", rc);
mutex_unlock(
&mount_crypt_stat->global_auth_tok_list_mutex);
goto out;
}
}
mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);
out:
return rc;
}
/** /**
* ecryptfs_set_default_crypt_stat_vals * ecryptfs_set_default_crypt_stat_vals
* @crypt_stat * @crypt_stat
@ -973,46 +1020,44 @@ static void ecryptfs_set_default_crypt_stat_vals(
/* Associate an authentication token(s) with the file */ /* Associate an authentication token(s) with the file */
int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry) int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry)
{ {
int rc = 0;
struct ecryptfs_crypt_stat *crypt_stat = struct ecryptfs_crypt_stat *crypt_stat =
&ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
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;
int cipher_name_len; int cipher_name_len;
int rc = 0;
ecryptfs_set_default_crypt_stat_vals(crypt_stat, mount_crypt_stat); ecryptfs_set_default_crypt_stat_vals(crypt_stat, mount_crypt_stat);
/* See if there are mount crypt options */ mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex);
if (mount_crypt_stat->global_auth_tok) { BUG_ON(mount_crypt_stat->num_global_auth_toks == 0);
ecryptfs_printk(KERN_DEBUG, "Initializing context for new " mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);
"file using mount_crypt_stat\n"); crypt_stat->flags |= ECRYPTFS_ENCRYPTED;
crypt_stat->flags |= ECRYPTFS_ENCRYPTED; crypt_stat->flags |= ECRYPTFS_KEY_VALID;
crypt_stat->flags |= ECRYPTFS_KEY_VALID; ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat,
ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat, mount_crypt_stat);
mount_crypt_stat); rc = ecryptfs_copy_mount_wide_sigs_to_inode_sigs(crypt_stat,
memcpy(crypt_stat->keysigs[crypt_stat->num_keysigs++], mount_crypt_stat);
mount_crypt_stat->global_auth_tok_sig, if (rc) {
ECRYPTFS_SIG_SIZE_HEX); printk(KERN_ERR "Error attempting to copy mount-wide key sigs "
cipher_name_len = "to the inode key sigs; rc = [%d]\n", rc);
strlen(mount_crypt_stat->global_default_cipher_name); goto out;
memcpy(crypt_stat->cipher, }
mount_crypt_stat->global_default_cipher_name, cipher_name_len =
cipher_name_len); strlen(mount_crypt_stat->global_default_cipher_name);
crypt_stat->cipher[cipher_name_len] = '\0'; memcpy(crypt_stat->cipher,
crypt_stat->key_size = mount_crypt_stat->global_default_cipher_name,
mount_crypt_stat->global_default_cipher_key_size; cipher_name_len);
ecryptfs_generate_new_key(crypt_stat); crypt_stat->cipher[cipher_name_len] = '\0';
} else crypt_stat->key_size =
/* We should not encounter this scenario since we mount_crypt_stat->global_default_cipher_key_size;
* should detect lack of global_auth_tok at mount time ecryptfs_generate_new_key(crypt_stat);
* TODO: Applies to 0.1 release only; remove in future
* release */
BUG();
rc = ecryptfs_init_crypt_ctx(crypt_stat); rc = ecryptfs_init_crypt_ctx(crypt_stat);
if (rc) if (rc)
ecryptfs_printk(KERN_ERR, "Error initializing cryptographic " ecryptfs_printk(KERN_ERR, "Error initializing cryptographic "
"context for cipher [%s]: rc = [%d]\n", "context for cipher [%s]: rc = [%d]\n",
crypt_stat->cipher, rc); crypt_stat->cipher, rc);
out:
return rc; return rc;
} }
@ -1776,7 +1821,7 @@ out:
} }
/** /**
* ecryptfs_process_cipher - Perform cipher initialization. * ecryptfs_process_key_cipher - Perform key cipher initialization.
* @key_tfm: Crypto context for key material, set by this function * @key_tfm: Crypto context for key material, set by this function
* @cipher_name: Name of the cipher * @cipher_name: Name of the cipher
* @key_size: Size of the key in bytes * @key_size: Size of the key in bytes
@ -1786,8 +1831,8 @@ out:
* event, regardless of whether this function succeeds for fails. * event, regardless of whether this function succeeds for fails.
*/ */
int int
ecryptfs_process_cipher(struct crypto_blkcipher **key_tfm, char *cipher_name, ecryptfs_process_key_cipher(struct crypto_blkcipher **key_tfm,
size_t *key_size) char *cipher_name, size_t *key_size)
{ {
char dummy_key[ECRYPTFS_MAX_KEY_BYTES]; char dummy_key[ECRYPTFS_MAX_KEY_BYTES];
char *full_alg_name; char *full_alg_name;
@ -1829,3 +1874,98 @@ ecryptfs_process_cipher(struct crypto_blkcipher **key_tfm, char *cipher_name,
out: out:
return rc; return rc;
} }
struct kmem_cache *ecryptfs_key_tfm_cache;
struct list_head key_tfm_list;
struct mutex key_tfm_list_mutex;
int ecryptfs_init_crypto(void)
{
mutex_init(&key_tfm_list_mutex);
INIT_LIST_HEAD(&key_tfm_list);
return 0;
}
int ecryptfs_destruct_crypto(void)
{
struct ecryptfs_key_tfm *key_tfm, *key_tfm_tmp;
mutex_lock(&key_tfm_list_mutex);
list_for_each_entry_safe(key_tfm, key_tfm_tmp, &key_tfm_list,
key_tfm_list) {
list_del(&key_tfm->key_tfm_list);
if (key_tfm->key_tfm)
crypto_free_blkcipher(key_tfm->key_tfm);
kmem_cache_free(ecryptfs_key_tfm_cache, key_tfm);
}
mutex_unlock(&key_tfm_list_mutex);
return 0;
}
int
ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name,
size_t key_size)
{
struct ecryptfs_key_tfm *tmp_tfm;
int rc = 0;
tmp_tfm = kmem_cache_alloc(ecryptfs_key_tfm_cache, GFP_KERNEL);
if (key_tfm != NULL)
(*key_tfm) = tmp_tfm;
if (!tmp_tfm) {
rc = -ENOMEM;
printk(KERN_ERR "Error attempting to allocate from "
"ecryptfs_key_tfm_cache\n");
goto out;
}
mutex_init(&tmp_tfm->key_tfm_mutex);
strncpy(tmp_tfm->cipher_name, cipher_name,
ECRYPTFS_MAX_CIPHER_NAME_SIZE);
tmp_tfm->key_size = key_size;
if ((rc = ecryptfs_process_key_cipher(&tmp_tfm->key_tfm,
tmp_tfm->cipher_name,
&tmp_tfm->key_size))) {
printk(KERN_ERR "Error attempting to initialize key TFM "
"cipher with name = [%s]; rc = [%d]\n",
tmp_tfm->cipher_name, rc);
kmem_cache_free(ecryptfs_key_tfm_cache, tmp_tfm);
if (key_tfm != NULL)
(*key_tfm) = NULL;
goto out;
}
mutex_lock(&key_tfm_list_mutex);
list_add(&tmp_tfm->key_tfm_list, &key_tfm_list);
mutex_unlock(&key_tfm_list_mutex);
out:
return rc;
}
int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,
struct mutex **tfm_mutex,
char *cipher_name)
{
struct ecryptfs_key_tfm *key_tfm;
int rc = 0;
(*tfm) = NULL;
(*tfm_mutex) = NULL;
mutex_lock(&key_tfm_list_mutex);
list_for_each_entry(key_tfm, &key_tfm_list, key_tfm_list) {
if (strcmp(key_tfm->cipher_name, cipher_name) == 0) {
(*tfm) = key_tfm->key_tfm;
(*tfm_mutex) = &key_tfm->key_tfm_mutex;
mutex_unlock(&key_tfm_list_mutex);
goto out;
}
}
mutex_unlock(&key_tfm_list_mutex);
if ((rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0))) {
printk(KERN_ERR "Error adding new key_tfm to list; rc = [%d]\n",
rc);
goto out;
}
(*tfm) = key_tfm->key_tfm;
(*tfm_mutex) = &key_tfm->key_tfm_mutex;
out:
return rc;
}

View file

@ -48,10 +48,12 @@
#define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0x00000004 #define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0x00000004
#define ECRYPTFS_VERSIONING_POLICY 0x00000008 #define ECRYPTFS_VERSIONING_POLICY 0x00000008
#define ECRYPTFS_VERSIONING_XATTR 0x00000010 #define ECRYPTFS_VERSIONING_XATTR 0x00000010
#define ECRYPTFS_VERSIONING_MULTKEY 0x00000020
#define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \ #define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \
| ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH \ | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH \
| ECRYPTFS_VERSIONING_PUBKEY \ | ECRYPTFS_VERSIONING_PUBKEY \
| ECRYPTFS_VERSIONING_XATTR) | ECRYPTFS_VERSIONING_XATTR \
| ECRYPTFS_VERSIONING_MULTKEY)
#define ECRYPTFS_MAX_PASSWORD_LENGTH 64 #define ECRYPTFS_MAX_PASSWORD_LENGTH 64
#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH #define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH
#define ECRYPTFS_SALT_SIZE 8 #define ECRYPTFS_SALT_SIZE 8
@ -144,6 +146,7 @@ struct ecryptfs_private_key {
struct ecryptfs_auth_tok { struct ecryptfs_auth_tok {
u16 version; /* 8-bit major and 8-bit minor */ u16 version; /* 8-bit major and 8-bit minor */
u16 token_type; u16 token_type;
#define ECRYPTFS_ENCRYPT_ONLY 0x00000001
u32 flags; u32 flags;
struct ecryptfs_session_key session_key; struct ecryptfs_session_key session_key;
u8 reserved[32]; u8 reserved[32];
@ -153,6 +156,7 @@ struct ecryptfs_auth_tok {
} token; } token;
} __attribute__ ((packed)); } __attribute__ ((packed));
int ecryptfs_get_auth_tok_sig(char **sig, struct ecryptfs_auth_tok *auth_tok);
void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok); void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok);
extern void ecryptfs_to_hex(char *dst, char *src, size_t src_size); extern void ecryptfs_to_hex(char *dst, char *src, size_t src_size);
extern void ecryptfs_from_hex(char *dst, char *src, int dst_size); extern void ecryptfs_from_hex(char *dst, char *src, int dst_size);
@ -194,7 +198,6 @@ ecryptfs_get_key_payload_data(struct key *key)
#define ECRYPTFS_MAX_KEYSET_SIZE 1024 #define ECRYPTFS_MAX_KEYSET_SIZE 1024
#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32 #define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32
#define ECRYPTFS_MAX_NUM_ENC_KEYS 64 #define ECRYPTFS_MAX_NUM_ENC_KEYS 64
#define ECRYPTFS_MAX_NUM_KEYSIGS 2 /* TODO: Make this a linked list */
#define ECRYPTFS_MAX_IV_BYTES 16 /* 128 bits */ #define ECRYPTFS_MAX_IV_BYTES 16 /* 128 bits */
#define ECRYPTFS_SALT_BYTES 2 #define ECRYPTFS_SALT_BYTES 2
#define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5 #define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5
@ -212,6 +215,11 @@ ecryptfs_get_key_payload_data(struct key *key)
#define ECRYPTFS_TAG_67_PACKET_TYPE 0x43 #define ECRYPTFS_TAG_67_PACKET_TYPE 0x43
#define MD5_DIGEST_SIZE 16 #define MD5_DIGEST_SIZE 16
struct ecryptfs_key_sig {
struct list_head crypt_stat_list;
char keysig[ECRYPTFS_SIG_SIZE_HEX];
};
/** /**
* This is the primary struct associated with each encrypted file. * This is the primary struct associated with each encrypted file.
* *
@ -231,7 +239,6 @@ struct ecryptfs_crypt_stat {
u32 flags; u32 flags;
unsigned int file_version; unsigned int file_version;
size_t iv_bytes; size_t iv_bytes;
size_t num_keysigs;
size_t header_extent_size; size_t header_extent_size;
size_t num_header_extents_at_front; size_t num_header_extents_at_front;
size_t extent_size; /* Data extent size; default is 4096 */ size_t extent_size; /* Data extent size; default is 4096 */
@ -245,7 +252,8 @@ struct ecryptfs_crypt_stat {
unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE]; unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
unsigned char key[ECRYPTFS_MAX_KEY_BYTES]; unsigned char key[ECRYPTFS_MAX_KEY_BYTES];
unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES]; unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES];
unsigned char keysigs[ECRYPTFS_MAX_NUM_KEYSIGS][ECRYPTFS_SIG_SIZE_HEX]; struct list_head keysig_list;
struct mutex keysig_list_mutex;
struct mutex cs_tfm_mutex; struct mutex cs_tfm_mutex;
struct mutex cs_hash_tfm_mutex; struct mutex cs_hash_tfm_mutex;
struct mutex cs_mutex; struct mutex cs_mutex;
@ -265,6 +273,26 @@ struct ecryptfs_dentry_info {
struct ecryptfs_crypt_stat *crypt_stat; struct ecryptfs_crypt_stat *crypt_stat;
}; };
struct ecryptfs_global_auth_tok {
#define ECRYPTFS_AUTH_TOK_INVALID 0x00000001
u32 flags;
struct list_head mount_crypt_stat_list;
struct key *global_auth_tok_key;
struct ecryptfs_auth_tok *global_auth_tok;
unsigned char sig[ECRYPTFS_SIG_SIZE_HEX + 1];
};
struct ecryptfs_key_tfm {
struct crypto_blkcipher *key_tfm;
size_t key_size;
struct mutex key_tfm_mutex;
struct list_head key_tfm_list;
unsigned char cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
};
extern struct list_head key_tfm_list;
extern struct mutex key_tfm_list_mutex;
/** /**
* This struct is to enable a mount-wide passphrase/salt combo. This * This struct is to enable a mount-wide passphrase/salt combo. This
* is more or less a stopgap to provide similar functionality to other * is more or less a stopgap to provide similar functionality to other
@ -276,15 +304,14 @@ struct ecryptfs_mount_crypt_stat {
#define ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED 0x00000001 #define ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED 0x00000001
#define ECRYPTFS_XATTR_METADATA_ENABLED 0x00000002 #define ECRYPTFS_XATTR_METADATA_ENABLED 0x00000002
#define ECRYPTFS_ENCRYPTED_VIEW_ENABLED 0x00000004 #define ECRYPTFS_ENCRYPTED_VIEW_ENABLED 0x00000004
#define ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED 0x00000008
u32 flags; u32 flags;
struct ecryptfs_auth_tok *global_auth_tok; struct list_head global_auth_tok_list;
struct key *global_auth_tok_key; struct mutex global_auth_tok_list_mutex;
size_t num_global_auth_toks;
size_t global_default_cipher_key_size; size_t global_default_cipher_key_size;
struct crypto_blkcipher *global_key_tfm;
struct mutex global_key_tfm_mutex;
unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE
+ 1]; + 1];
unsigned char global_auth_tok_sig[ECRYPTFS_SIG_SIZE_HEX + 1];
}; };
/* superblock private data. */ /* superblock private data. */
@ -468,6 +495,9 @@ extern struct kmem_cache *ecryptfs_header_cache_2;
extern struct kmem_cache *ecryptfs_xattr_cache; extern struct kmem_cache *ecryptfs_xattr_cache;
extern struct kmem_cache *ecryptfs_lower_page_cache; extern struct kmem_cache *ecryptfs_lower_page_cache;
extern struct kmem_cache *ecryptfs_key_record_cache; extern struct kmem_cache *ecryptfs_key_record_cache;
extern struct kmem_cache *ecryptfs_key_sig_cache;
extern struct kmem_cache *ecryptfs_global_auth_tok_cache;
extern struct kmem_cache *ecryptfs_key_tfm_cache;
int ecryptfs_interpose(struct dentry *hidden_dentry, int ecryptfs_interpose(struct dentry *hidden_dentry,
struct dentry *this_dentry, struct super_block *sb, struct dentry *this_dentry, struct super_block *sb,
@ -538,9 +568,8 @@ int
ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
unsigned char *src, struct dentry *ecryptfs_dentry); unsigned char *src, struct dentry *ecryptfs_dentry);
int ecryptfs_truncate(struct dentry *dentry, loff_t new_length); int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
int int ecryptfs_process_key_cipher(struct crypto_blkcipher **key_tfm,
ecryptfs_process_cipher(struct crypto_blkcipher **key_tfm, char *cipher_name, char *cipher_name, size_t *key_size);
size_t *key_size);
int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode); int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode);
int ecryptfs_inode_set(struct inode *inode, void *lower_inode); int ecryptfs_inode_set(struct inode *inode, void *lower_inode);
void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode); void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode);
@ -580,6 +609,24 @@ void
ecryptfs_write_header_metadata(char *virt, ecryptfs_write_header_metadata(char *virt,
struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_crypt_stat *crypt_stat,
size_t *written); size_t *written);
int ecryptfs_add_keysig(struct ecryptfs_crypt_stat *crypt_stat, char *sig);
int
ecryptfs_add_global_auth_tok(struct ecryptfs_mount_crypt_stat *mount_crypt_stat,
char *sig);
int ecryptfs_get_global_auth_tok_for_sig(
struct ecryptfs_global_auth_tok **global_auth_tok,
struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig);
int
ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name,
size_t key_size);
int ecryptfs_init_crypto(void);
int ecryptfs_destruct_crypto(void);
int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,
struct mutex **tfm_mutex,
char *cipher_name);
int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key,
struct ecryptfs_auth_tok **auth_tok,
char *sig);
int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start, int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start,
int num_zeros); int num_zeros);

File diff suppressed because it is too large Load diff

View file

@ -179,38 +179,40 @@ static match_table_t tokens = {
{ecryptfs_opt_err, NULL} {ecryptfs_opt_err, NULL}
}; };
/** static int ecryptfs_init_global_auth_toks(
* ecryptfs_verify_version struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
* @version: The version number to confirm
*
* Returns zero on good version; non-zero otherwise
*/
static int ecryptfs_verify_version(u16 version)
{ {
struct ecryptfs_global_auth_tok *global_auth_tok;
int rc = 0; int rc = 0;
unsigned char major;
unsigned char minor;
major = ((version >> 8) & 0xFF); list_for_each_entry(global_auth_tok,
minor = (version & 0xFF); &mount_crypt_stat->global_auth_tok_list,
if (major != ECRYPTFS_VERSION_MAJOR) { mount_crypt_stat_list) {
ecryptfs_printk(KERN_ERR, "Major version number mismatch. " if ((rc = ecryptfs_keyring_auth_tok_for_sig(
"Expected [%d]; got [%d]\n", &global_auth_tok->global_auth_tok_key,
ECRYPTFS_VERSION_MAJOR, major); &global_auth_tok->global_auth_tok,
rc = -EINVAL; global_auth_tok->sig))) {
goto out; printk(KERN_ERR "Could not find valid key in user "
"session keyring for sig specified in mount "
"option: [%s]\n", global_auth_tok->sig);
global_auth_tok->flags |= ECRYPTFS_AUTH_TOK_INVALID;
rc = 0;
} else
global_auth_tok->flags &= ~ECRYPTFS_AUTH_TOK_INVALID;
} }
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; return rc;
} }
static void ecryptfs_init_mount_crypt_stat(
struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
{
memset((void *)mount_crypt_stat, 0,
sizeof(struct ecryptfs_mount_crypt_stat));
INIT_LIST_HEAD(&mount_crypt_stat->global_auth_tok_list);
mutex_init(&mount_crypt_stat->global_auth_tok_list_mutex);
mount_crypt_stat->flags |= ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED;
}
/** /**
* ecryptfs_parse_options * ecryptfs_parse_options
* @sb: The ecryptfs super block * @sb: The ecryptfs super block
@ -264,14 +266,13 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options)
case ecryptfs_opt_sig: case ecryptfs_opt_sig:
case ecryptfs_opt_ecryptfs_sig: case ecryptfs_opt_ecryptfs_sig:
sig_src = args[0].from; sig_src = args[0].from;
sig_dst = rc = ecryptfs_add_global_auth_tok(mount_crypt_stat,
mount_crypt_stat->global_auth_tok_sig; sig_src);
memcpy(sig_dst, sig_src, ECRYPTFS_SIG_SIZE_HEX); if (rc) {
sig_dst[ECRYPTFS_SIG_SIZE_HEX] = '\0'; printk(KERN_ERR "Error attempting to register "
ecryptfs_printk(KERN_DEBUG, "global sig; rc = [%d]\n", rc);
"The mount_crypt_stat " goto out;
"global_auth_tok_sig set to: " }
"[%s]\n", sig_dst);
sig_set = 1; sig_set = 1;
break; break;
case ecryptfs_opt_debug: case ecryptfs_opt_debug:
@ -358,55 +359,21 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options)
if (!cipher_key_bytes_set) { if (!cipher_key_bytes_set) {
mount_crypt_stat->global_default_cipher_key_size = 0; mount_crypt_stat->global_default_cipher_key_size = 0;
} }
rc = ecryptfs_process_cipher( if ((rc = ecryptfs_add_new_key_tfm(
&mount_crypt_stat->global_key_tfm, NULL, mount_crypt_stat->global_default_cipher_name,
mount_crypt_stat->global_default_cipher_name, mount_crypt_stat->global_default_cipher_key_size))) {
&mount_crypt_stat->global_default_cipher_key_size); printk(KERN_ERR "Error attempting to initialize cipher with "
if (rc) { "name = [%s] and key size = [%d]; rc = [%d]\n",
printk(KERN_ERR "Error attempting to initialize cipher [%s] "
"with key size [%Zd] bytes; rc = [%d]\n",
mount_crypt_stat->global_default_cipher_name, mount_crypt_stat->global_default_cipher_name,
mount_crypt_stat->global_default_cipher_key_size, rc); mount_crypt_stat->global_default_cipher_key_size, rc);
mount_crypt_stat->global_key_tfm = NULL;
mount_crypt_stat->global_auth_tok_key = NULL;
rc = -EINVAL; rc = -EINVAL;
goto out; goto out;
} }
mutex_init(&mount_crypt_stat->global_key_tfm_mutex); if ((rc = ecryptfs_init_global_auth_toks(mount_crypt_stat))) {
ecryptfs_printk(KERN_DEBUG, "Requesting the key with description: " printk(KERN_WARNING "One or more global auth toks could not "
"[%s]\n", mount_crypt_stat->global_auth_tok_sig); "properly register; rc = [%d]\n", rc);
/* The reference to this key is held until umount is done The
* call to key_put is done in ecryptfs_put_super() */
auth_tok_key = request_key(&key_type_user,
mount_crypt_stat->global_auth_tok_sig,
NULL);
if (!auth_tok_key || IS_ERR(auth_tok_key)) {
ecryptfs_printk(KERN_ERR, "Could not find key with "
"description: [%s]\n",
mount_crypt_stat->global_auth_tok_sig);
process_request_key_err(PTR_ERR(auth_tok_key));
rc = -EINVAL;
goto out;
} }
auth_tok = ecryptfs_get_key_payload_data(auth_tok_key); rc = 0;
if (ecryptfs_verify_version(auth_tok->version)) {
ecryptfs_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) {
ecryptfs_printk(KERN_ERR, "Invalid auth_tok structure "
"returned from key query\n");
rc = -EINVAL;
goto out;
}
mount_crypt_stat->global_auth_tok_key = auth_tok_key;
mount_crypt_stat->global_auth_tok = auth_tok;
out: out:
return rc; return rc;
} }