Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vfs: export check_sticky()

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 <mszeredi@suse.cz>

+12 -26
+1 -19
fs/btrfs/ioctl.c
··· 765 765 return ret; 766 766 } 767 767 768 - /* copy of check_sticky in fs/namei.c() 769 - * It's inline, so penalty for filesystems that don't use sticky bit is 770 - * minimal. 771 - */ 772 - static inline int btrfs_check_sticky(struct inode *dir, struct inode *inode) 773 - { 774 - kuid_t fsuid = current_fsuid(); 775 - 776 - if (!(dir->i_mode & S_ISVTX)) 777 - return 0; 778 - if (uid_eq(inode->i_uid, fsuid)) 779 - return 0; 780 - if (uid_eq(dir->i_uid, fsuid)) 781 - return 0; 782 - return !capable(CAP_FOWNER); 783 - } 784 - 785 768 /* copy of may_delete in fs/namei.c() 786 769 * Check whether we can remove a link victim from directory dir, check 787 770 * whether the type of victim is right. ··· 800 817 return error; 801 818 if (IS_APPEND(dir)) 802 819 return -EPERM; 803 - if (btrfs_check_sticky(dir, victim->d_inode)|| 804 - IS_APPEND(victim->d_inode)|| 820 + if (check_sticky(dir, victim->d_inode) || IS_APPEND(victim->d_inode) || 805 821 IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode)) 806 822 return -EPERM; 807 823 if (isdir) {
+2 -7
fs/namei.c
··· 2384 2384 } 2385 2385 EXPORT_SYMBOL(kern_path_mountpoint); 2386 2386 2387 - /* 2388 - * It's inline, so penalty for filesystems that don't use sticky bit is 2389 - * minimal. 2390 - */ 2391 - static inline int check_sticky(struct inode *dir, struct inode *inode) 2387 + int __check_sticky(struct inode *dir, struct inode *inode) 2392 2388 { 2393 2389 kuid_t fsuid = current_fsuid(); 2394 2390 2395 - if (!(dir->i_mode & S_ISVTX)) 2396 - return 0; 2397 2391 if (uid_eq(inode->i_uid, fsuid)) 2398 2392 return 0; 2399 2393 if (uid_eq(dir->i_uid, fsuid)) 2400 2394 return 0; 2401 2395 return !capable_wrt_inode_uidgid(inode, CAP_FOWNER); 2402 2396 } 2397 + EXPORT_SYMBOL(__check_sticky); 2403 2398 2404 2399 /* 2405 2400 * Check whether we can remove a link victim from directory dir, check
+9
include/linux/fs.h
··· 2259 2259 extern int inode_permission(struct inode *, int); 2260 2260 extern int __inode_permission(struct inode *, int); 2261 2261 extern int generic_permission(struct inode *, int); 2262 + extern int __check_sticky(struct inode *dir, struct inode *inode); 2262 2263 2263 2264 static inline bool execute_ok(struct inode *inode) 2264 2265 { ··· 2744 2743 static inline int is_sxid(umode_t mode) 2745 2744 { 2746 2745 return (mode & S_ISUID) || ((mode & S_ISGID) && (mode & S_IXGRP)); 2746 + } 2747 + 2748 + static inline int check_sticky(struct inode *dir, struct inode *inode) 2749 + { 2750 + if (!(dir->i_mode & S_ISVTX)) 2751 + return 0; 2752 + 2753 + return __check_sticky(dir, inode); 2747 2754 } 2748 2755 2749 2756 static inline void inode_has_no_xattr(struct inode *inode)