lkml.org 
[lkml]   [2016]   [Oct]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v27 02/21] vfs: Add MAY_CREATE_FILE and MAY_CREATE_DIR permission flags
    Date
    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 <agruenba@redhat.com>
    Reviewed-by: J. Bruce Fields <bfields@redhat.com>
    Reviewed-by: Andreas Dilger <adilger@dilger.ca>
    Reviewed-by: Steve French <steve.french@primarydata.com>
    Reviewed-by: Jeff Layton <jlayton@redhat.com>
    ---
    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 33bdea7..7290dea 100644
    --- a/fs/namei.c
    +++ b/fs/namei.c
    @@ -463,7 +463,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)
    {
    @@ -2765,7 +2767,8 @@ EXPORT_SYMBOL(__check_sticky);
    * 11. 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;
    @@ -2777,7 +2780,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))
    @@ -2800,6 +2803,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
    @@ -2809,9 +2824,11 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
    * 4. We should have write and exec permissions on dir
    * 5. 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;
    struct user_namespace *s_user_ns;
    +
    audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
    if (child->d_inode)
    return -EEXIST;
    @@ -2821,7 +2838,7 @@ static inline int may_create(struct inode *dir, struct dentry *child)
    if (!kuid_has_mapping(s_user_ns, current_fsuid()) ||
    !kgid_has_mapping(s_user_ns, current_fsgid()))
    return -EOVERFLOW;
    - return inode_permission(dir, MAY_WRITE | MAY_EXEC);
    + return inode_permission(dir, MAY_WRITE | MAY_EXEC | mask);
    }

    /*
    @@ -2871,7 +2888,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;

    @@ -3664,7 +3681,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;
    @@ -3758,7 +3775,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)
    @@ -3814,7 +3831,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;
    @@ -3936,7 +3953,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;
    @@ -4070,7 +4087,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;
    @@ -4153,7 +4170,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;

    @@ -4357,14 +4374,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;
    @@ -4618,7 +4635,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 b88225a..26455c6 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
    --
    2.7.4
    \
     
     \ /
      Last update: 2016-10-11 14:57    [W:5.957 / U:0.732 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site