Skip to content

Commit

Permalink
vfs: export check_sticky()
Browse files Browse the repository at this point in the history
It's already duplicated in btrfs and about to be used in overlayfs too.

Move the sticky bit check to an inline helper and call the out-of-line
helper only in the unlikly case of the sticky bit being set.

Signed-off-by: Miklos Szeredi <[email protected]>
  • Loading branch information
Miklos Szeredi committed Oct 23, 2014
1 parent c771d68 commit cbdf35b
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 26 deletions.
20 changes: 1 addition & 19 deletions fs/btrfs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -765,23 +765,6 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
return ret;
}

/* copy of check_sticky in fs/namei.c()
* It's inline, so penalty for filesystems that don't use sticky bit is
* minimal.
*/
static inline int btrfs_check_sticky(struct inode *dir, struct inode *inode)
{
kuid_t fsuid = current_fsuid();

if (!(dir->i_mode & S_ISVTX))
return 0;
if (uid_eq(inode->i_uid, fsuid))
return 0;
if (uid_eq(dir->i_uid, fsuid))
return 0;
return !capable(CAP_FOWNER);
}

/* copy of may_delete in fs/namei.c()
* Check whether we can remove a link victim from directory dir, check
* whether the type of victim is right.
Expand Down Expand Up @@ -817,8 +800,7 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir)
return error;
if (IS_APPEND(dir))
return -EPERM;
if (btrfs_check_sticky(dir, victim->d_inode)||
IS_APPEND(victim->d_inode)||
if (check_sticky(dir, victim->d_inode) || IS_APPEND(victim->d_inode) ||
IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode))
return -EPERM;
if (isdir) {
Expand Down
9 changes: 2 additions & 7 deletions fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -2384,22 +2384,17 @@ kern_path_mountpoint(int dfd, const char *name, struct path *path,
}
EXPORT_SYMBOL(kern_path_mountpoint);

/*
* It's inline, so penalty for filesystems that don't use sticky bit is
* minimal.
*/
static inline int check_sticky(struct inode *dir, struct inode *inode)
int __check_sticky(struct inode *dir, struct inode *inode)
{
kuid_t fsuid = current_fsuid();

if (!(dir->i_mode & S_ISVTX))
return 0;
if (uid_eq(inode->i_uid, fsuid))
return 0;
if (uid_eq(dir->i_uid, fsuid))
return 0;
return !capable_wrt_inode_uidgid(inode, CAP_FOWNER);
}
EXPORT_SYMBOL(__check_sticky);

/*
* Check whether we can remove a link victim from directory dir, check
Expand Down
9 changes: 9 additions & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2259,6 +2259,7 @@ extern int notify_change(struct dentry *, struct iattr *, struct inode **);
extern int inode_permission(struct inode *, int);
extern int __inode_permission(struct inode *, int);
extern int generic_permission(struct inode *, int);
extern int __check_sticky(struct inode *dir, struct inode *inode);

static inline bool execute_ok(struct inode *inode)
{
Expand Down Expand Up @@ -2745,6 +2746,14 @@ static inline int is_sxid(umode_t mode)
return (mode & S_ISUID) || ((mode & S_ISGID) && (mode & S_IXGRP));
}

static inline int check_sticky(struct inode *dir, struct inode *inode)
{
if (!(dir->i_mode & S_ISVTX))
return 0;

return __check_sticky(dir, inode);
}

static inline void inode_has_no_xattr(struct inode *inode)
{
if (!is_sxid(inode->i_mode) && (inode->i_sb->s_flags & MS_NOSEC))
Expand Down

0 comments on commit cbdf35b

Please sign in to comment.