diff options
author | Tyler Hicks <tyhicks@linux.vnet.ibm.com> | 2010-03-22 01:41:35 -0400 |
---|---|---|
committer | Tyler Hicks <tyhicks@linux.vnet.ibm.com> | 2010-04-19 15:41:51 -0400 |
commit | 3a60a1686f0d51c99bd0df8ac93050fb6dfce647 (patch) | |
tree | 8b1a32c122e86022f6397a9f5e82900783717aab /fs/ecryptfs | |
parent | f4e60e6b303bc46cdc477d3174dbf9cb5dd013aa (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>
Diffstat (limited to 'fs/ecryptfs')
-rw-r--r-- | fs/ecryptfs/inode.c | 100 |
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 | ||
651 | static int | 651 | static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf, |
652 | ecryptfs_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) { | 676 | out: |
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 | } | ||
713 | out_free_lower_buf: | ||
714 | kfree(lower_buf); | 677 | kfree(lower_buf); |
678 | return rc; | ||
679 | } | ||
680 | |||
681 | static int | ||
682 | ecryptfs_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); | ||
715 | out: | 696 | out: |
716 | return rc; | 697 | return rc; |
717 | } | 698 | } |
@@ -1016,6 +997,28 @@ out: | |||
1016 | return rc; | 997 | return rc; |
1017 | } | 998 | } |
1018 | 999 | ||
1000 | int 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 | |||
1019 | int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | 1022 | int 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, |