eCryptfs: initialize crypt_stat in setattr
authorMichael Halcrow <mhalcrow@us.ibm.com>
Wed, 27 Jun 2007 21:09:44 +0000 (14:09 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 28 Jun 2007 18:34:53 +0000 (11:34 -0700)
Recent changes in eCryptfs have made it possible to get to ecryptfs_setattr()
with an uninitialized crypt_stat struct.  This results in a wide and colorful
variety of unpleasantries.  This patch properly initializes the crypt_stat
structure in ecryptfs_setattr() when it is necessary to do so.

Signed-off-by: Michael Halcrow <mhalcrow@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/ecryptfs/inode.c

index 0981ae35ea164531ae0f127dbb6de120d7a7f56c..83e94fedd4e9cf3b4d6067df811b48afffe62f1e 100644 (file)
@@ -894,9 +894,54 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
        struct ecryptfs_crypt_stat *crypt_stat;
 
        crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
        struct ecryptfs_crypt_stat *crypt_stat;
 
        crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
-       lower_dentry = ecryptfs_dentry_to_lower(dentry);
+       if (!(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED))
+               ecryptfs_init_crypt_stat(crypt_stat);
        inode = dentry->d_inode;
        lower_inode = ecryptfs_inode_to_lower(inode);
        inode = dentry->d_inode;
        lower_inode = ecryptfs_inode_to_lower(inode);
+       lower_dentry = ecryptfs_dentry_to_lower(dentry);
+       mutex_lock(&crypt_stat->cs_mutex);
+       if (S_ISDIR(dentry->d_inode->i_mode))
+               crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
+       else if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)
+                || !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) {
+               struct vfsmount *lower_mnt;
+               struct file *lower_file = NULL;
+               struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
+               int lower_flags;
+
+               lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+               lower_flags = O_RDONLY;
+               if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry,
+                                                  lower_mnt, lower_flags))) {
+                       printk(KERN_ERR
+                              "Error opening lower file; rc = [%d]\n", rc);
+                       mutex_unlock(&crypt_stat->cs_mutex);
+                       goto out;
+               }
+               mount_crypt_stat = &ecryptfs_superblock_to_private(
+                       dentry->d_sb)->mount_crypt_stat;
+               if ((rc = ecryptfs_read_metadata(dentry, lower_file))) {
+                       if (!(mount_crypt_stat->flags
+                             & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
+                               rc = -EIO;
+                               printk(KERN_WARNING "Attempt to read file that "
+                                      "is not in a valid eCryptfs format, "
+                                      "and plaintext passthrough mode is not "
+                                      "enabled; returning -EIO\n");
+
+                               mutex_unlock(&crypt_stat->cs_mutex);
+                               fput(lower_file);
+                               goto out;
+                       }
+                       rc = 0;
+                       crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
+                       mutex_unlock(&crypt_stat->cs_mutex);
+                       fput(lower_file);
+                       goto out;
+               }
+               fput(lower_file);
+       }
+       mutex_unlock(&crypt_stat->cs_mutex);
        if (ia->ia_valid & ATTR_SIZE) {
                ecryptfs_printk(KERN_DEBUG,
                                "ia->ia_valid = [0x%x] ATTR_SIZE" " = [0x%x]\n",
        if (ia->ia_valid & ATTR_SIZE) {
                ecryptfs_printk(KERN_DEBUG,
                                "ia->ia_valid = [0x%x] ATTR_SIZE" " = [0x%x]\n",