aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTyler Hicks <tyhicks@linux.vnet.ibm.com>2010-03-22 01:41:35 -0400
committerTyler Hicks <tyhicks@linux.vnet.ibm.com>2010-04-19 15:41:51 -0400
commit3a60a1686f0d51c99bd0df8ac93050fb6dfce647 (patch)
tree8b1a32c122e86022f6397a9f5e82900783717aab
parentf4e60e6b303bc46cdc477d3174dbf9cb5dd013aa (diff)
eCryptfs: Decrypt symlink target for stat size
Create a getattr handler for eCryptfs symlinks that is capable of reading the lower target and decrypting its path. Prior to this patch, a stat's st_size field would represent the strlen of the encrypted path, while readlink() would return the strlen of the decrypted path. This could lead to confusion in some userspace applications, since the two values should be equal. https://bugs.launchpad.net/bugs/524919 Reported-by: Loïc Minier <loic.minier@canonical.com> Cc: stable@kernel.org Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com>
-rw-r--r--fs/ecryptfs/inode.c100
1 files changed, 52 insertions, 48 deletions
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index ddbd096c7406..605f514f3b47 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -648,38 +648,17 @@ out_lock:
648 return rc; 648 return rc;
649} 649}
650 650
651static int 651static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf,
652ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) 652 size_t *bufsiz)
653{ 653{
654 struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
654 char *lower_buf; 655 char *lower_buf;
655 size_t lower_bufsiz; 656 size_t lower_bufsiz = PATH_MAX;
656 struct dentry *lower_dentry;
657 struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
658 char *plaintext_name;
659 size_t plaintext_name_size;
660 mm_segment_t old_fs; 657 mm_segment_t old_fs;
661 int rc; 658 int rc;
662 659
663 lower_dentry = ecryptfs_dentry_to_lower(dentry);
664 if (!lower_dentry->d_inode->i_op->readlink) {
665 rc = -EINVAL;
666 goto out;
667 }
668 mount_crypt_stat = &ecryptfs_superblock_to_private(
669 dentry->d_sb)->mount_crypt_stat;
670 /*
671 * If the lower filename is encrypted, it will result in a significantly
672 * longer name. If needed, truncate the name after decode and decrypt.
673 */
674 if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)
675 lower_bufsiz = PATH_MAX;
676 else
677 lower_bufsiz = bufsiz;
678 /* Released in this function */
679 lower_buf = kmalloc(lower_bufsiz, GFP_KERNEL); 660 lower_buf = kmalloc(lower_bufsiz, GFP_KERNEL);
680 if (lower_buf == NULL) { 661 if (!lower_buf) {
681 printk(KERN_ERR "%s: Out of memory whilst attempting to "
682 "kmalloc [%zd] bytes\n", __func__, lower_bufsiz);
683 rc = -ENOMEM; 662 rc = -ENOMEM;
684 goto out; 663 goto out;
685 } 664 }
@@ -689,29 +668,31 @@ ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
689 (char __user *)lower_buf, 668 (char __user *)lower_buf,
690 lower_bufsiz); 669 lower_bufsiz);
691 set_fs(old_fs); 670 set_fs(old_fs);
692 if (rc >= 0) { 671 if (rc < 0)
693 rc = ecryptfs_decode_and_decrypt_filename(&plaintext_name, 672 goto out;
694 &plaintext_name_size, 673 lower_bufsiz = rc;
695 dentry, lower_buf, 674 rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry,
696 rc); 675 lower_buf, lower_bufsiz);
697 if (rc) { 676out:
698 printk(KERN_ERR "%s: Error attempting to decode and "
699 "decrypt filename; rc = [%d]\n", __func__,
700 rc);
701 goto out_free_lower_buf;
702 }
703 /* Check for bufsiz <= 0 done in sys_readlinkat() */
704 rc = copy_to_user(buf, plaintext_name,
705 min((size_t) bufsiz, plaintext_name_size));
706 if (rc)
707 rc = -EFAULT;
708 else
709 rc = plaintext_name_size;
710 kfree(plaintext_name);
711 fsstack_copy_attr_atime(dentry->d_inode, lower_dentry->d_inode);
712 }
713out_free_lower_buf:
714 kfree(lower_buf); 677 kfree(lower_buf);
678 return rc;
679}
680
681static int
682ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
683{
684 char *kbuf;
685 size_t kbufsiz, copied;
686 int rc;
687
688 rc = ecryptfs_readlink_lower(dentry, &kbuf, &kbufsiz);
689 if (rc)
690 goto out;
691 copied = min_t(size_t, bufsiz, kbufsiz);
692 rc = copy_to_user(buf, kbuf, copied) ? -EFAULT : copied;
693 kfree(kbuf);
694 fsstack_copy_attr_atime(dentry->d_inode,
695 ecryptfs_dentry_to_lower(dentry)->d_inode);
715out: 696out:
716 return rc; 697 return rc;
717} 698}
@@ -1016,6 +997,28 @@ out:
1016 return rc; 997 return rc;
1017} 998}
1018 999
1000int ecryptfs_getattr_link(struct vfsmount *mnt, struct dentry *dentry,
1001 struct kstat *stat)
1002{
1003 struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
1004 int rc = 0;
1005
1006 mount_crypt_stat = &ecryptfs_superblock_to_private(
1007 dentry->d_sb)->mount_crypt_stat;
1008 generic_fillattr(dentry->d_inode, stat);
1009 if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) {
1010 char *target;
1011 size_t targetsiz;
1012
1013 rc = ecryptfs_readlink_lower(dentry, &target, &targetsiz);
1014 if (!rc) {
1015 kfree(target);
1016 stat->size = targetsiz;
1017 }
1018 }
1019 return rc;
1020}
1021
1019int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry, 1022int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
1020 struct kstat *stat) 1023 struct kstat *stat)
1021{ 1024{
@@ -1133,6 +1136,7 @@ const struct inode_operations ecryptfs_symlink_iops = {
1133 .put_link = ecryptfs_put_link, 1136 .put_link = ecryptfs_put_link,
1134 .permission = ecryptfs_permission, 1137 .permission = ecryptfs_permission,
1135 .setattr = ecryptfs_setattr, 1138 .setattr = ecryptfs_setattr,
1139 .getattr = ecryptfs_getattr_link,
1136 .setxattr = ecryptfs_setxattr, 1140 .setxattr = ecryptfs_setxattr,
1137 .getxattr = ecryptfs_getxattr, 1141 .getxattr = ecryptfs_getxattr,
1138 .listxattr = ecryptfs_listxattr, 1142 .listxattr = ecryptfs_listxattr,