diff options
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 49 |
1 files changed, 31 insertions, 18 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 8ea4ea13ec5f..d1acab931330 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -695,6 +695,20 @@ static int fuse_do_getattr(struct inode *inode) | |||
695 | } | 695 | } |
696 | 696 | ||
697 | /* | 697 | /* |
698 | * Check if attributes are still valid, and if not send a GETATTR | ||
699 | * request to refresh them. | ||
700 | */ | ||
701 | static int fuse_refresh_attributes(struct inode *inode) | ||
702 | { | ||
703 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
704 | |||
705 | if (fi->i_time < get_jiffies_64()) | ||
706 | return fuse_do_getattr(inode); | ||
707 | else | ||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | /* | ||
698 | * Calling into a user-controlled filesystem gives the filesystem | 712 | * Calling into a user-controlled filesystem gives the filesystem |
699 | * daemon ptrace-like capabilities over the requester process. This | 713 | * daemon ptrace-like capabilities over the requester process. This |
700 | * means, that the filesystem daemon is able to record the exact | 714 | * means, that the filesystem daemon is able to record the exact |
@@ -770,7 +784,6 @@ static int fuse_access(struct inode *inode, int mask) | |||
770 | static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | 784 | static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) |
771 | { | 785 | { |
772 | struct fuse_conn *fc = get_fuse_conn(inode); | 786 | struct fuse_conn *fc = get_fuse_conn(inode); |
773 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
774 | bool refreshed = false; | 787 | bool refreshed = false; |
775 | int err = 0; | 788 | int err = 0; |
776 | 789 | ||
@@ -778,12 +791,11 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
778 | return -EACCES; | 791 | return -EACCES; |
779 | 792 | ||
780 | /* | 793 | /* |
781 | * If attributes are needed, but are stale, refresh them | 794 | * If attributes are needed, refresh them before proceeding |
782 | * before proceeding | ||
783 | */ | 795 | */ |
784 | if (((fc->flags & FUSE_DEFAULT_PERMISSIONS) || (mask & MAY_EXEC)) && | 796 | if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || |
785 | fi->i_time < get_jiffies_64()) { | 797 | ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { |
786 | err = fuse_do_getattr(inode); | 798 | err = fuse_refresh_attributes(inode); |
787 | if (err) | 799 | if (err) |
788 | return err; | 800 | return err; |
789 | 801 | ||
@@ -806,14 +818,17 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
806 | exist. So if permissions are revoked this won't be | 818 | exist. So if permissions are revoked this won't be |
807 | noticed immediately, only after the attribute | 819 | noticed immediately, only after the attribute |
808 | timeout has expired */ | 820 | timeout has expired */ |
809 | 821 | } else if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) { | |
810 | } else { | 822 | err = fuse_access(inode, mask); |
811 | int mode = inode->i_mode; | 823 | } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { |
812 | if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) | 824 | if (!(inode->i_mode & S_IXUGO)) { |
813 | return -EACCES; | 825 | if (refreshed) |
814 | 826 | return -EACCES; | |
815 | if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) | 827 | |
816 | return fuse_access(inode, mask); | 828 | err = fuse_do_getattr(inode); |
829 | if (!err && !(inode->i_mode & S_IXUGO)) | ||
830 | return -EACCES; | ||
831 | } | ||
817 | } | 832 | } |
818 | return err; | 833 | return err; |
819 | } | 834 | } |
@@ -1046,14 +1061,12 @@ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, | |||
1046 | struct inode *inode = entry->d_inode; | 1061 | struct inode *inode = entry->d_inode; |
1047 | struct fuse_inode *fi = get_fuse_inode(inode); | 1062 | struct fuse_inode *fi = get_fuse_inode(inode); |
1048 | struct fuse_conn *fc = get_fuse_conn(inode); | 1063 | struct fuse_conn *fc = get_fuse_conn(inode); |
1049 | int err = 0; | 1064 | int err; |
1050 | 1065 | ||
1051 | if (!fuse_allow_task(fc, current)) | 1066 | if (!fuse_allow_task(fc, current)) |
1052 | return -EACCES; | 1067 | return -EACCES; |
1053 | 1068 | ||
1054 | if (fi->i_time < get_jiffies_64()) | 1069 | err = fuse_refresh_attributes(inode); |
1055 | err = fuse_do_getattr(inode); | ||
1056 | |||
1057 | if (!err) { | 1070 | if (!err) { |
1058 | generic_fillattr(inode, stat); | 1071 | generic_fillattr(inode, stat); |
1059 | stat->mode = fi->orig_i_mode; | 1072 | stat->mode = fi->orig_i_mode; |