/* * 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, unsigned int flags) { struct fuse_conn *fc = get_fuse_conn(inode); bool refreshed = false; int err = 0; if (flags & IPERM_FLAG_RCU) return -ECHILD; if (!fuse_allow_task(fc, current)) return -EACCES; /* * If attributes are needed, refresh them before proceeding */ if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { err = fuse_update_attributes(inode, NULL, NULL, &refreshed); if (err) return err; } if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { err = generic_permission(inode, mask, flags, NULL); /* 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_do_getattr(inode, NULL, NULL); if (!err) err = generic_permission(inode, mask, flags, NULL); } /* 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_do_getattr(inode, NULL, NULL); if (!err && !(inode->i_mode & S_IXUGO)) return -EACCES; } } return err; }
int fuse_update_attributes(struct inode *inode, struct kstat *stat, struct file *file, bool *refreshed) { struct fuse_inode *fi = get_fuse_inode(inode); int err; bool r; if (fi->i_time < get_jiffies_64()) { r = true; err = fuse_do_getattr(inode, stat, file); } else { r = false; err = 0; if (stat) { generic_fillattr(inode, stat); stat->mode = fi->orig_i_mode; stat->ino = fi->orig_ino; } } if (refreshed != NULL) *refreshed = r; return err; }
static int fuse_perm_getattr(struct inode *inode, int mask) { if (mask & MAY_NOT_BLOCK) return -ECHILD; return fuse_do_getattr(inode, NULL, NULL); }
/* * 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(const 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) { int err = generic_permission(inode, mask, NULL); /* 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) err = generic_permission(inode, mask, NULL); } /* 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; if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) return -EACCES; if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) return fuse_access(inode, mask); return 0; } }
static int fuse_update_get_attr(struct inode *inode, struct file *file, struct kstat *stat, u32 request_mask, unsigned int flags) { struct fuse_inode *fi = get_fuse_inode(inode); int err = 0; bool sync; if (flags & AT_STATX_FORCE_SYNC) sync = true; else if (flags & AT_STATX_DONT_SYNC) sync = false; else if (request_mask & READ_ONCE(fi->inval_mask)) sync = true; else sync = time_before64(fi->i_time, get_jiffies_64()); if (sync) { forget_all_cached_acls(inode); err = fuse_do_getattr(inode, stat, file); } else if (stat) { generic_fillattr(inode, stat); stat->mode = fi->orig_i_mode; stat->ino = fi->orig_ino; } return err; }
static int fuse_perm_getattr(struct inode *inode, int flags) { if (flags & IPERM_FLAG_RCU) return -ECHILD; return fuse_do_getattr(inode, NULL, NULL); }
static int fuse_perm_getattr(struct inode *inode, int mask) { if (mask & MAY_NOT_BLOCK) return -ECHILD; forget_all_cached_acls(inode); return fuse_do_getattr(inode, NULL, NULL); }
static int fuse_setattr(struct dentry *entry, struct iattr *attr) { struct inode *inode = d_inode(entry); struct fuse_conn *fc = get_fuse_conn(inode); struct file *file = (attr->ia_valid & ATTR_FILE) ? attr->ia_file : NULL; int ret; if (!fuse_allow_current_process(get_fuse_conn(inode))) return -EACCES; if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) { attr->ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE); /* * The only sane way to reliably kill suid/sgid is to do it in * the userspace filesystem * * This should be done on write(), truncate() and chown(). */ if (!fc->handle_killpriv) { /* * ia_mode calculation may have used stale i_mode. * Refresh and recalculate. */ ret = fuse_do_getattr(inode, NULL, file); if (ret) return ret; attr->ia_mode = inode->i_mode; if (inode->i_mode & S_ISUID) { attr->ia_valid |= ATTR_MODE; attr->ia_mode &= ~S_ISUID; } if ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { attr->ia_valid |= ATTR_MODE; attr->ia_mode &= ~S_ISGID; } } } if (!attr->ia_valid) return 0; ret = fuse_do_setattr(entry, attr, file); if (!ret) { /* * If filesystem supports acls it may have updated acl xattrs in * the filesystem, so forget cached acls for the inode. */ if (fc->posix_acl) forget_all_cached_acls(inode); /* Directory mode changed, may need to revalidate access */ if (d_is_dir(entry) && (attr->ia_valid & ATTR_MODE)) fuse_invalidate_entry_cache(entry); } return ret; }
/* * Check whether the inode attributes are still valid * * If the attribute validity timeout has expired, then fetch the fresh * attributes with a 'getattr' request * * I'm not sure why cached attributes are never returned for the root * inode, this is probably being too cautious. */ static int fuse_revalidate(struct dentry *entry) { struct _inode *inode = d_get_inode(entry); struct fuse_inode *fi = get_fuse_inode(parent(inode)); struct fuse_conn *fc = get_fuse_conn(inode); if (!fuse_allow_task(fc, current)) return -EACCES; if (_get_node_id(inode) != FUSE_ROOT_ID && fi->i_time >= get_jiffies_64()) return 0; return fuse_do_getattr(inode); }
/* * Check whether the inode attributes are still valid * * If the attribute validity timeout has expired, then fetch the fresh * attributes with a 'getattr' request * * I'm not sure why cached attributes are never returned for the root * inode, this is probably being too cautious. */ static int fuse_revalidate(struct dentry *entry) { struct inode *inode = entry->d_inode; struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_conn *fc = get_fuse_conn(inode); if (!fuse_allow_task(fc, current)) return -EACCES; if (get_node_id(inode) != FUSE_ROOT_ID && time_before_eq(jiffies, fi->i_time)) return 0; return fuse_do_getattr(inode); }
/* * 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_update_get_attr(struct inode *inode, struct file *file, struct kstat *stat) { struct fuse_inode *fi = get_fuse_inode(inode); int err = 0; if (time_before64(fi->i_time, get_jiffies_64())) { forget_all_cached_acls(inode); err = fuse_do_getattr(inode, stat, file); } else if (stat) { generic_fillattr(inode, stat); stat->mode = fi->orig_i_mode; stat->ino = fi->orig_ino; } return err; }
static int fuse_setattr(struct dentry *entry, struct iattr *attr) { struct inode *inode = d_inode(entry); struct file *file = (attr->ia_valid & ATTR_FILE) ? attr->ia_file : NULL; int ret; if (!fuse_allow_current_process(get_fuse_conn(inode))) return -EACCES; if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) { int kill; attr->ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE); /* * ia_mode calculation may have used stale i_mode. Refresh and * recalculate. */ ret = fuse_do_getattr(inode, NULL, file); if (ret) return ret; attr->ia_mode = inode->i_mode; kill = should_remove_suid(entry); if (kill & ATTR_KILL_SUID) { attr->ia_valid |= ATTR_MODE; attr->ia_mode &= ~S_ISUID; } if (kill & ATTR_KILL_SGID) { attr->ia_valid |= ATTR_MODE; attr->ia_mode &= ~S_ISGID; } } if (!attr->ia_valid) return 0; ret = fuse_do_setattr(inode, attr, file); if (!ret) { /* Directory mode changed, may need to revalidate access */ if (d_is_dir(entry) && (attr->ia_valid & ATTR_MODE)) fuse_invalidate_entry_cache(entry); } return ret; }
int fuse_open_common(struct inode *inode, struct file *file, int isdir) { struct fuse_open_out outarg; struct fuse_file *ff; int err; /* VFS checks this, but only _after_ ->open() */ if (file->f_flags & O_DIRECT) return -EINVAL; err = generic_file_open(inode, file); if (err) return err; /* If opening the root node, no lookup has been performed on it, so the attributes must be refreshed */ if (get_node_id(inode) == FUSE_ROOT_ID) { err = fuse_do_getattr(inode); if (err) return err; } ff = fuse_file_alloc(); if (!ff) return -ENOMEM; err = fuse_send_open(inode, file, isdir, &outarg); if (err) fuse_file_free(ff); else { if (isdir) outarg.open_flags &= ~FOPEN_DIRECT_IO; fuse_finish_open(inode, file, ff, &outarg); } return err; }