Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ecryptfs...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 19 Apr 2010 21:20:32 +0000 (14:20 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 19 Apr 2010 21:20:32 +0000 (14:20 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ecryptfs/ecryptfs-2.6:
  eCryptfs: Turn lower lookup error messages into debug messages
  eCryptfs: Copy lower directory inode times and size on link
  ecryptfs: fix use with tmpfs by removing d_drop from ecryptfs_destroy_inode
  ecryptfs: fix error code for missing xattrs in lower fs
  eCryptfs: Decrypt symlink target for stat size
  eCryptfs: Strip metadata in xattr flag in encrypted view
  eCryptfs: Clear buffer before reading in metadata xattr
  eCryptfs: Rename ecryptfs_crypt_stat.num_header_bytes_at_front
  eCryptfs: Fix metadata in xattr feature regression

1  2 
fs/ecryptfs/crypto.c
fs/ecryptfs/inode.c
fs/ecryptfs/mmap.c
fs/ecryptfs/super.c

diff --combined fs/ecryptfs/crypto.c
@@@ -33,7 -33,6 +33,7 @@@
  #include <linux/crypto.h>
  #include <linux/file.h>
  #include <linux/scatterlist.h>
 +#include <linux/slab.h>
  #include <asm/unaligned.h>
  #include "ecryptfs_kernel.h"
  
@@@ -382,8 -381,8 +382,8 @@@ out
  static void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
                                             struct ecryptfs_crypt_stat *crypt_stat)
  {
-       (*offset) = (crypt_stat->num_header_bytes_at_front
-                    + (crypt_stat->extent_size * extent_num));
+       (*offset) = ecryptfs_lower_header_size(crypt_stat)
+                   + (crypt_stat->extent_size * extent_num);
  }
  
  /**
@@@ -835,13 -834,13 +835,13 @@@ void ecryptfs_set_default_sizes(struct 
        set_extent_mask_and_shift(crypt_stat);
        crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;
        if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
-               crypt_stat->num_header_bytes_at_front = 0;
+               crypt_stat->metadata_size = ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
        else {
                if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)
-                       crypt_stat->num_header_bytes_at_front =
+                       crypt_stat->metadata_size =
                                ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
                else
-                       crypt_stat->num_header_bytes_at_front = PAGE_CACHE_SIZE;
+                       crypt_stat->metadata_size = PAGE_CACHE_SIZE;
        }
  }
  
@@@ -1108,9 -1107,9 +1108,9 @@@ static void write_ecryptfs_marker(char 
        (*written) = MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
  }
  
- static void
write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat,
-                    size_t *written)
+ void ecryptfs_write_crypt_stat_flags(char *page_virt,
                                   struct ecryptfs_crypt_stat *crypt_stat,
+                                    size_t *written)
  {
        u32 flags = 0;
        int i;
@@@ -1238,8 -1237,7 +1238,7 @@@ ecryptfs_write_header_metadata(char *vi
  
        header_extent_size = (u32)crypt_stat->extent_size;
        num_header_extents_at_front =
-               (u16)(crypt_stat->num_header_bytes_at_front
-                     / crypt_stat->extent_size);
+               (u16)(crypt_stat->metadata_size / crypt_stat->extent_size);
        put_unaligned_be32(header_extent_size, virt);
        virt += 4;
        put_unaligned_be16(num_header_extents_at_front, virt);
@@@ -1292,7 -1290,8 +1291,8 @@@ static int ecryptfs_write_headers_virt(
        offset = ECRYPTFS_FILE_SIZE_BYTES;
        write_ecryptfs_marker((page_virt + offset), &written);
        offset += written;
-       write_ecryptfs_flags((page_virt + offset), crypt_stat, &written);
+       ecryptfs_write_crypt_stat_flags((page_virt + offset), crypt_stat,
+                                       &written);
        offset += written;
        ecryptfs_write_header_metadata((page_virt + offset), crypt_stat,
                                       &written);
@@@ -1382,7 -1381,7 +1382,7 @@@ int ecryptfs_write_metadata(struct dent
                rc = -EINVAL;
                goto out;
        }
-       virt_len = crypt_stat->num_header_bytes_at_front;
+       virt_len = crypt_stat->metadata_size;
        order = get_order(virt_len);
        /* Released in this function */
        virt = (char *)ecryptfs_get_zeroed_pages(GFP_KERNEL, order);
@@@ -1428,16 -1427,15 +1428,15 @@@ static int parse_header_metadata(struc
        header_extent_size = get_unaligned_be32(virt);
        virt += sizeof(__be32);
        num_header_extents_at_front = get_unaligned_be16(virt);
-       crypt_stat->num_header_bytes_at_front =
-               (((size_t)num_header_extents_at_front
-                 * (size_t)header_extent_size));
+       crypt_stat->metadata_size = (((size_t)num_header_extents_at_front
+                                    * (size_t)header_extent_size));
        (*bytes_read) = (sizeof(__be32) + sizeof(__be16));
        if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE)
-           && (crypt_stat->num_header_bytes_at_front
+           && (crypt_stat->metadata_size
                < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) {
                rc = -EINVAL;
                printk(KERN_WARNING "Invalid header size: [%zd]\n",
-                      crypt_stat->num_header_bytes_at_front);
+                      crypt_stat->metadata_size);
        }
        return rc;
  }
   */
  static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
  {
-       crypt_stat->num_header_bytes_at_front =
-               ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
+       crypt_stat->metadata_size = ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
  }
  
  /**
@@@ -1607,6 -1604,7 +1605,7 @@@ int ecryptfs_read_metadata(struct dentr
                                                ecryptfs_dentry,
                                                ECRYPTFS_VALIDATE_HEADER_SIZE);
        if (rc) {
+               memset(page_virt, 0, PAGE_CACHE_SIZE);
                rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_inode);
                if (rc) {
                        printk(KERN_DEBUG "Valid eCryptfs headers not found in "
diff --combined fs/ecryptfs/inode.c
@@@ -31,7 -31,6 +31,7 @@@
  #include <linux/mount.h>
  #include <linux/crypto.h>
  #include <linux/fs_stack.h>
 +#include <linux/slab.h>
  #include <asm/unaligned.h>
  #include "ecryptfs_kernel.h"
  
@@@ -324,6 -323,7 +324,7 @@@ int ecryptfs_lookup_and_interpose_lower
        rc = ecryptfs_read_and_validate_header_region(page_virt,
                                                      ecryptfs_dentry->d_inode);
        if (rc) {
+               memset(page_virt, 0, PAGE_CACHE_SIZE);
                rc = ecryptfs_read_and_validate_xattr_region(page_virt,
                                                             ecryptfs_dentry);
                if (rc) {
                ecryptfs_dentry->d_sb)->mount_crypt_stat;
        if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
                if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
-                       file_size = (crypt_stat->num_header_bytes_at_front
+                       file_size = (crypt_stat->metadata_size
                                     + i_size_read(lower_dentry->d_inode));
                else
                        file_size = i_size_read(lower_dentry->d_inode);
@@@ -388,9 -388,9 +389,9 @@@ static struct dentry *ecryptfs_lookup(s
        mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
        if (IS_ERR(lower_dentry)) {
                rc = PTR_ERR(lower_dentry);
-               printk(KERN_ERR "%s: lookup_one_len() returned [%d] on "
-                      "lower_dentry = [%s]\n", __func__, rc,
-                      ecryptfs_dentry->d_name.name);
+               ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "
+                               "[%d] on lower_dentry = [%s]\n", __func__, rc,
+                               encrypted_and_encoded_name);
                goto out_d_drop;
        }
        if (lower_dentry->d_inode)
        mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
        if (IS_ERR(lower_dentry)) {
                rc = PTR_ERR(lower_dentry);
-               printk(KERN_ERR "%s: lookup_one_len() returned [%d] on "
-                      "lower_dentry = [%s]\n", __func__, rc,
-                      encrypted_and_encoded_name);
+               ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "
+                               "[%d] on lower_dentry = [%s]\n", __func__, rc,
+                               encrypted_and_encoded_name);
                goto out_d_drop;
        }
  lookup_and_interpose:
@@@ -456,8 -456,8 +457,8 @@@ static int ecryptfs_link(struct dentry 
        rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
        if (rc)
                goto out_lock;
-       fsstack_copy_attr_times(dir, lower_new_dentry->d_inode);
-       fsstack_copy_inode_size(dir, lower_new_dentry->d_inode);
+       fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
+       fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
        old_dentry->d_inode->i_nlink =
                ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink;
        i_size_write(new_dentry->d_inode, file_size_save);
@@@ -648,38 -648,17 +649,17 @@@ out_lock
        return rc;
  }
  
- static int
ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
+ static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf,
                                 size_t *bufsiz)
  {
+       struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
        char *lower_buf;
-       size_t lower_bufsiz;
-       struct dentry *lower_dentry;
-       struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
-       char *plaintext_name;
-       size_t plaintext_name_size;
+       size_t lower_bufsiz = PATH_MAX;
        mm_segment_t old_fs;
        int rc;
  
-       lower_dentry = ecryptfs_dentry_to_lower(dentry);
-       if (!lower_dentry->d_inode->i_op->readlink) {
-               rc = -EINVAL;
-               goto out;
-       }
-       mount_crypt_stat = &ecryptfs_superblock_to_private(
-                                               dentry->d_sb)->mount_crypt_stat;
-       /*
-        * If the lower filename is encrypted, it will result in a significantly
-        * longer name.  If needed, truncate the name after decode and decrypt.
-        */
-       if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)
-               lower_bufsiz = PATH_MAX;
-       else
-               lower_bufsiz = bufsiz;
-       /* Released in this function */
        lower_buf = kmalloc(lower_bufsiz, GFP_KERNEL);
-       if (lower_buf == NULL) {
-               printk(KERN_ERR "%s: Out of memory whilst attempting to "
-                      "kmalloc [%zd] bytes\n", __func__, lower_bufsiz);
+       if (!lower_buf) {
                rc = -ENOMEM;
                goto out;
        }
                                                   (char __user *)lower_buf,
                                                   lower_bufsiz);
        set_fs(old_fs);
-       if (rc >= 0) {
-               rc = ecryptfs_decode_and_decrypt_filename(&plaintext_name,
-                                                         &plaintext_name_size,
-                                                         dentry, lower_buf,
-                                                         rc);
-               if (rc) {
-                       printk(KERN_ERR "%s: Error attempting to decode and "
-                              "decrypt filename; rc = [%d]\n", __func__,
-                               rc);
-                       goto out_free_lower_buf;
-               }
-               /* Check for bufsiz <= 0 done in sys_readlinkat() */
-               rc = copy_to_user(buf, plaintext_name,
-                                 min((size_t) bufsiz, plaintext_name_size));
-               if (rc)
-                       rc = -EFAULT;
-               else
-                       rc = plaintext_name_size;
-               kfree(plaintext_name);
-               fsstack_copy_attr_atime(dentry->d_inode, lower_dentry->d_inode);
-       }
- out_free_lower_buf:
+       if (rc < 0)
+               goto out;
+       lower_bufsiz = rc;
+       rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry,
+                                                 lower_buf, lower_bufsiz);
+ out:
        kfree(lower_buf);
+       return rc;
+ }
+ static int
+ ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
+ {
+       char *kbuf;
+       size_t kbufsiz, copied;
+       int rc;
+       rc = ecryptfs_readlink_lower(dentry, &kbuf, &kbufsiz);
+       if (rc)
+               goto out;
+       copied = min_t(size_t, bufsiz, kbufsiz);
+       rc = copy_to_user(buf, kbuf, copied) ? -EFAULT : copied;
+       kfree(kbuf);
+       fsstack_copy_attr_atime(dentry->d_inode,
+                               ecryptfs_dentry_to_lower(dentry)->d_inode);
  out:
        return rc;
  }
@@@ -769,7 -750,7 +751,7 @@@ upper_size_to_lower_size(struct ecryptf
  {
        loff_t lower_size;
  
-       lower_size = crypt_stat->num_header_bytes_at_front;
+       lower_size = ecryptfs_lower_header_size(crypt_stat);
        if (upper_size != 0) {
                loff_t num_extents;
  
@@@ -1016,6 -997,28 +998,28 @@@ out
        return rc;
  }
  
+ int ecryptfs_getattr_link(struct vfsmount *mnt, struct dentry *dentry,
+                         struct kstat *stat)
+ {
+       struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
+       int rc = 0;
+       mount_crypt_stat = &ecryptfs_superblock_to_private(
+                                               dentry->d_sb)->mount_crypt_stat;
+       generic_fillattr(dentry->d_inode, stat);
+       if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) {
+               char *target;
+               size_t targetsiz;
+               rc = ecryptfs_readlink_lower(dentry, &target, &targetsiz);
+               if (!rc) {
+                       kfree(target);
+                       stat->size = targetsiz;
+               }
+       }
+       return rc;
+ }
  int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
                     struct kstat *stat)
  {
@@@ -1040,7 -1043,7 +1044,7 @@@ ecryptfs_setxattr(struct dentry *dentry
  
        lower_dentry = ecryptfs_dentry_to_lower(dentry);
        if (!lower_dentry->d_inode->i_op->setxattr) {
-               rc = -ENOSYS;
+               rc = -EOPNOTSUPP;
                goto out;
        }
        mutex_lock(&lower_dentry->d_inode->i_mutex);
@@@ -1058,7 -1061,7 +1062,7 @@@ ecryptfs_getxattr_lower(struct dentry *
        int rc = 0;
  
        if (!lower_dentry->d_inode->i_op->getxattr) {
-               rc = -ENOSYS;
+               rc = -EOPNOTSUPP;
                goto out;
        }
        mutex_lock(&lower_dentry->d_inode->i_mutex);
@@@ -1085,7 -1088,7 +1089,7 @@@ ecryptfs_listxattr(struct dentry *dentr
  
        lower_dentry = ecryptfs_dentry_to_lower(dentry);
        if (!lower_dentry->d_inode->i_op->listxattr) {
-               rc = -ENOSYS;
+               rc = -EOPNOTSUPP;
                goto out;
        }
        mutex_lock(&lower_dentry->d_inode->i_mutex);
@@@ -1102,7 -1105,7 +1106,7 @@@ static int ecryptfs_removexattr(struct 
  
        lower_dentry = ecryptfs_dentry_to_lower(dentry);
        if (!lower_dentry->d_inode->i_op->removexattr) {
-               rc = -ENOSYS;
+               rc = -EOPNOTSUPP;
                goto out;
        }
        mutex_lock(&lower_dentry->d_inode->i_mutex);
@@@ -1133,6 -1136,7 +1137,7 @@@ const struct inode_operations ecryptfs_
        .put_link = ecryptfs_put_link,
        .permission = ecryptfs_permission,
        .setattr = ecryptfs_setattr,
+       .getattr = ecryptfs_getattr_link,
        .setxattr = ecryptfs_setxattr,
        .getxattr = ecryptfs_getxattr,
        .listxattr = ecryptfs_listxattr,
diff --combined fs/ecryptfs/mmap.c
@@@ -32,7 -32,6 +32,7 @@@
  #include <linux/file.h>
  #include <linux/crypto.h>
  #include <linux/scatterlist.h>
 +#include <linux/slab.h>
  #include <asm/unaligned.h>
  #include "ecryptfs_kernel.h"
  
@@@ -83,6 -82,19 +83,19 @@@ out
        return rc;
  }
  
+ static void strip_xattr_flag(char *page_virt,
+                            struct ecryptfs_crypt_stat *crypt_stat)
+ {
+       if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) {
+               size_t written;
+               crypt_stat->flags &= ~ECRYPTFS_METADATA_IN_XATTR;
+               ecryptfs_write_crypt_stat_flags(page_virt, crypt_stat,
+                                               &written);
+               crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;
+       }
+ }
  /**
   *   Header Extent:
   *     Octets 0-7:        Unencrypted file size (big-endian)
   *                        (big-endian)
   *     Octet  26:         Begin RFC 2440 authentication token packet set
   */
- static void set_header_info(char *page_virt,
-                           struct ecryptfs_crypt_stat *crypt_stat)
- {
-       size_t written;
-       size_t save_num_header_bytes_at_front =
-               crypt_stat->num_header_bytes_at_front;
-       crypt_stat->num_header_bytes_at_front =
-               ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
-       ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written);
-       crypt_stat->num_header_bytes_at_front =
-               save_num_header_bytes_at_front;
- }
  
  /**
   * ecryptfs_copy_up_encrypted_with_header
@@@ -136,8 -135,7 +136,7 @@@ ecryptfs_copy_up_encrypted_with_header(
                                           * num_extents_per_page)
                                          + extent_num_in_page);
                size_t num_header_extents_at_front =
-                       (crypt_stat->num_header_bytes_at_front
-                        / crypt_stat->extent_size);
+                       (crypt_stat->metadata_size / crypt_stat->extent_size);
  
                if (view_extent_num < num_header_extents_at_front) {
                        /* This is a header extent */
                        memset(page_virt, 0, PAGE_CACHE_SIZE);
                        /* TODO: Support more than one header extent */
                        if (view_extent_num == 0) {
+                               size_t written;
                                rc = ecryptfs_read_xattr_region(
                                        page_virt, page->mapping->host);
-                               set_header_info(page_virt, crypt_stat);
+                               strip_xattr_flag(page_virt + 16, crypt_stat);
+                               ecryptfs_write_header_metadata(page_virt + 20,
+                                                              crypt_stat,
+                                                              &written);
                        }
                        kunmap_atomic(page_virt, KM_USER0);
                        flush_dcache_page(page);
                        /* This is an encrypted data extent */
                        loff_t lower_offset =
                                ((view_extent_num * crypt_stat->extent_size)
-                                - crypt_stat->num_header_bytes_at_front);
+                                - crypt_stat->metadata_size);
  
                        rc = ecryptfs_read_lower_page_segment(
                                page, (lower_offset >> PAGE_CACHE_SHIFT),
diff --combined fs/ecryptfs/super.c
@@@ -26,7 -26,6 +26,7 @@@
  #include <linux/fs.h>
  #include <linux/mount.h>
  #include <linux/key.h>
 +#include <linux/slab.h>
  #include <linux/seq_file.h>
  #include <linux/smp_lock.h>
  #include <linux/file.h>
@@@ -86,7 -85,6 +86,6 @@@ static void ecryptfs_destroy_inode(stru
                if (lower_dentry->d_inode) {
                        fput(inode_info->lower_file);
                        inode_info->lower_file = NULL;
-                       d_drop(lower_dentry);
                }
        }
        ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat);