forked from luck/tmp_suning_uos_patched
Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull misc vfs updates from Al Viro: "Assorted stuff all over the place (the largest group here is Christoph's stat cleanups)" * 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: fs: remove KSTAT_QUERY_FLAGS fs: remove vfs_stat_set_lookup_flags fs: move vfs_fstatat out of line fs: implement vfs_stat and vfs_lstat in terms of vfs_fstatat fs: remove vfs_statx_fd fs: omfs: use kmemdup() rather than kmalloc+memcpy [PATCH] reduce boilerplate in fsid handling fs: Remove duplicated flag O_NDELAY occurring twice in VALID_OPEN_FLAGS selftests: mount: add nosymfollow tests Add a "nosymfollow" mount option.
This commit is contained in:
commit
0eac1102e9
|
@ -260,8 +260,7 @@ static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_bavail = rs.bavail;
|
||||
buf->f_files = rs.files;
|
||||
buf->f_ffree = rs.ffree;
|
||||
buf->f_fsid.val[0] = rs.fsid & 0xFFFFFFFFUL;
|
||||
buf->f_fsid.val[1] = (rs.fsid >> 32) & 0xFFFFFFFFUL;
|
||||
buf->f_fsid = u64_to_fsid(rs.fsid);
|
||||
buf->f_namelen = rs.namelen;
|
||||
}
|
||||
if (res != -ENOSYS)
|
||||
|
|
|
@ -210,8 +210,7 @@ static int adfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_namelen = sbi->s_namelen;
|
||||
buf->f_bsize = sb->s_blocksize;
|
||||
buf->f_ffree = (long)(buf->f_bfree * buf->f_files) / (long)buf->f_blocks;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -620,8 +620,7 @@ affs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_blocks = AFFS_SB(sb)->s_partition_size - AFFS_SB(sb)->s_reserved;
|
||||
buf->f_bfree = free;
|
||||
buf->f_bavail = free;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
buf->f_namelen = AFFSNAMEMAX;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -963,8 +963,7 @@ befs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_bavail = buf->f_bfree;
|
||||
buf->f_files = 0; /* UNKNOWN */
|
||||
buf->f_ffree = 0; /* UNKNOWN */
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
buf->f_namelen = BEFS_NAME_LEN;
|
||||
|
||||
befs_debug(sb, "<--- %s", __func__);
|
||||
|
|
|
@ -229,8 +229,7 @@ static int bfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_bfree = buf->f_bavail = info->si_freeb;
|
||||
buf->f_files = info->si_lasti + 1 - BFS_ROOT_INO;
|
||||
buf->f_ffree = info->si_freei;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
buf->f_namelen = BFS_NAMELEN;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -104,8 +104,7 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
le64_to_cpu(*((__le64 *)&monc->monmap->fsid + 1));
|
||||
mutex_unlock(&monc->mutex);
|
||||
|
||||
buf->f_fsid.val[0] = fsid & 0xffffffff;
|
||||
buf->f_fsid.val[1] = fsid >> 32;
|
||||
buf->f_fsid = u64_to_fsid(fsid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -690,8 +690,7 @@ static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_bavail = 0;
|
||||
buf->f_files = CRAMFS_SB(sb)->files;
|
||||
buf->f_ffree = 0;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
buf->f_namelen = CRAMFS_MAXPATHLEN;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -342,8 +342,7 @@ static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) {
|
|||
sbi->inode_blocks *
|
||||
(EFS_BLOCKSIZE / sizeof(struct efs_dinode));
|
||||
buf->f_ffree = sbi->inode_free; /* free inodes */
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
buf->f_namelen = EFS_MAXNAMELEN; /* max filename length */
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -561,8 +561,7 @@ static int erofs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
|
||||
buf->f_namelen = EROFS_NAME_LEN;
|
||||
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,8 +89,7 @@ static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_blocks = sbi->num_clusters - 2; /* clu 0 & 1 */
|
||||
buf->f_bfree = buf->f_blocks - sbi->used_clusters;
|
||||
buf->f_bavail = buf->f_bfree;
|
||||
buf->f_fsid.val[0] = (unsigned int)id;
|
||||
buf->f_fsid.val[1] = (unsigned int)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
/* Unicode utf16 255 characters */
|
||||
buf->f_namelen = EXFAT_MAX_FILE_LEN * NLS_MAX_CHARSET_SIZE;
|
||||
return 0;
|
||||
|
|
|
@ -1455,8 +1455,7 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf)
|
|||
buf->f_namelen = EXT2_NAME_LEN;
|
||||
fsid = le64_to_cpup((void *)es->s_uuid) ^
|
||||
le64_to_cpup((void *)es->s_uuid + sizeof(u64));
|
||||
buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL;
|
||||
buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL;
|
||||
buf->f_fsid = u64_to_fsid(fsid);
|
||||
spin_unlock(&sbi->s_lock);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -6144,8 +6144,7 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_namelen = EXT4_NAME_LEN;
|
||||
fsid = le64_to_cpup((void *)es->s_uuid) ^
|
||||
le64_to_cpup((void *)es->s_uuid + sizeof(u64));
|
||||
buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL;
|
||||
buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL;
|
||||
buf->f_fsid = u64_to_fsid(fsid);
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
if (ext4_test_inode_flag(dentry->d_inode, EXT4_INODE_PROJINHERIT) &&
|
||||
|
|
|
@ -1442,8 +1442,7 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
}
|
||||
|
||||
buf->f_namelen = F2FS_NAME_LEN;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
if (is_inode_flag_set(dentry->d_inode, FI_PROJ_INHERIT) &&
|
||||
|
|
|
@ -836,8 +836,7 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_blocks = sbi->max_cluster - FAT_START_ENT;
|
||||
buf->f_bfree = sbi->free_clusters;
|
||||
buf->f_bavail = sbi->free_clusters;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
buf->f_namelen =
|
||||
(sbi->options.isvfat ? FAT_LFN_LEN : 12) * NLS_MAX_CHARSET_SIZE;
|
||||
|
||||
|
|
|
@ -104,8 +104,7 @@ static int hfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_bavail = buf->f_bfree;
|
||||
buf->f_files = HFS_SB(sb)->fs_ablocks;
|
||||
buf->f_ffree = HFS_SB(sb)->free_ablocks;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
buf->f_namelen = HFS_NAMELEN;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -320,8 +320,7 @@ static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_bavail = buf->f_bfree;
|
||||
buf->f_files = 0xFFFFFFFF;
|
||||
buf->f_ffree = 0xFFFFFFFF - sbi->next_cnid;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
buf->f_namelen = HFSPLUS_MAX_STRLEN;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -192,8 +192,7 @@ static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_bavail = sbi->sb_n_free;
|
||||
buf->f_files = sbi->sb_dirband_size / 4;
|
||||
buf->f_ffree = hpfs_get_free_dnodes(s);
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
buf->f_namelen = 254;
|
||||
|
||||
hpfs_unlock(s);
|
||||
|
|
|
@ -1038,8 +1038,7 @@ static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_bavail = 0;
|
||||
buf->f_files = ISOFS_SB(sb)->s_ninodes;
|
||||
buf->f_ffree = 0;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
buf->f_namelen = NAME_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -383,8 +383,7 @@ static int minix_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_files = sbi->s_ninodes;
|
||||
buf->f_ffree = minix_count_free_inodes(sb);
|
||||
buf->f_namelen = sbi->s_namelen;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1626,7 +1626,8 @@ static const char *pick_link(struct nameidata *nd, struct path *link,
|
|||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
if (unlikely(nd->flags & LOOKUP_NO_SYMLINKS))
|
||||
if (unlikely(nd->flags & LOOKUP_NO_SYMLINKS) ||
|
||||
unlikely(link->mnt->mnt_flags & MNT_NOSYMFOLLOW))
|
||||
return ERR_PTR(-ELOOP);
|
||||
|
||||
if (!(nd->flags & LOOKUP_RCU)) {
|
||||
|
|
|
@ -3171,6 +3171,8 @@ int path_mount(const char *dev_name, struct path *path,
|
|||
mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
|
||||
if (flags & MS_RDONLY)
|
||||
mnt_flags |= MNT_READONLY;
|
||||
if (flags & MS_NOSYMFOLLOW)
|
||||
mnt_flags |= MNT_NOSYMFOLLOW;
|
||||
|
||||
/* The default atime for remount is preservation */
|
||||
if ((flags & MS_REMOUNT) &&
|
||||
|
|
|
@ -651,8 +651,7 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_files = nmaxinodes;
|
||||
buf->f_ffree = nfreeinodes;
|
||||
buf->f_namelen = NILFS_NAME_LEN;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2643,8 +2643,7 @@ static int ntfs_statfs(struct dentry *dentry, struct kstatfs *sfs)
|
|||
* the least significant 32-bits in f_fsid[0] and the most significant
|
||||
* 32-bits in f_fsid[1].
|
||||
*/
|
||||
sfs->f_fsid.val[0] = vol->serial_no & 0xffffffff;
|
||||
sfs->f_fsid.val[1] = (vol->serial_no >> 32) & 0xffffffff;
|
||||
sfs->f_fsid = u64_to_fsid(vol->serial_no);
|
||||
/* Maximum length of filenames. */
|
||||
sfs->f_namelen = NTFS_MAX_NAME_LEN;
|
||||
return 0;
|
||||
|
|
|
@ -282,8 +282,7 @@ static int omfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_blocks = sbi->s_num_blocks;
|
||||
buf->f_files = sbi->s_num_blocks;
|
||||
buf->f_namelen = OMFS_NAMELEN;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
|
||||
buf->f_bfree = buf->f_bavail = buf->f_ffree =
|
||||
omfs_count_free(s);
|
||||
|
@ -363,12 +362,11 @@ static int omfs_get_imap(struct super_block *sb)
|
|||
bh = sb_bread(sb, block++);
|
||||
if (!bh)
|
||||
goto nomem_free;
|
||||
*ptr = kmalloc(sb->s_blocksize, GFP_KERNEL);
|
||||
*ptr = kmemdup(bh->b_data, sb->s_blocksize, GFP_KERNEL);
|
||||
if (!*ptr) {
|
||||
brelse(bh);
|
||||
goto nomem_free;
|
||||
}
|
||||
memcpy(*ptr, bh->b_data, sb->s_blocksize);
|
||||
if (count < sb->s_blocksize)
|
||||
memset((void *)*ptr + count, 0xff,
|
||||
sb->s_blocksize - count);
|
||||
|
|
|
@ -70,6 +70,7 @@ static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
|
|||
{ MNT_NOATIME, ",noatime" },
|
||||
{ MNT_NODIRATIME, ",nodiratime" },
|
||||
{ MNT_RELATIME, ",relatime" },
|
||||
{ MNT_NOSYMFOLLOW, ",nosymfollow" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
const struct proc_fs_opts *fs_infop;
|
||||
|
|
|
@ -137,8 +137,7 @@ static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_bfree = qnx4_count_free_blocks(sb);
|
||||
buf->f_bavail = buf->f_bfree;
|
||||
buf->f_namelen = QNX4_NAME_MAX;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -166,8 +166,7 @@ static int qnx6_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_ffree = fs32_to_cpu(sbi, sbi->sb->sb_free_inodes);
|
||||
buf->f_bavail = buf->f_bfree;
|
||||
buf->f_namelen = QNX6_LONG_NAME_MAX;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -416,8 +416,7 @@ static int romfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_bfree = buf->f_bavail = buf->f_ffree;
|
||||
buf->f_blocks =
|
||||
(romfs_maxsize(dentry->d_sb) + ROMBSIZE - 1) >> ROMBSBITS;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -380,8 +380,7 @@ static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_files = msblk->inodes;
|
||||
buf->f_ffree = 0;
|
||||
buf->f_namelen = SQUASHFS_NAME_LEN;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
70
fs/stat.c
70
fs/stat.c
|
@ -56,7 +56,7 @@ EXPORT_SYMBOL(generic_fillattr);
|
|||
* @path: file to get attributes from
|
||||
* @stat: structure to return attributes in
|
||||
* @request_mask: STATX_xxx flags indicating what the caller wants
|
||||
* @query_flags: Query mode (KSTAT_QUERY_FLAGS)
|
||||
* @query_flags: Query mode (AT_STATX_SYNC_TYPE)
|
||||
*
|
||||
* Get attributes without calling security_inode_getattr.
|
||||
*
|
||||
|
@ -71,7 +71,7 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat,
|
|||
|
||||
memset(stat, 0, sizeof(*stat));
|
||||
stat->result_mask |= STATX_BASIC_STATS;
|
||||
query_flags &= KSTAT_QUERY_FLAGS;
|
||||
query_flags &= AT_STATX_SYNC_TYPE;
|
||||
|
||||
/* allow the fs to override these if it really wants to */
|
||||
/* SB_NOATIME means filesystem supplies dummy atime value */
|
||||
|
@ -97,7 +97,7 @@ EXPORT_SYMBOL(vfs_getattr_nosec);
|
|||
* @path: The file of interest
|
||||
* @stat: Where to return the statistics
|
||||
* @request_mask: STATX_xxx flags indicating what the caller wants
|
||||
* @query_flags: Query mode (KSTAT_QUERY_FLAGS)
|
||||
* @query_flags: Query mode (AT_STATX_SYNC_TYPE)
|
||||
*
|
||||
* Ask the filesystem for a file's attributes. The caller must indicate in
|
||||
* request_mask and query_flags to indicate what they want.
|
||||
|
@ -126,53 +126,27 @@ int vfs_getattr(const struct path *path, struct kstat *stat,
|
|||
EXPORT_SYMBOL(vfs_getattr);
|
||||
|
||||
/**
|
||||
* vfs_statx_fd - Get the enhanced basic attributes by file descriptor
|
||||
* vfs_fstat - Get the basic attributes by file descriptor
|
||||
* @fd: The file descriptor referring to the file of interest
|
||||
* @stat: The result structure to fill in.
|
||||
* @request_mask: STATX_xxx flags indicating what the caller wants
|
||||
* @query_flags: Query mode (KSTAT_QUERY_FLAGS)
|
||||
*
|
||||
* This function is a wrapper around vfs_getattr(). The main difference is
|
||||
* that it uses a file descriptor to determine the file location.
|
||||
*
|
||||
* 0 will be returned on success, and a -ve error code if unsuccessful.
|
||||
*/
|
||||
int vfs_statx_fd(unsigned int fd, struct kstat *stat,
|
||||
u32 request_mask, unsigned int query_flags)
|
||||
int vfs_fstat(int fd, struct kstat *stat)
|
||||
{
|
||||
struct fd f;
|
||||
int error = -EBADF;
|
||||
|
||||
if (query_flags & ~KSTAT_QUERY_FLAGS)
|
||||
return -EINVAL;
|
||||
int error;
|
||||
|
||||
f = fdget_raw(fd);
|
||||
if (f.file) {
|
||||
error = vfs_getattr(&f.file->f_path, stat,
|
||||
request_mask, query_flags);
|
||||
fdput(f);
|
||||
}
|
||||
if (!f.file)
|
||||
return -EBADF;
|
||||
error = vfs_getattr(&f.file->f_path, stat, STATX_BASIC_STATS, 0);
|
||||
fdput(f);
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_statx_fd);
|
||||
|
||||
static inline unsigned vfs_stat_set_lookup_flags(unsigned *lookup_flags,
|
||||
int flags)
|
||||
{
|
||||
if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
|
||||
AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
*lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
|
||||
if (flags & AT_SYMLINK_NOFOLLOW)
|
||||
*lookup_flags &= ~LOOKUP_FOLLOW;
|
||||
if (flags & AT_NO_AUTOMOUNT)
|
||||
*lookup_flags &= ~LOOKUP_AUTOMOUNT;
|
||||
if (flags & AT_EMPTY_PATH)
|
||||
*lookup_flags |= LOOKUP_EMPTY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vfs_statx - Get basic and extra attributes by filename
|
||||
|
@ -189,15 +163,24 @@ static inline unsigned vfs_stat_set_lookup_flags(unsigned *lookup_flags,
|
|||
*
|
||||
* 0 will be returned on success, and a -ve error code if unsuccessful.
|
||||
*/
|
||||
int vfs_statx(int dfd, const char __user *filename, int flags,
|
||||
static int vfs_statx(int dfd, const char __user *filename, int flags,
|
||||
struct kstat *stat, u32 request_mask)
|
||||
{
|
||||
struct path path;
|
||||
int error = -EINVAL;
|
||||
unsigned lookup_flags;
|
||||
unsigned lookup_flags = 0;
|
||||
int error;
|
||||
|
||||
if (vfs_stat_set_lookup_flags(&lookup_flags, flags))
|
||||
if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | AT_EMPTY_PATH |
|
||||
AT_STATX_SYNC_TYPE))
|
||||
return -EINVAL;
|
||||
|
||||
if (!(flags & AT_SYMLINK_NOFOLLOW))
|
||||
lookup_flags |= LOOKUP_FOLLOW;
|
||||
if (!(flags & AT_NO_AUTOMOUNT))
|
||||
lookup_flags |= LOOKUP_AUTOMOUNT;
|
||||
if (flags & AT_EMPTY_PATH)
|
||||
lookup_flags |= LOOKUP_EMPTY;
|
||||
|
||||
retry:
|
||||
error = user_path_at(dfd, filename, lookup_flags, &path);
|
||||
if (error)
|
||||
|
@ -217,8 +200,13 @@ int vfs_statx(int dfd, const char __user *filename, int flags,
|
|||
out:
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_statx);
|
||||
|
||||
int vfs_fstatat(int dfd, const char __user *filename,
|
||||
struct kstat *stat, int flags)
|
||||
{
|
||||
return vfs_statx(dfd, filename, flags | AT_NO_AUTOMOUNT,
|
||||
stat, STATX_BASIC_STATS);
|
||||
}
|
||||
|
||||
#ifdef __ARCH_WANT_OLD_STAT
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ static int flags_by_mnt(int mnt_flags)
|
|||
flags |= ST_NODIRATIME;
|
||||
if (mnt_flags & MNT_RELATIME)
|
||||
flags |= ST_RELATIME;
|
||||
if (mnt_flags & MNT_NOSYMFOLLOW)
|
||||
flags |= ST_NOSYMFOLLOW;
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,8 +98,7 @@ static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
buf->f_files = sbi->s_ninodes;
|
||||
buf->f_ffree = sysv_count_free_inodes(sb);
|
||||
buf->f_namelen = SYSV_NAMELEN;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -2414,8 +2414,7 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
+ buf->f_bfree;
|
||||
buf->f_ffree = buf->f_bfree;
|
||||
buf->f_namelen = UDF_NAME_LEN;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1431,8 +1431,7 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
? (buf->f_bfree - uspi->s_root_blocks) : 0;
|
||||
buf->f_files = uspi->s_ncg * uspi->s_ipg;
|
||||
buf->f_namelen = UFS_MAXNAMLEN;
|
||||
buf->f_fsid.val[0] = (u32)id;
|
||||
buf->f_fsid.val[1] = (u32)(id >> 32);
|
||||
buf->f_fsid = u64_to_fsid(id);
|
||||
|
||||
mutex_unlock(&UFS_SB(sb)->s_lock);
|
||||
|
||||
|
|
|
@ -794,8 +794,7 @@ xfs_fs_statfs(
|
|||
statp->f_namelen = MAXNAMELEN - 1;
|
||||
|
||||
id = huge_encode_dev(mp->m_ddev_targp->bt_dev);
|
||||
statp->f_fsid.val[0] = (u32)id;
|
||||
statp->f_fsid.val[1] = (u32)(id >> 32);
|
||||
statp->f_fsid = u64_to_fsid(id);
|
||||
|
||||
icount = percpu_counter_sum(&mp->m_icount);
|
||||
ifree = percpu_counter_sum(&mp->m_ifree);
|
||||
|
|
|
@ -1116,8 +1116,7 @@ static int zonefs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
|
||||
fsid = le64_to_cpup((void *)sbi->s_uuid.b) ^
|
||||
le64_to_cpup((void *)sbi->s_uuid.b + sizeof(u64));
|
||||
buf->f_fsid.val[0] = (u32)fsid;
|
||||
buf->f_fsid.val[1] = (u32)(fsid >> 32);
|
||||
buf->f_fsid = u64_to_fsid(fsid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
/* List of all valid flags for the open/openat flags argument: */
|
||||
#define VALID_OPEN_FLAGS \
|
||||
(O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \
|
||||
O_APPEND | O_NDELAY | O_NONBLOCK | O_NDELAY | __O_SYNC | O_DSYNC | \
|
||||
O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \
|
||||
FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \
|
||||
O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE)
|
||||
|
||||
|
|
|
@ -3096,30 +3096,18 @@ extern const struct inode_operations simple_symlink_inode_operations;
|
|||
|
||||
extern int iterate_dir(struct file *, struct dir_context *);
|
||||
|
||||
extern int vfs_statx(int, const char __user *, int, struct kstat *, u32);
|
||||
extern int vfs_statx_fd(unsigned int, struct kstat *, u32, unsigned int);
|
||||
int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
|
||||
int flags);
|
||||
int vfs_fstat(int fd, struct kstat *stat);
|
||||
|
||||
static inline int vfs_stat(const char __user *filename, struct kstat *stat)
|
||||
{
|
||||
return vfs_statx(AT_FDCWD, filename, AT_NO_AUTOMOUNT,
|
||||
stat, STATX_BASIC_STATS);
|
||||
return vfs_fstatat(AT_FDCWD, filename, stat, 0);
|
||||
}
|
||||
static inline int vfs_lstat(const char __user *name, struct kstat *stat)
|
||||
{
|
||||
return vfs_statx(AT_FDCWD, name, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT,
|
||||
stat, STATX_BASIC_STATS);
|
||||
return vfs_fstatat(AT_FDCWD, name, stat, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
static inline int vfs_fstatat(int dfd, const char __user *filename,
|
||||
struct kstat *stat, int flags)
|
||||
{
|
||||
return vfs_statx(dfd, filename, flags | AT_NO_AUTOMOUNT,
|
||||
stat, STATX_BASIC_STATS);
|
||||
}
|
||||
static inline int vfs_fstat(int fd, struct kstat *stat)
|
||||
{
|
||||
return vfs_statx_fd(fd, stat, STATX_BASIC_STATS, 0);
|
||||
}
|
||||
|
||||
|
||||
extern const char *vfs_get_link(struct dentry *, struct delayed_call *);
|
||||
extern int vfs_readlink(struct dentry *, char __user *, int);
|
||||
|
|
|
@ -30,6 +30,7 @@ struct fs_context;
|
|||
#define MNT_NODIRATIME 0x10
|
||||
#define MNT_RELATIME 0x20
|
||||
#define MNT_READONLY 0x40 /* does the user want this to be r/o? */
|
||||
#define MNT_NOSYMFOLLOW 0x80
|
||||
|
||||
#define MNT_SHRINKABLE 0x100
|
||||
#define MNT_WRITE_HOLD 0x200
|
||||
|
@ -46,7 +47,7 @@ struct fs_context;
|
|||
#define MNT_SHARED_MASK (MNT_UNBINDABLE)
|
||||
#define MNT_USER_SETTABLE_MASK (MNT_NOSUID | MNT_NODEV | MNT_NOEXEC \
|
||||
| MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME \
|
||||
| MNT_READONLY)
|
||||
| MNT_READONLY | MNT_NOSYMFOLLOW)
|
||||
#define MNT_ATIME_MASK (MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME )
|
||||
|
||||
#define MNT_INTERNAL_FLAGS (MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL | \
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
#include <linux/time.h>
|
||||
#include <linux/uidgid.h>
|
||||
|
||||
#define KSTAT_QUERY_FLAGS (AT_STATX_SYNC_TYPE)
|
||||
|
||||
struct kstat {
|
||||
u32 result_mask; /* What fields the user got */
|
||||
umode_t mode;
|
||||
|
|
|
@ -40,8 +40,14 @@ struct kstatfs {
|
|||
#define ST_NOATIME 0x0400 /* do not update access times */
|
||||
#define ST_NODIRATIME 0x0800 /* do not update directory access times */
|
||||
#define ST_RELATIME 0x1000 /* update atime relative to mtime/ctime */
|
||||
#define ST_NOSYMFOLLOW 0x2000 /* do not follow symlinks */
|
||||
|
||||
struct dentry;
|
||||
extern int vfs_get_fsid(struct dentry *dentry, __kernel_fsid_t *fsid);
|
||||
|
||||
static inline __kernel_fsid_t u64_to_fsid(u64 v)
|
||||
{
|
||||
return (__kernel_fsid_t){.val = {(u32)v, (u32)(v>>32)}};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define MS_REMOUNT 32 /* Alter flags of a mounted FS */
|
||||
#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */
|
||||
#define MS_DIRSYNC 128 /* Directory modifications are synchronous */
|
||||
#define MS_NOSYMFOLLOW 256 /* Do not follow symlinks */
|
||||
#define MS_NOATIME 1024 /* Do not update access times. */
|
||||
#define MS_NODIRATIME 2048 /* Do not update directory access times */
|
||||
#define MS_BIND 4096
|
||||
|
|
1
tools/testing/selftests/mount/.gitignore
vendored
1
tools/testing/selftests/mount/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
unprivileged-remount-test
|
||||
nosymfollow-test
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
CFLAGS = -Wall \
|
||||
-O2
|
||||
|
||||
TEST_PROGS := run_tests.sh
|
||||
TEST_GEN_FILES := unprivileged-remount-test
|
||||
TEST_PROGS := run_unprivileged_remount.sh run_nosymfollow.sh
|
||||
TEST_GEN_FILES := unprivileged-remount-test nosymfollow-test
|
||||
|
||||
include ../lib.mk
|
||||
|
|
218
tools/testing/selftests/mount/nosymfollow-test.c
Normal file
218
tools/testing/selftests/mount/nosymfollow-test.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <sched.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef MS_NOSYMFOLLOW
|
||||
# define MS_NOSYMFOLLOW 256 /* Do not follow symlinks */
|
||||
#endif
|
||||
|
||||
#ifndef ST_NOSYMFOLLOW
|
||||
# define ST_NOSYMFOLLOW 0x2000 /* Do not follow symlinks */
|
||||
#endif
|
||||
|
||||
#define DATA "/tmp/data"
|
||||
#define LINK "/tmp/symlink"
|
||||
#define TMP "/tmp"
|
||||
|
||||
static void die(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void vmaybe_write_file(bool enoent_ok, char *filename, char *fmt,
|
||||
va_list ap)
|
||||
{
|
||||
ssize_t written;
|
||||
char buf[4096];
|
||||
int buf_len;
|
||||
int fd;
|
||||
|
||||
buf_len = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
if (buf_len < 0)
|
||||
die("vsnprintf failed: %s\n", strerror(errno));
|
||||
|
||||
if (buf_len >= sizeof(buf))
|
||||
die("vsnprintf output truncated\n");
|
||||
|
||||
fd = open(filename, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
if ((errno == ENOENT) && enoent_ok)
|
||||
return;
|
||||
die("open of %s failed: %s\n", filename, strerror(errno));
|
||||
}
|
||||
|
||||
written = write(fd, buf, buf_len);
|
||||
if (written != buf_len) {
|
||||
if (written >= 0) {
|
||||
die("short write to %s\n", filename);
|
||||
} else {
|
||||
die("write to %s failed: %s\n",
|
||||
filename, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (close(fd) != 0)
|
||||
die("close of %s failed: %s\n", filename, strerror(errno));
|
||||
}
|
||||
|
||||
static void maybe_write_file(char *filename, char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vmaybe_write_file(true, filename, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void write_file(char *filename, char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vmaybe_write_file(false, filename, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void create_and_enter_ns(void)
|
||||
{
|
||||
uid_t uid = getuid();
|
||||
gid_t gid = getgid();
|
||||
|
||||
if (unshare(CLONE_NEWUSER) != 0)
|
||||
die("unshare(CLONE_NEWUSER) failed: %s\n", strerror(errno));
|
||||
|
||||
maybe_write_file("/proc/self/setgroups", "deny");
|
||||
write_file("/proc/self/uid_map", "0 %d 1", uid);
|
||||
write_file("/proc/self/gid_map", "0 %d 1", gid);
|
||||
|
||||
if (setgid(0) != 0)
|
||||
die("setgid(0) failed %s\n", strerror(errno));
|
||||
if (setuid(0) != 0)
|
||||
die("setuid(0) failed %s\n", strerror(errno));
|
||||
|
||||
if (unshare(CLONE_NEWNS) != 0)
|
||||
die("unshare(CLONE_NEWNS) failed: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
static void setup_symlink(void)
|
||||
{
|
||||
int data, err;
|
||||
|
||||
data = creat(DATA, O_RDWR);
|
||||
if (data < 0)
|
||||
die("creat failed: %s\n", strerror(errno));
|
||||
|
||||
err = symlink(DATA, LINK);
|
||||
if (err < 0)
|
||||
die("symlink failed: %s\n", strerror(errno));
|
||||
|
||||
if (close(data) != 0)
|
||||
die("close of %s failed: %s\n", DATA, strerror(errno));
|
||||
}
|
||||
|
||||
static void test_link_traversal(bool nosymfollow)
|
||||
{
|
||||
int link;
|
||||
|
||||
link = open(LINK, 0, O_RDWR);
|
||||
if (nosymfollow) {
|
||||
if ((link != -1 || errno != ELOOP)) {
|
||||
die("link traversal unexpected result: %d, %s\n",
|
||||
link, strerror(errno));
|
||||
}
|
||||
} else {
|
||||
if (link < 0)
|
||||
die("link traversal failed: %s\n", strerror(errno));
|
||||
|
||||
if (close(link) != 0)
|
||||
die("close of link failed: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_readlink(void)
|
||||
{
|
||||
char buf[4096];
|
||||
ssize_t ret;
|
||||
|
||||
bzero(buf, sizeof(buf));
|
||||
|
||||
ret = readlink(LINK, buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
die("readlink failed: %s\n", strerror(errno));
|
||||
if (strcmp(buf, DATA) != 0)
|
||||
die("readlink strcmp failed: '%s' '%s'\n", buf, DATA);
|
||||
}
|
||||
|
||||
static void test_realpath(void)
|
||||
{
|
||||
char *path = realpath(LINK, NULL);
|
||||
|
||||
if (!path)
|
||||
die("realpath failed: %s\n", strerror(errno));
|
||||
if (strcmp(path, DATA) != 0)
|
||||
die("realpath strcmp failed\n");
|
||||
|
||||
free(path);
|
||||
}
|
||||
|
||||
static void test_statfs(bool nosymfollow)
|
||||
{
|
||||
struct statfs buf;
|
||||
int ret;
|
||||
|
||||
ret = statfs(TMP, &buf);
|
||||
if (ret)
|
||||
die("statfs failed: %s\n", strerror(errno));
|
||||
|
||||
if (nosymfollow) {
|
||||
if ((buf.f_flags & ST_NOSYMFOLLOW) == 0)
|
||||
die("ST_NOSYMFOLLOW not set on %s\n", TMP);
|
||||
} else {
|
||||
if ((buf.f_flags & ST_NOSYMFOLLOW) != 0)
|
||||
die("ST_NOSYMFOLLOW set on %s\n", TMP);
|
||||
}
|
||||
}
|
||||
|
||||
static void run_tests(bool nosymfollow)
|
||||
{
|
||||
test_link_traversal(nosymfollow);
|
||||
test_readlink();
|
||||
test_realpath();
|
||||
test_statfs(nosymfollow);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
create_and_enter_ns();
|
||||
|
||||
if (mount("testing", TMP, "ramfs", 0, NULL) != 0)
|
||||
die("mount failed: %s\n", strerror(errno));
|
||||
|
||||
setup_symlink();
|
||||
run_tests(false);
|
||||
|
||||
if (mount("testing", TMP, "ramfs", MS_REMOUNT|MS_NOSYMFOLLOW, NULL) != 0)
|
||||
die("remount failed: %s\n", strerror(errno));
|
||||
|
||||
run_tests(true);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
4
tools/testing/selftests/mount/run_nosymfollow.sh
Executable file
4
tools/testing/selftests/mount/run_nosymfollow.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
./nosymfollow-test
|
Loading…
Reference in New Issue
Block a user