lkml.org 
[lkml]   [2016]   [Feb]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v18 03/22] vfs: Add MAY_DELETE_SELF and MAY_DELETE_CHILD permission flags
    Date
    Normally, deleting a file requires MAY_WRITE access to the parent
    directory. With richacls, a file may be deleted with MAY_DELETE_CHILD access
    to the parent directory or with MAY_DELETE_SELF access to the file.

    To support that, pass the MAY_DELETE_CHILD mask flag to inode_permission()
    when checking for delete access inside a directory, and MAY_DELETE_SELF
    when checking for delete access to a file itelf.

    The MAY_DELETE_SELF permission overrides the sticky directory check.

    Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
    Reviewed-by: J. Bruce Fields <bfields@redhat.com>
    ---
    fs/namei.c | 20 ++++++++++++--------
    include/linux/fs.h | 2 ++
    2 files changed, 14 insertions(+), 8 deletions(-)

    diff --git a/fs/namei.c b/fs/namei.c
    index ae30626..59b1da0 100644
    --- a/fs/namei.c
    +++ b/fs/namei.c
    @@ -453,9 +453,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.
    *
    - * 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.
    + * MAY_WRITE must be set in @mask whenever MAY_APPEND, MAY_CREATE_FILE,
    + * MAY_CREATE_DIR, or MAY_DELETE_CHILD 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)
    {
    @@ -2626,14 +2626,18 @@ static int may_delete_or_replace(struct inode *dir, struct dentry *victim,
    BUG_ON(victim->d_parent->d_inode != dir);
    audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);

    - error = inode_permission(dir, mask);
    + error = inode_permission(dir, mask | MAY_WRITE | MAY_DELETE_CHILD);
    + if (!error && check_sticky(dir, inode))
    + error = -EPERM;
    + if (error && IS_RICHACL(inode) &&
    + inode_permission(inode, MAY_DELETE_SELF) == 0 &&
    + inode_permission(dir, mask) == 0)
    + error = 0;
    if (error)
    return error;
    if (IS_APPEND(dir))
    return -EPERM;
    -
    - if (check_sticky(dir, inode) || IS_APPEND(inode) ||
    - IS_IMMUTABLE(inode) || IS_SWAPFILE(inode))
    + if (IS_APPEND(inode) || IS_IMMUTABLE(inode) || IS_SWAPFILE(inode))
    return -EPERM;
    if (isdir) {
    if (!d_is_dir(victim))
    @@ -2651,7 +2655,7 @@ static int may_delete_or_replace(struct inode *dir, struct dentry *victim,

    static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
    {
    - return may_delete_or_replace(dir, victim, isdir, MAY_WRITE | MAY_EXEC);
    + return may_delete_or_replace(dir, victim, isdir, MAY_EXEC);
    }

    static int may_replace(struct inode *dir, struct dentry *victim, bool isdir)
    diff --git a/include/linux/fs.h b/include/linux/fs.h
    index 02e99d7..97e34ba 100644
    --- a/include/linux/fs.h
    +++ b/include/linux/fs.h
    @@ -85,6 +85,8 @@ typedef void (dax_iodone_t)(struct buffer_head *bh_map, int uptodate);
    #define MAY_NOT_BLOCK 0x00000080
    #define MAY_CREATE_FILE 0x00000100
    #define MAY_CREATE_DIR 0x00000200
    +#define MAY_DELETE_CHILD 0x00000400
    +#define MAY_DELETE_SELF 0x00000800

    /*
    * flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond
    --
    2.4.3
    \
     
     \ /
      Last update: 2016-02-29 10:01    [W:4.113 / U:0.772 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site