Return-Path: Received: from mail-qt0-f172.google.com ([209.85.216.172]:35373 "EHLO mail-qt0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754537AbcGELCz (ORCPT ); Tue, 5 Jul 2016 07:02:55 -0400 Received: by mail-qt0-f172.google.com with SMTP id f89so98653733qtd.2 for ; Tue, 05 Jul 2016 04:02:54 -0700 (PDT) Message-ID: <1467716572.3800.2.camel@redhat.com> Subject: Re: [PATCH v23 02/22] vfs: Add MAY_CREATE_FILE and MAY_CREATE_DIR permission flags From: Jeff Layton To: Andreas Gruenbacher , Alexander Viro Cc: Christoph Hellwig , "Theodore Ts'o" , Andreas Dilger , "J. Bruce Fields" , Trond Myklebust , Anna Schumaker , Dave Chinner , linux-ext4@vger.kernel.org, xfs@oss.sgi.com, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, linux-api@vger.kernel.org Date: Tue, 05 Jul 2016 07:02:52 -0400 In-Reply-To: <1467294433-3222-3-git-send-email-agruenba@redhat.com> References: <1467294433-3222-1-git-send-email-agruenba@redhat.com> <1467294433-3222-3-git-send-email-agruenba@redhat.com> Content-Type: text/plain; charset="UTF-8" Mime-Version: 1.0 Sender: linux-nfs-owner@vger.kernel.org List-ID: On Thu, 2016-06-30 at 15:46 +0200, Andreas Gruenbacher wrote: > Richacls distinguish between creating non-directories and directories. To > support that, add an isdir parameter to may_create(). When checking > inode_permission() for create permission, pass in an additional > MAY_CREATE_FILE or MAY_CREATE_DIR mask flag. > > Add may_replace() to allow checking for delete and create access when > replacing an existing file in vfs_rename(). > > Signed-off-by: Andreas Gruenbacher > Reviewed-by: J. Bruce Fields > Reviewed-by: Andreas Dilger > Reviewed-by: Steve French > --- >  fs/namei.c         | 49 +++++++++++++++++++++++++++++++++---------------- >  include/linux/fs.h |  2 ++ >  2 files changed, 35 insertions(+), 16 deletions(-) > > diff --git a/fs/namei.c b/fs/namei.c > index 7cc5487..dc91858 100644 > --- a/fs/namei.c > +++ b/fs/namei.c > @@ -454,7 +454,9 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask) >   * this, letting us set arbitrary permissions for filesystem access without >   * changing the "normal" UIDs which are used for other things. >   * > - * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask. > + * MAY_WRITE must be set in @mask whenever MAY_APPEND, MAY_CREATE_FILE, or > + * MAY_CREATE_DIR are set.  That way, file systems that don't support these > + * permissions will check for MAY_WRITE instead. >   */ >  int inode_permission(struct inode *inode, int mask) >  { > @@ -2763,7 +2765,8 @@ EXPORT_SYMBOL(__check_sticky); >   * 10. We don't allow removal of NFS sillyrenamed files; it's handled by >   *     nfs_async_unlink(). >   */ > -static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) > +static int may_delete_or_replace(struct inode *dir, struct dentry *victim, > +  bool isdir, int mask) >  { >   struct inode *inode = d_backing_inode(victim); >   int error; > @@ -2775,7 +2778,7 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) >   BUG_ON(victim->d_parent->d_inode != dir); >   audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); >   > - error = inode_permission(dir, MAY_WRITE | MAY_EXEC); > + error = inode_permission(dir, mask); >   if (error) >   return error; >   if (IS_APPEND(dir)) > @@ -2798,6 +2801,18 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) >   return 0; >  } >   > +static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) > +{ > + return may_delete_or_replace(dir, victim, isdir, MAY_WRITE | MAY_EXEC); > +} > + > +static int may_replace(struct inode *dir, struct dentry *victim, bool isdir) > +{ > + int mask = isdir ? MAY_CREATE_DIR : MAY_CREATE_FILE; > + > + return may_delete_or_replace(dir, victim, isdir, mask | MAY_WRITE | MAY_EXEC); > +} > + >  /* Check whether we can create an object with dentry child in directory >   *  dir. >   *  1. We can't do it if child already exists (open has special treatment for > @@ -2806,14 +2821,16 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) >   *  3. We should have write and exec permissions on dir >   *  4. We can't do it if dir is immutable (done in permission()) >   */ > -static inline int may_create(struct inode *dir, struct dentry *child) > +static inline int may_create(struct inode *dir, struct dentry *child, bool isdir) >  { > + int mask = isdir ? MAY_CREATE_DIR : MAY_CREATE_FILE; > + >   audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE); >   if (child->d_inode) >   return -EEXIST; >   if (IS_DEADDIR(dir)) >   return -ENOENT; > - return inode_permission(dir, MAY_WRITE | MAY_EXEC); > + return inode_permission(dir, MAY_WRITE | MAY_EXEC | mask); >  } >   >  /* > @@ -2863,7 +2880,7 @@ EXPORT_SYMBOL(unlock_rename); >  int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, >   bool want_excl) >  { > - int error = may_create(dir, dentry); > + int error = may_create(dir, dentry, false); >   if (error) >   return error; >   > @@ -3650,7 +3667,7 @@ EXPORT_SYMBOL(user_path_create); >   >  int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) >  { > - int error = may_create(dir, dentry); > + int error = may_create(dir, dentry, false); >   >   if (error) >   return error; > @@ -3744,7 +3761,7 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d >   >  int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) >  { > - int error = may_create(dir, dentry); > + int error = may_create(dir, dentry, true); >   unsigned max_links = dir->i_sb->s_max_links; >   >   if (error) > @@ -3800,7 +3817,7 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode) >   >  int vfs_rmdir(struct inode *dir, struct dentry *dentry) >  { > - int error = may_delete(dir, dentry, 1); > + int error = may_delete(dir, dentry, true); >   >   if (error) >   return error; > @@ -3922,7 +3939,7 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname) >  int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode) >  { >   struct inode *target = dentry->d_inode; > - int error = may_delete(dir, dentry, 0); > + int error = may_delete(dir, dentry, false); >   >   if (error) >   return error; > @@ -4056,7 +4073,7 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname) >   >  int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) >  { > - int error = may_create(dir, dentry); > + int error = may_create(dir, dentry, false); >   >   if (error) >   return error; > @@ -4139,7 +4156,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de >   if (!inode) >   return -ENOENT; >   > - error = may_create(dir, new_dentry); > + error = may_create(dir, new_dentry, false); >   if (error) >   return error; >   > @@ -4336,14 +4353,14 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, >   return error; >   >   if (!target) { > - error = may_create(new_dir, new_dentry); > + error = may_create(new_dir, new_dentry, is_dir); >   } else { >   new_is_dir = d_is_dir(new_dentry); >   >   if (!(flags & RENAME_EXCHANGE)) > - error = may_delete(new_dir, new_dentry, is_dir); > + error = may_replace(new_dir, new_dentry, is_dir); >   else > - error = may_delete(new_dir, new_dentry, new_is_dir); > + error = may_replace(new_dir, new_dentry, new_is_dir); >   } >   if (error) >   return error; > @@ -4606,7 +4623,7 @@ SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newna >   >  int vfs_whiteout(struct inode *dir, struct dentry *dentry) >  { > - int error = may_create(dir, dentry); > + int error = may_create(dir, dentry, false); >   if (error) >   return error; >   > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 4ad130c..dd614ad 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -84,6 +84,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, >  #define MAY_CHDIR 0x00000040 >  /* called from RCU mode, don't block */ >  #define MAY_NOT_BLOCK 0x00000080 > +#define MAY_CREATE_FILE 0x00000100 > +#define MAY_CREATE_DIR 0x00000200 >   >  /* >   * flags in file.f_mode.  Note that FMODE_READ and FMODE_WRITE must correspond Reviewed-by: Jeff Layton