diff options
Diffstat (limited to 'fs/ecryptfs/inode.c')
-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, |