From 48b512e6857139393cdfce26348c362b87537018 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Tue, 5 Oct 2010 18:53:45 +0200 Subject: [PATCH 1/6] ecryptfs: call vfs_setxattr() in ecryptfs_setxattr() Ecryptfs is a stackable filesystem which relies on lower filesystems the ability of setting/getting extended attributes. If there is a security module enabled on the system it updates the 'security' field of inodes according to the owned extended attribute set with the function vfs_setxattr(). When this function is performed on a ecryptfs filesystem the 'security' field is not updated for the lower filesystem since the call security_inode_post_setxattr() is missing for the lower inode. Further, the call security_inode_setxattr() is missing for the lower inode, leading to policy violations in the security module because specific checks for this hook are not performed (i. e. filesystem 'associate' permission on SELinux is not checked for the lower filesystem). This patch replaces the call of the setxattr() method of the lower inode in the function ecryptfs_setxattr() with vfs_setxattr(). Signed-off-by: Roberto Sassu Cc: stable Cc: Dustin Kirkland Acked-by: James Morris Signed-off-by: Tyler Hicks --- fs/ecryptfs/inode.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 3fbc94203380..63e6ec0e8b50 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "ecryptfs_kernel.h" @@ -1108,10 +1109,8 @@ ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value, rc = -EOPNOTSUPP; goto out; } - mutex_lock(&lower_dentry->d_inode->i_mutex); - rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry, name, value, - size, flags); - mutex_unlock(&lower_dentry->d_inode->i_mutex); + + rc = vfs_setxattr(lower_dentry, name, value, size, flags); out: return rc; } From 2e21b3f124eceb6ab5a07c8a061adce14ac94e14 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Thu, 23 Sep 2010 02:35:04 -0500 Subject: [PATCH 2/6] eCryptfs: Clear LOOKUP_OPEN flag when creating lower file eCryptfs was passing the LOOKUP_OPEN flag through to the lower file system, even though ecryptfs_create() doesn't support the flag. A valid filp for the lower filesystem could be returned in the nameidata if the lower file system's create() function supported LOOKUP_OPEN, possibly resulting in unencrypted writes to the lower file. However, this is only a potential problem in filesystems (FUSE, NFS, CIFS, CEPH, 9p) that eCryptfs isn't known to support today. https://bugs.launchpad.net/ecryptfs/+bug/641703 Reported-by: Kevin Buhr Cc: stable Signed-off-by: Tyler Hicks --- fs/ecryptfs/inode.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 63e6ec0e8b50..9d1a22d62765 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -71,15 +71,19 @@ ecryptfs_create_underlying_file(struct inode *lower_dir_inode, struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); struct dentry *dentry_save; struct vfsmount *vfsmount_save; + unsigned int flags_save; int rc; dentry_save = nd->path.dentry; vfsmount_save = nd->path.mnt; + flags_save = nd->flags; nd->path.dentry = lower_dentry; nd->path.mnt = lower_mnt; + nd->flags &= ~LOOKUP_OPEN; rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd); nd->path.dentry = dentry_save; nd->path.mnt = vfsmount_save; + nd->flags = flags_save; return rc; } From aee683b9e77e17237b0e146025c3d363c9203634 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Wed, 6 Oct 2010 18:31:06 +0200 Subject: [PATCH 3/6] ecryptfs: release keys loaded in ecryptfs_keyring_auth_tok_for_sig() This patch allows keys requested in the function ecryptfs_keyring_auth_tok_for_sig()to be released when they are no longer required. In particular keys are directly released in the same function if the obtained authentication token is not valid. Further, a new function parameter 'auth_tok_key' has been added to ecryptfs_find_auth_tok_for_sig() in order to provide callers the key pointer to be passed to key_put(). Signed-off-by: Roberto Sassu Cc: Dustin Kirkland Cc: James Morris [Tyler: Initialize auth_tok_key to NULL in ecryptfs_parse_packet_set] Signed-off-by: Tyler Hicks --- fs/ecryptfs/keystore.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index 73811cfa2ea4..b85c6a7770a8 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -446,6 +446,7 @@ ecryptfs_find_global_auth_tok_for_sig( */ static int ecryptfs_find_auth_tok_for_sig( + struct key **auth_tok_key, struct ecryptfs_auth_tok **auth_tok, struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig) @@ -453,12 +454,12 @@ ecryptfs_find_auth_tok_for_sig( struct ecryptfs_global_auth_tok *global_auth_tok; int rc = 0; + (*auth_tok_key) = NULL; (*auth_tok) = NULL; if (ecryptfs_find_global_auth_tok_for_sig(&global_auth_tok, mount_crypt_stat, sig)) { - struct key *auth_tok_key; - 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); } else (*auth_tok) = global_auth_tok->global_auth_tok; @@ -509,6 +510,7 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes, char *filename, size_t filename_size) { struct ecryptfs_write_tag_70_packet_silly_stack *s; + struct key *auth_tok_key = NULL; int rc = 0; s = kmalloc(sizeof(*s), GFP_KERNEL); @@ -606,6 +608,7 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes, } dest[s->i++] = s->cipher_code; rc = ecryptfs_find_auth_tok_for_sig( + &auth_tok_key, &s->auth_tok, mount_crypt_stat, mount_crypt_stat->global_default_fnek_sig); if (rc) { @@ -753,6 +756,8 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes, out_unlock: mutex_unlock(s->tfm_mutex); out: + if (auth_tok_key) + key_put(auth_tok_key); kfree(s); return rc; } @@ -798,6 +803,7 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size, char *data, size_t max_packet_size) { struct ecryptfs_parse_tag_70_packet_silly_stack *s; + struct key *auth_tok_key = NULL; int rc = 0; (*packet_size) = 0; @@ -910,7 +916,8 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size, * >= ECRYPTFS_MAX_IV_BYTES. */ memset(s->iv, 0, ECRYPTFS_MAX_IV_BYTES); s->desc.info = s->iv; - rc = ecryptfs_find_auth_tok_for_sig(&s->auth_tok, mount_crypt_stat, + rc = ecryptfs_find_auth_tok_for_sig(&auth_tok_key, + &s->auth_tok, mount_crypt_stat, s->fnek_sig_hex); if (rc) { printk(KERN_ERR "%s: Error attempting to find auth tok for " @@ -986,6 +993,8 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size, (*filename_size) = 0; (*filename) = NULL; } + if (auth_tok_key) + key_put(auth_tok_key); kfree(s); return rc; } @@ -1557,14 +1566,19 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, ECRYPTFS_VERSION_MAJOR, ECRYPTFS_VERSION_MINOR); rc = -EINVAL; - goto out; + 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; + goto out_release_key; + } +out_release_key: + if (rc) { + key_put(*auth_tok_key); + (*auth_tok_key) = NULL; } out: return rc; @@ -1688,6 +1702,7 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_auth_tok_list_item *auth_tok_list_item; size_t tag_11_contents_size; size_t tag_11_packet_size; + struct key *auth_tok_key = NULL; int rc = 0; INIT_LIST_HEAD(&auth_tok_list); @@ -1784,6 +1799,10 @@ 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) { + 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)) { @@ -1800,7 +1819,8 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, rc = -EINVAL; goto out_wipe_list; } - ecryptfs_find_auth_tok_for_sig(&matching_auth_tok, + ecryptfs_find_auth_tok_for_sig(&auth_tok_key, + &matching_auth_tok, crypt_stat->mount_crypt_stat, candidate_auth_tok_sig); if (matching_auth_tok) { @@ -1866,6 +1886,8 @@ 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) + key_put(auth_tok_key); return rc; } From 39fac853a758306285404368fbe392408057b136 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Wed, 6 Oct 2010 18:31:15 +0200 Subject: [PATCH 4/6] ecryptfs: checking return code of ecryptfs_find_auth_tok_for_sig() This patch replaces the check of the 'matching_auth_tok' pointer with the exit status of ecryptfs_find_auth_tok_for_sig(). This avoids to use authentication tokens obtained through the function ecryptfs_keyring_auth_tok_for_sig which are not valid. Signed-off-by: Roberto Sassu Cc: Dustin Kirkland Cc: James Morris Signed-off-by: Tyler Hicks --- fs/ecryptfs/keystore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index b85c6a7770a8..e7f029f00c6b 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -1819,11 +1819,11 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, rc = -EINVAL; goto out_wipe_list; } - ecryptfs_find_auth_tok_for_sig(&auth_tok_key, + rc = ecryptfs_find_auth_tok_for_sig(&auth_tok_key, &matching_auth_tok, crypt_stat->mount_crypt_stat, candidate_auth_tok_sig); - if (matching_auth_tok) { + if (!rc) { found_auth_tok = 1; goto found_matching_auth_tok; } From f16feb5119a87f5e683be7e8916c060abfb0e8d6 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Wed, 6 Oct 2010 18:31:32 +0200 Subject: [PATCH 5/6] ecryptfs: added ecryptfs_mount_auth_tok_only mount parameter This patch adds a new mount parameter 'ecryptfs_mount_auth_tok_only' to force ecryptfs to use only authentication tokens which signature has been specified at mount time with parameters 'ecryptfs_sig' and 'ecryptfs_fnek_sig'. In this way, after disabling the passthrough and the encrypted view modes, it's possible to make available to users only files encrypted with the specified authentication token. Signed-off-by: Roberto Sassu Cc: Dustin Kirkland Cc: James Morris [Tyler: Clean up coding style errors found by checkpatch] Signed-off-by: Tyler Hicks --- fs/ecryptfs/ecryptfs_kernel.h | 1 + fs/ecryptfs/keystore.c | 9 +++++++++ fs/ecryptfs/main.c | 8 +++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index 0032a9f5a3a9..59ab793fc01b 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -377,6 +377,7 @@ struct ecryptfs_mount_crypt_stat { #define ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES 0x00000010 #define ECRYPTFS_GLOBAL_ENCFN_USE_MOUNT_FNEK 0x00000020 #define ECRYPTFS_GLOBAL_ENCFN_USE_FEK 0x00000040 +#define ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY 0x00000080 u32 flags; struct list_head global_auth_tok_list; struct mutex global_auth_tok_list_mutex; diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index e7f029f00c6b..b1f6858a5223 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -459,6 +459,15 @@ ecryptfs_find_auth_tok_for_sig( if (ecryptfs_find_global_auth_tok_for_sig(&global_auth_tok, mount_crypt_stat, sig)) { + /* if the flag ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY is set in the + * mount_crypt_stat structure, we prevent to use auth toks that + * are not inserted through the ecryptfs_add_global_auth_tok + * function. + */ + if (mount_crypt_stat->flags + & ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY) + return -EINVAL; + rc = ecryptfs_keyring_auth_tok_for_sig(auth_tok_key, auth_tok, sig); } else diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index cbd4e18adb20..09eb5296aebb 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -208,7 +208,8 @@ enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata, ecryptfs_opt_encrypted_view, ecryptfs_opt_fnek_sig, ecryptfs_opt_fn_cipher, ecryptfs_opt_fn_cipher_key_bytes, - ecryptfs_opt_unlink_sigs, ecryptfs_opt_err }; + ecryptfs_opt_unlink_sigs, ecryptfs_opt_mount_auth_tok_only, + ecryptfs_opt_err }; static const match_table_t tokens = { {ecryptfs_opt_sig, "sig=%s"}, @@ -223,6 +224,7 @@ static const match_table_t tokens = { {ecryptfs_opt_fn_cipher, "ecryptfs_fn_cipher=%s"}, {ecryptfs_opt_fn_cipher_key_bytes, "ecryptfs_fn_key_bytes=%u"}, {ecryptfs_opt_unlink_sigs, "ecryptfs_unlink_sigs"}, + {ecryptfs_opt_mount_auth_tok_only, "ecryptfs_mount_auth_tok_only"}, {ecryptfs_opt_err, NULL} }; @@ -406,6 +408,10 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options) case ecryptfs_opt_unlink_sigs: mount_crypt_stat->flags |= ECRYPTFS_UNLINK_SIGS; break; + case ecryptfs_opt_mount_auth_tok_only: + mount_crypt_stat->flags |= + ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY; + break; case ecryptfs_opt_err: default: printk(KERN_WARNING From 8747f954817212b4623f9067d4909cbde04b4d89 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Fri, 15 Oct 2010 16:43:41 -0500 Subject: [PATCH 6/6] eCryptfs: Print mount_auth_tok_only param in ecryptfs_show_options When printing mount options, print the new ecryptfs_mount_auth_tok_only mount option. Signed-off-by: Tyler Hicks --- fs/ecryptfs/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index f7fc286a3aa9..253732382d37 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c @@ -180,6 +180,8 @@ static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt) seq_printf(m, ",ecryptfs_encrypted_view"); if (mount_crypt_stat->flags & ECRYPTFS_UNLINK_SIGS) seq_printf(m, ",ecryptfs_unlink_sigs"); + if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY) + seq_printf(m, ",ecryptfs_mount_auth_tok_only"); return 0; }