Re: [fuse-devel] [RFC] fuse: Support posix ACLs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Jun 29, 2016 at 02:52:37PM -0500, Michael j Theall wrote:
> 
> More comments:
> 
> My patch does set_cached_acl() in fuse_get_acl(). I would investigate if
> this is necessary.

Hmm, on the one hand it looks like a lot of filesystems do call it, on
the other hand it looks like get_acl is caching it. I'll have to take a
closer look.

> Since your patch invalidates the cached acls on getattr(), I would
> investigate on whether you also need to invalidate cached acls on the
> entries returned by readdirplus.

Possibly so. I missed the fact that fuse_direntplus_link might update
the inode attributes.

> > There are some indications that fuse supports ACLs on the userspace side
> > when default_permissions is not used (though I'm not seeing how that
> > works). Will these changes conflict with that support, and if how do we
> > avoid those conflicts?
> 
> I wouldn't exactly call it "support". Basically by turning off
> default_permissions, the fuser server can do what it wants permission-wise.
> My filesystem turns off default_permissions in order to support ACLs, but
> as far as fuse is concerned, it is totally oblivious and blindly does what
> my server says is permitted. That being said, there still lies the problem
> of checking permissions along the path. The low-level interface only gives
> you the final inode, which in the case of hard links, the path is
> ambiguous. This means you can't check each path component for permissions
> (and the kernel certainly won't! since you turned off default_permissions).
> Therefore the only "correct" way to implement ACL support on the fuse
> server is by setting the attr/entry timeout to 0 to force the lookup every
> time, which defeats many purposes of using fuse in the first place. You can
> read all the gory details in the thread I linked containing my original
> patch.
> 
> Fortunately, this patch (and mine) allows you to use default_permissions
> *and* have acl support, meaning permission checks will be performed in
> kernel for each path component. The extra benefit is that it allows any
> backing filesystem which supports xattrs to support acls, provided your
> fuse server has unencumbered privileges for that filesystem.

But if we're going through the posix acl xattr handlers then the acls
will be cached. What I worry about is that somehow we could end up in a
situation where the cached acls don't match those that the filesystem is
using, and userspace sees one thing in response to getfacl but something
different is being enforced.

Thanks,
Seth

> 
> Regards,
> Michael Theall
> 
> Michael j Theall/Houston/IBM@IBMUS wrote on 06/29/2016 02:24:14 PM:
> 
> > From: Michael j Theall/Houston/IBM@IBMUS
> > To: Seth Forshee <seth.forshee@xxxxxxxxxxxxx>
> > Cc: fuse-devel@xxxxxxxxxxxxxxxxxxxxx, linux-fsdevel@xxxxxxxxxxxxxxx,
> > Miklos@xxxxxxxxxxxxxxxxxxxxxxxxxx, Szeredi <miklos@xxxxxxxxxx>
> > Date: 06/29/2016 02:37 PM
> > Subject: Re: [fuse-devel] [RFC] fuse: Support posix ACLs
> >
> > Going by the patch I posted a couple of years ago: https://
> > sourceforge.net/p/fuse/mailman/message/33033653/
> >
> > The only hole I see in your patch is that in setattr() you are not
> > updating the cached acl if the ATTR_MODE is updated. The other major
> > difference is that my version uses the get_acl/set_acl inode
> > operations but you use that plus the xattr handlers. I'm not up-to-
> > speed on the kernel so I'm not sure if you actually need to implement
> both.
> >
> > Regards,
> > Michael Theall
> >
> > Seth Forshee <seth.forshee@xxxxxxxxxxxxx> wrote on 06/29/2016 02:07:31
> PM:
> >
> > > From: Seth Forshee <seth.forshee@xxxxxxxxxxxxx>
> > > To: fuse-devel@xxxxxxxxxxxxxxxxxxxxx, linux-fsdevel@xxxxxxxxxxxxxxx
> > > Cc: "Eric W. Biederman" <ebiederm@xxxxxxxxxxxx>, Miklos Szeredi
> > > <miklos@xxxxxxxxxx>
> > > Date: 06/29/2016 02:08 PM
> > > Subject: [fuse-devel] [RFC] fuse: Support posix ACLs
> > >
> > > Eric and I are working towards adding support for fuse mounts in
> > > non-init user namespaces. Towards that end we'd like to add ACL support
> > > to fuse as this will allow for a cleaner implementation overall. Below
> > > is an initial patch to support this. I'd like to get some general
> > > feedback on this patch and ask a couple of specific questions.
> > >
> > > There are some indications that fuse supports ACLs on the userspace
> side
> > > when default_permissions is not used (though I'm not seeing how that
> > > works). Will these changes conflict with that support, and if how do we
> > > avoid those conflicts?
> > >
> > > Are there any places where we need to invalidate cached ACLs that
> aren't
> > > covered in the patch?
> > >
> > > Thanks,
> > > Seth
> > >
> > >
> > > diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> > > index 8466e122ee62..2f53b0491159 100644
> > > --- a/fs/fuse/dir.c
> > > +++ b/fs/fuse/dir.c
> > > @@ -13,6 +13,8 @@
> > >  #include <linux/sched.h>
> > >  #include <linux/namei.h>
> > >  #include <linux/slab.h>
> > > +#include <linux/xattr.h>
> > > +#include <linux/posix_acl_xattr.h>
> > >
> > >  static bool fuse_use_readdirplus(struct inode *dir, struct
> > dir_context *ctx)
> > >  {
> > > @@ -1061,6 +1063,7 @@ 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);
> > >  }
> > >
> > > @@ -1719,9 +1722,8 @@ static int fuse_getattr(struct vfsmount *mnt,
> > > struct dentry *entry,
> > >     return fuse_update_attributes(inode, stat, NULL, NULL);
> > >  }
> > >
> > > -static int fuse_setxattr(struct dentry *unused, struct inode *inode,
> > > -          const char *name, const void *value,
> > > -          size_t size, int flags)
> > > +static int fuse_setxattr(struct inode *inode, const char *name,
> > > +          const void *value, size_t size, int flags)
> > >  {
> > >     struct fuse_conn *fc = get_fuse_conn(inode);
> > >     FUSE_ARGS(args);
> > > @@ -1755,8 +1757,8 @@ static int fuse_setxattr(struct dentry
> > > *unused, struct inode *inode,
> > >     return err;
> > >  }
> > >
> > > -static ssize_t fuse_getxattr(struct dentry *entry, struct inode
> *inode,
> > > -              const char *name, void *value, size_t size)
> > > +static ssize_t fuse_getxattr(struct inode *inode, const char *name,
> > > +              void *value, size_t size)
> > >  {
> > >     struct fuse_conn *fc = get_fuse_conn(inode);
> > >     FUSE_ARGS(args);
> > > @@ -1838,9 +1840,8 @@ static ssize_t fuse_listxattr(struct dentry
> > > *entry, char *list, size_t size)
> > >     return ret;
> > >  }
> > >
> > > -static int fuse_removexattr(struct dentry *entry, const char *name)
> > > +static int fuse_removexattr(struct inode *inode, const char *name)
> > >  {
> > > -   struct inode *inode = d_inode(entry);
> > >     struct fuse_conn *fc = get_fuse_conn(inode);
> > >     FUSE_ARGS(args);
> > >     int err;
> > > @@ -1865,6 +1866,138 @@ static int fuse_removexattr(struct dentry
> > > *entry, const char *name)
> > >     return err;
> > >  }
> > >
> > > +static int fuse_xattr_get(const struct xattr_handler *handler,
> > > +           struct dentry *dentry, struct inode *inode,
> > > +           const char *name, void *value, size_t size)
> > > +{
> > > +   return fuse_getxattr(inode, name, value, size);
> > > +}
> > > +
> > > +static int fuse_xattr_set(const struct xattr_handler *handler,
> > > +           struct dentry *dentry, struct inode *inode,
> > > +           const char *name, const void *value, size_t size,
> > > +           int flags)
> > > +{
> > > +   if (!value)
> > > +      return fuse_removexattr(inode, name);
> > > +
> > > +   return fuse_setxattr(inode, name, value, size, flags);
> > > +}
> > > +
> > > +static const struct xattr_handler fuse_xattr_handler = {
> > > +   .prefix   = "",
> > > +   .get   = fuse_xattr_get,
> > > +   .set   = fuse_xattr_set,
> > > +};
> > > +
> > > +#ifndef CONFIG_POSIX_ACL
> > > +static int fuse_xattr_acl_get(const struct xattr_handler *handler,
> > > +               struct dentry *dentry, struct inode *inode,
> > > +               const char *name, void *value, size_t size)
> > > +{
> > > +   return -EOPNOTSUPP;
> > > +}
> > > +
> > > +static int fuse_xattr_acl_set(const struct xattr_handler *handler,
> > > +            struct dentry *dentry, struct inode *inode,
> > > +            const char *name, const void *value, size_t size,
> > > +            int flags)
> > > +{
> > > +   return -EOPNOTSUPP;
> > > +}
> > > +
> > > +static const struct xattr_handler fuse_xattr_acl_access_handler = {
> > > +   .name   = XATTR_NAME_POSIX_ACL_ACCESS,
> > > +   .get   = fuse_xattr_acl_get,
> > > +   .set   = fuse_xattr_acl_set,
> > > +};
> > > +
> > > +static const struct xattr_handler fuse_xattr_acl_default_handler = {
> > > +   .name   = XATTR_NAME_POSIX_ACL_DEFAULT,
> > > +   .get   = fuse_xattr_acl_get,
> > > +   .set   = fuse_xattr_acl_set,
> > > +};
> > > +#endif /* CONFIG_POSIX_ACL */
> > > +
> > > +const struct xattr_handler *fuse_xattr_handlers[] = {
> > > +#ifdef CONFIG_FS_POSIX_ACL
> > > +   &posix_acl_access_xattr_handler,
> > > +   &posix_acl_default_xattr_handler,
> > > +#else
> > > +   &fuse_xattr_acl_access_handler,
> > > +   &fuse_xattr_acl_default_handler,
> > > +#endif
> > > +   &fuse_xattr_handler,
> > > +};
> > > +
> > > +static struct posix_acl *fuse_get_acl(struct inode *inode, int type)
> > > +{
> > > +   int size;
> > > +   const char *name;
> > > +   void *value = NULL;
> > > +   struct posix_acl *acl;
> > > +
> > > +   if (type == ACL_TYPE_ACCESS)
> > > +      name = XATTR_NAME_POSIX_ACL_ACCESS;
> > > +   else if (type == ACL_TYPE_DEFAULT)
> > > +      name = XATTR_NAME_POSIX_ACL_DEFAULT;
> > > +   else
> > > +      return ERR_PTR(-EOPNOTSUPP);
> > > +
> > > +   size = fuse_getxattr(inode, name, NULL, 0);
> > > +   if (size > 0) {
> > > +      value = kzalloc(size, GFP_KERNEL);
> > > +      if (!value)
> > > +         return ERR_PTR(-ENOMEM);
> > > +      size = fuse_getxattr(inode, name, value, size);
> > > +   }
> > > +   if (size > 0) {
> > > +      acl = posix_acl_from_xattr(inode->i_sb->s_user_ns, value, size);
> > > +   } else if ((size == 0) || (size == -ENODATA)) {
> > > +      acl = NULL;
> > > +   } else {
> > > +      acl = ERR_PTR(size);
> > > +   }
> > > +   kfree(value);
> > > +
> > > +   return acl;
> > > +}
> > > +
> > > +static int fuse_set_acl(struct inode *inode, struct posix_acl
> > *acl,int type)
> > > +{
> > > +   const char *name;
> > > +   int ret;
> > > +
> > > +   if (type == ACL_TYPE_ACCESS)
> > > +      name = XATTR_NAME_POSIX_ACL_ACCESS;
> > > +   else if (type == ACL_TYPE_DEFAULT)
> > > +      name = XATTR_NAME_POSIX_ACL_DEFAULT;
> > > +   else
> > > +      return -EINVAL;
> > > +
> > > +   if (acl) {
> > > +      struct user_namespace *s_user_ns = inode->i_sb->s_user_ns;
> > > +      size_t size = posix_acl_xattr_size(acl->a_count);
> > > +      void *value = kmalloc(size, GFP_KERNEL);
> > > +      if (!value)
> > > +         return -ENOMEM;
> > > +
> > > +      ret = posix_acl_to_xattr(s_user_ns, acl, value, size);
> > > +      if (ret < 0) {
> > > +         kfree(value);
> > > +         return ret;
> > > +      }
> > > +
> > > +      ret = fuse_setxattr(inode, name, value, size, 0);
> > > +      kfree(value);
> > > +   } else {
> > > +      ret = fuse_removexattr(inode, name);
> > > +   }
> > > +   if (ret == 0)
> > > +      set_cached_acl(inode, type, acl);
> > > +   return ret;
> > > +}
> > > +
> > >  static const struct inode_operations fuse_dir_inode_operations = {
> > >     .lookup      = fuse_lookup,
> > >     .mkdir      = fuse_mkdir,
> > > @@ -1879,10 +2012,12 @@ static const struct inode_operations
> > > fuse_dir_inode_operations = {
> > >     .mknod      = fuse_mknod,
> > >     .permission   = fuse_permission,
> > >     .getattr   = fuse_getattr,
> > > -   .setxattr   = fuse_setxattr,
> > > -   .getxattr   = fuse_getxattr,
> > > +   .setxattr   = generic_setxattr,
> > > +   .getxattr   = generic_getxattr,
> > >     .listxattr   = fuse_listxattr,
> > > -   .removexattr   = fuse_removexattr,
> > > +   .removexattr   = generic_removexattr,
> > > +   .get_acl   = fuse_get_acl,
> > > +   .set_acl   = fuse_set_acl,
> > >  };
> > >
> > >  static const struct file_operations fuse_dir_operations = {
> > > @@ -1900,10 +2035,12 @@ static const struct inode_operations
> > > fuse_common_inode_operations = {
> > >     .setattr   = fuse_setattr,
> > >     .permission   = fuse_permission,
> > >     .getattr   = fuse_getattr,
> > > -   .setxattr   = fuse_setxattr,
> > > -   .getxattr   = fuse_getxattr,
> > > +   .setxattr   = generic_setxattr,
> > > +   .getxattr   = generic_getxattr,
> > >     .listxattr   = fuse_listxattr,
> > > -   .removexattr   = fuse_removexattr,
> > > +   .removexattr   = generic_removexattr,
> > > +   .get_acl   = fuse_get_acl,
> > > +   .set_acl   = fuse_set_acl,
> > >  };
> > >
> > >  static const struct inode_operations fuse_symlink_inode_operations = {
> > > @@ -1911,10 +2048,12 @@ static const struct inode_operations
> > > fuse_symlink_inode_operations = {
> > >     .get_link   = fuse_get_link,
> > >     .readlink   = generic_readlink,
> > >     .getattr   = fuse_getattr,
> > > -   .setxattr   = fuse_setxattr,
> > > -   .getxattr   = fuse_getxattr,
> > > +   .setxattr   = generic_setxattr,
> > > +   .getxattr   = generic_getxattr,
> > >     .listxattr   = fuse_listxattr,
> > > -   .removexattr   = fuse_removexattr,
> > > +   .removexattr   = generic_removexattr,
> > > +   .get_acl   = fuse_get_acl,
> > > +   .set_acl   = fuse_set_acl,
> > >  };
> > >
> > >  void fuse_init_common(struct inode *inode)
> > > diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> > > index 9f4c3c82edd6..02c08796051e 100644
> > > --- a/fs/fuse/fuse_i.h
> > > +++ b/fs/fuse/fuse_i.h
> > > @@ -23,6 +23,7 @@
> > >  #include <linux/poll.h>
> > >  #include <linux/workqueue.h>
> > >  #include <linux/kref.h>
> > > +#include <linux/xattr.h>
> > >  #include <linux/pid_namespace.h>
> > >  #include <linux/user_namespace.h>
> > >
> > > @@ -693,6 +694,8 @@ extern const struct file_operations
> fuse_dev_operations;
> > >
> > >  extern const struct dentry_operations fuse_dentry_operations;
> > >
> > > +extern const struct xattr_handler *fuse_xattr_handlers[];
> > > +
> > >  /**
> > >   * Inode to nodeid comparison.
> > >   */
> > > diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> > > index 254f1944ee98..9c1519c269bb 100644
> > > --- a/fs/fuse/inode.c
> > > +++ b/fs/fuse/inode.c
> > > @@ -21,6 +21,7 @@
> > >  #include <linux/sched.h>
> > >  #include <linux/exportfs.h>
> > >  #include <linux/pid_namespace.h>
> > > +#include <linux/posix_acl.h>
> > >
> > >  MODULE_AUTHOR("Miklos Szeredi <miklos@xxxxxxxxxx>");
> > >  MODULE_DESCRIPTION("Filesystem in Userspace");
> > > @@ -339,6 +340,7 @@ int fuse_reverse_inval_inode(struct super_block
> > > *sb, u64 nodeid,
> > >        return -ENOENT;
> > >
> > >     fuse_invalidate_attr(inode);
> > > +   forget_all_cached_acls(inode);
> > >     if (offset >= 0) {
> > >        pg_start = offset >> PAGE_SHIFT;
> > >        if (len <= 0)
> > > @@ -1066,6 +1068,7 @@ static int fuse_fill_super(struct super_block
> > > *sb, void *data, int silent)
> > >     }
> > >     sb->s_magic = FUSE_SUPER_MAGIC;
> > >     sb->s_op = &fuse_super_operations;
> > > +   sb->s_xattr = fuse_xattr_handlers;
> > >     sb->s_maxbytes = MAX_LFS_FILESIZE;
> > >     sb->s_time_gran = 1;
> > >     sb->s_export_op = &fuse_export_operations;
> > >
> > >
> > >
> >
> ------------------------------------------------------------------------------
> 
> > > Attend Shape: An AT&T Tech Expo July 15-16. Meet us at AT&T Park in San
> > > Francisco, CA to explore cutting-edge tech and listen to tech
> luminaries
> > > present their vision of the future. This family event has something for
> > > everyone, including kids. Get more information and register today.
> > > http://sdm.link/attshape
> > > --
> > > fuse-devel mailing list
> > > To unsubscribe or subscribe, visit https://lists.sourceforge.net/
> > > lists/listinfo/fuse-devel
> > >
> >
> ------------------------------------------------------------------------------
> 
> > Attend Shape: An AT&T Tech Expo July 15-16. Meet us at AT&T Park in San
> > Francisco, CA to explore cutting-edge tech and listen to tech luminaries
> > present their vision of the future. This family event has something for
> > everyone, including kids. Get more information and register today.
> > http://sdm.link/attshape--
> > fuse-devel mailing list
> > To unsubscribe or subscribe, visit https://lists.sourceforge.net/
> > lists/listinfo/fuse-devel
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux