/* * Check permission. The two basic access models of FUSE are: * * 1) Local access checking ('default_permissions' mount option) based * on file mode. This is the plain old disk filesystem permission * modell. * * 2) "Remote" access checking, where server is responsible for * checking permission in each inode operation. An exception to this * is if ->permission() was invoked from sys_access() in which case an * access request is sent. Execute permission is still checked * locally based on file mode. */ static int fuse_permission(struct inode *inode, int mask) { struct fuse_conn *fc = get_fuse_conn(inode); bool refreshed = false; int err = 0; if (!fuse_allow_current_process(fc)) return -EACCES; /* * If attributes are needed, refresh them before proceeding */ if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { struct fuse_inode *fi = get_fuse_inode(inode); if (fi->i_time < get_jiffies_64()) { refreshed = true; err = fuse_perm_getattr(inode, mask); if (err) return err; } } if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { err = generic_permission(inode, mask); /* If permission is denied, try to refresh file attributes. This is also needed, because the root node will at first have no permissions */ if (err == -EACCES && !refreshed) { err = fuse_perm_getattr(inode, mask); if (!err) err = generic_permission(inode, mask); } /* Note: the opposite of the above test does not exist. So if permissions are revoked this won't be noticed immediately, only after the attribute timeout has expired */ } else if (mask & (MAY_ACCESS | MAY_CHDIR)) { err = fuse_access(inode, mask); } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { if (!(inode->i_mode & S_IXUGO)) { if (refreshed) return -EACCES; err = fuse_perm_getattr(inode, mask); if (!err && !(inode->i_mode & S_IXUGO)) return -EACCES; } } return err; }
/* * Check permission. The two basic access models of FUSE are: * * 1) Local access checking ('default_permissions' mount option) based * on file mode. This is the plain old disk filesystem permission * modell. * * 2) "Remote" access checking, where server is responsible for * checking permission in each inode operation. An exception to this * is if ->permission() was invoked from sys_access() in which case an * access request is sent. Execute permission is still checked * locally based on file mode. */ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) { struct fuse_conn *fc = get_fuse_conn(inode); if (!fuse_allow_task(fc, current)) return -EACCES; else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { #ifdef KERNEL_2_6_10_PLUS int err = generic_permission(inode, mask, NULL); #else int err = vfs_permission(inode, mask); #endif /* If permission is denied, try to refresh file attributes. This is also needed, because the root node will at first have no permissions */ if (err == -EACCES) { err = fuse_do_getattr(inode); if (!err) #ifdef KERNEL_2_6_10_PLUS err = generic_permission(inode, mask, NULL); #else err = vfs_permission(inode, mask); #endif } /* Note: the opposite of the above test does not exist. So if permissions are revoked this won't be noticed immediately, only after the attribute timeout has expired */ return err; } else { int mode = inode->i_mode; #ifndef KERNEL_2_6_11_PLUS if ((mask & MAY_WRITE) && IS_RDONLY(inode) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) return -EROFS; #endif if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) return -EACCES; #ifndef LOOKUP_CHDIR #define LOOKUP_CHDIR 0 #endif if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) return fuse_access(inode, mask); return 0; } }
static int fuse_permission(struct inode *inode, int mask) { struct fuse_conn *fc = get_fuse_conn(inode); bool refreshed = false; int err = 0; if (!fuse_allow_task(fc, current)) return -EACCES; if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { struct fuse_inode *fi = get_fuse_inode(inode); if (fi->i_time < get_jiffies_64()) { refreshed = true; err = fuse_perm_getattr(inode, mask); if (err) return err; } } if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { err = generic_permission(inode, mask); if (err == -EACCES && !refreshed) { err = fuse_perm_getattr(inode, mask); if (!err) err = generic_permission(inode, mask); } } else if (mask & (MAY_ACCESS | MAY_CHDIR)) { if (mask & MAY_NOT_BLOCK) return -ECHILD; err = fuse_access(inode, mask); } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { if (!(inode->i_mode & S_IXUGO)) { if (refreshed) return -EACCES; err = fuse_perm_getattr(inode, mask); if (!err && !(inode->i_mode & S_IXUGO)) return -EACCES; } } return err; }