sanitize struct filename and lookup flags handling in statx

and friends
 
 Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQQqUNBr3gm4hGXdBJlZ7Krx/gZQ6wUCZzdpZQAKCRBZ7Krx/gZQ
 6whMAQDhlGFV+nGRetwe4t60mVRpxIoc71GLC7b6V8FmyfTI5AEAkAigkJ8KCZDP
 mfGsN/3PtzoxnIkIqdk7Y7q4/fowyAw=
 =4DWZ
 -----END PGP SIGNATURE-----

Merge tag 'pull-statx' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull statx updates from Al Viro:
 "Sanitize struct filename and lookup flags handling in statx and
  friends"

* tag 'pull-statx' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  libfs: kill empty_dir_getattr()
  fs: Simplify getattr interface function checking AT_GETATTR_NOSEC flag
  fs/stat.c: switch to CLASS(fd_raw)
  kill getname_statx_lookup_flags()
  io_statx_prep(): use getname_uflags()
This commit is contained in:
Linus Torvalds 2024-11-18 14:54:10 -08:00
commit c6d64479d6
8 changed files with 15 additions and 58 deletions

View File

@ -1008,14 +1008,6 @@ static int ecryptfs_getattr_link(struct mnt_idmap *idmap,
return rc; return rc;
} }
static int ecryptfs_do_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int flags)
{
if (flags & AT_GETATTR_NOSEC)
return vfs_getattr_nosec(path, stat, request_mask, flags);
return vfs_getattr(path, stat, request_mask, flags);
}
static int ecryptfs_getattr(struct mnt_idmap *idmap, static int ecryptfs_getattr(struct mnt_idmap *idmap,
const struct path *path, struct kstat *stat, const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int flags) u32 request_mask, unsigned int flags)
@ -1024,7 +1016,7 @@ static int ecryptfs_getattr(struct mnt_idmap *idmap,
struct kstat lower_stat; struct kstat lower_stat;
int rc; int rc;
rc = ecryptfs_do_getattr(ecryptfs_dentry_to_lower_path(dentry), rc = vfs_getattr_nosec(ecryptfs_dentry_to_lower_path(dentry),
&lower_stat, request_mask, flags); &lower_stat, request_mask, flags);
if (!rc) { if (!rc) {
fsstack_copy_attr_all(d_inode(dentry), fsstack_copy_attr_all(d_inode(dentry),

View File

@ -246,7 +246,6 @@ int open_namespace(struct ns_common *ns);
* fs/stat.c: * fs/stat.c:
*/ */
int getname_statx_lookup_flags(int flags);
int do_statx(int dfd, struct filename *filename, unsigned int flags, int do_statx(int dfd, struct filename *filename, unsigned int flags,
unsigned int mask, struct statx __user *buffer); unsigned int mask, struct statx __user *buffer);
int do_statx_fd(int fd, unsigned int flags, unsigned int mask, int do_statx_fd(int fd, unsigned int flags, unsigned int mask,

View File

@ -1715,15 +1715,6 @@ static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
static int empty_dir_getattr(struct mnt_idmap *idmap,
const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int query_flags)
{
struct inode *inode = d_inode(path->dentry);
generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
return 0;
}
static int empty_dir_setattr(struct mnt_idmap *idmap, static int empty_dir_setattr(struct mnt_idmap *idmap,
struct dentry *dentry, struct iattr *attr) struct dentry *dentry, struct iattr *attr)
{ {
@ -1737,9 +1728,7 @@ static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t siz
static const struct inode_operations empty_dir_inode_operations = { static const struct inode_operations empty_dir_inode_operations = {
.lookup = empty_dir_lookup, .lookup = empty_dir_lookup,
.permission = generic_permission,
.setattr = empty_dir_setattr, .setattr = empty_dir_setattr,
.getattr = empty_dir_getattr,
.listxattr = empty_dir_listxattr, .listxattr = empty_dir_listxattr,
}; };

View File

@ -170,7 +170,7 @@ int ovl_getattr(struct mnt_idmap *idmap, const struct path *path,
type = ovl_path_real(dentry, &realpath); type = ovl_path_real(dentry, &realpath);
old_cred = ovl_override_creds(dentry->d_sb); old_cred = ovl_override_creds(dentry->d_sb);
err = ovl_do_getattr(&realpath, stat, request_mask, flags); err = vfs_getattr_nosec(&realpath, stat, request_mask, flags);
if (err) if (err)
goto out; goto out;
@ -195,7 +195,7 @@ int ovl_getattr(struct mnt_idmap *idmap, const struct path *path,
(!is_dir ? STATX_NLINK : 0); (!is_dir ? STATX_NLINK : 0);
ovl_path_lower(dentry, &realpath); ovl_path_lower(dentry, &realpath);
err = ovl_do_getattr(&realpath, &lowerstat, lowermask, err = vfs_getattr_nosec(&realpath, &lowerstat, lowermask,
flags); flags);
if (err) if (err)
goto out; goto out;
@ -248,7 +248,7 @@ int ovl_getattr(struct mnt_idmap *idmap, const struct path *path,
ovl_path_lowerdata(dentry, &realpath); ovl_path_lowerdata(dentry, &realpath);
if (realpath.dentry) { if (realpath.dentry) {
err = ovl_do_getattr(&realpath, &lowerdatastat, err = vfs_getattr_nosec(&realpath, &lowerdatastat,
lowermask, flags); lowermask, flags);
if (err) if (err)
goto out; goto out;

View File

@ -412,14 +412,6 @@ static inline bool ovl_open_flags_need_copy_up(int flags)
return ((OPEN_FMODE(flags) & FMODE_WRITE) || (flags & O_TRUNC)); return ((OPEN_FMODE(flags) & FMODE_WRITE) || (flags & O_TRUNC));
} }
static inline int ovl_do_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int flags)
{
if (flags & AT_GETATTR_NOSEC)
return vfs_getattr_nosec(path, stat, request_mask, flags);
return vfs_getattr(path, stat, request_mask, flags);
}
/* util.c */ /* util.c */
int ovl_get_write_access(struct dentry *dentry); int ovl_get_write_access(struct dentry *dentry);
void ovl_put_write_access(struct dentry *dentry); void ovl_put_write_access(struct dentry *dentry);

View File

@ -207,7 +207,7 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat,
if (inode->i_op->getattr) if (inode->i_op->getattr)
return inode->i_op->getattr(idmap, path, stat, return inode->i_op->getattr(idmap, path, stat,
request_mask, request_mask,
query_flags | AT_GETATTR_NOSEC); query_flags);
generic_fillattr(idmap, request_mask, inode, stat); generic_fillattr(idmap, request_mask, inode, stat);
return 0; return 0;
@ -240,9 +240,6 @@ int vfs_getattr(const struct path *path, struct kstat *stat,
{ {
int retval; int retval;
if (WARN_ON_ONCE(query_flags & AT_GETATTR_NOSEC))
return -EPERM;
retval = security_inode_getattr(path); retval = security_inode_getattr(path);
if (retval) if (retval)
return retval; return retval;
@ -262,18 +259,13 @@ EXPORT_SYMBOL(vfs_getattr);
*/ */
int vfs_fstat(int fd, struct kstat *stat) int vfs_fstat(int fd, struct kstat *stat)
{ {
struct fd f; CLASS(fd_raw, f)(fd);
int error; if (fd_empty(f))
f = fdget_raw(fd);
if (!fd_file(f))
return -EBADF; return -EBADF;
error = vfs_getattr(&fd_file(f)->f_path, stat, STATX_BASIC_STATS, 0); return vfs_getattr(&fd_file(f)->f_path, stat, STATX_BASIC_STATS, 0);
fdput(f);
return error;
} }
int getname_statx_lookup_flags(int flags) static int statx_lookup_flags(int flags)
{ {
int lookup_flags = 0; int lookup_flags = 0;
@ -281,8 +273,6 @@ int getname_statx_lookup_flags(int flags)
lookup_flags |= LOOKUP_FOLLOW; lookup_flags |= LOOKUP_FOLLOW;
if (!(flags & AT_NO_AUTOMOUNT)) if (!(flags & AT_NO_AUTOMOUNT))
lookup_flags |= LOOKUP_AUTOMOUNT; lookup_flags |= LOOKUP_AUTOMOUNT;
if (flags & AT_EMPTY_PATH)
lookup_flags |= LOOKUP_EMPTY;
return lookup_flags; return lookup_flags;
} }
@ -319,7 +309,7 @@ static int vfs_statx_fd(int fd, int flags, struct kstat *stat,
u32 request_mask) u32 request_mask)
{ {
CLASS(fd_raw, f)(fd); CLASS(fd_raw, f)(fd);
if (!fd_file(f)) if (fd_empty(f))
return -EBADF; return -EBADF;
return vfs_statx_path(&fd_file(f)->f_path, flags, stat, request_mask); return vfs_statx_path(&fd_file(f)->f_path, flags, stat, request_mask);
} }
@ -343,7 +333,7 @@ static int vfs_statx(int dfd, struct filename *filename, int flags,
struct kstat *stat, u32 request_mask) struct kstat *stat, u32 request_mask)
{ {
struct path path; struct path path;
unsigned int lookup_flags = getname_statx_lookup_flags(flags); unsigned int lookup_flags = statx_lookup_flags(flags);
int error; int error;
if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | AT_EMPTY_PATH | if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | AT_EMPTY_PATH |

View File

@ -154,8 +154,4 @@
usable with open_by_handle_at(2). */ usable with open_by_handle_at(2). */
#define AT_HANDLE_MNT_ID_UNIQUE 0x001 /* Return the u64 unique mount ID. */ #define AT_HANDLE_MNT_ID_UNIQUE 0x001 /* Return the u64 unique mount ID. */
#if defined(__KERNEL__)
#define AT_GETATTR_NOSEC 0x80000000
#endif
#endif /* _UAPI_LINUX_FCNTL_H */ #endif /* _UAPI_LINUX_FCNTL_H */

View File

@ -36,8 +36,7 @@ int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
sx->buffer = u64_to_user_ptr(READ_ONCE(sqe->addr2)); sx->buffer = u64_to_user_ptr(READ_ONCE(sqe->addr2));
sx->flags = READ_ONCE(sqe->statx_flags); sx->flags = READ_ONCE(sqe->statx_flags);
sx->filename = getname_flags(path, sx->filename = getname_uflags(path, sx->flags);
getname_statx_lookup_flags(sx->flags));
if (IS_ERR(sx->filename)) { if (IS_ERR(sx->filename)) {
int ret = PTR_ERR(sx->filename); int ret = PTR_ERR(sx->filename);