Skip to content

Commit

Permalink
Merge tag 'vfs-6.15-rc3.fixes.2' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/kernel/git/vfs/vfs

Pull vfs fixes from Christian Brauner:

 - Revert the hfs{plus} deprecation warning that's also included in this
   pull request. The commit introducing the deprecation warning resides
   rather early in this branch. So simply dropping it would've rebased
   all other commits which I decided to avoid. Hence the revert in the
   same branch

   [ Background - the deprecation warning discussion resulted in people
     stepping up, and so hfs{plus} will have a maintainer taking care of
     it after all..   - Linus ]

 - Switch CONFIG_SYSFS_SYCALL default to n and decouple from
   CONFIG_EXPERT

 - Fix an audit bug caused by changes to our kernel path lookup helpers
   this cycle. Audit needs the parent path even if the dentry it tried
   to look up is negative

 - Ensure that the kernel path lookup helpers leave the passed in path
   argument clean when they return an error. This is consistent with all
   our other helpers

 - Ensure that vfs_getattr_nosec() calls bdev_statx() so the relevant
   information is available to kernel consumers as well

 - Don't set a timer and call schedule() if the timer will expire
   immediately in epoll

 - Make netfs lookup tables with __nonstring

* tag 'vfs-6.15-rc3.fixes.2' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  Revert "hfs{plus}: add deprecation warning"
  fs: move the bdex_statx call to vfs_getattr_nosec
  netfs: Mark __nonstring lookup tables
  eventpoll: Set epoll timeout if it's in the future
  fs: ensure that *path_locked*() helpers leave passed path pristine
  fs: add kern_path_locked_negative()
  hfs{plus}: add deprecation warning
  Kconfig: switch CONFIG_SYSFS_SYCALL default to n
  • Loading branch information
Linus Torvalds committed Apr 19, 2025
2 parents 6fe8131 + 408e450 commit 119009d
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 61 deletions.
3 changes: 1 addition & 2 deletions block/bdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1272,8 +1272,7 @@ void sync_bdevs(bool wait)
/*
* Handle STATX_{DIOALIGN, WRITE_ATOMIC} for block devices.
*/
void bdev_statx(struct path *path, struct kstat *stat,
u32 request_mask)
void bdev_statx(const struct path *path, struct kstat *stat, u32 request_mask)
{
struct inode *backing_inode;
struct block_device *bdev;
Expand Down
10 changes: 9 additions & 1 deletion fs/eventpoll.c
Original file line number Diff line number Diff line change
Expand Up @@ -1996,6 +1996,14 @@ static int ep_try_send_events(struct eventpoll *ep,
return res;
}

static int ep_schedule_timeout(ktime_t *to)
{
if (to)
return ktime_after(*to, ktime_get());
else
return 1;
}

/**
* ep_poll - Retrieves ready events, and delivers them to the caller-supplied
* event buffer.
Expand Down Expand Up @@ -2103,7 +2111,7 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,

write_unlock_irq(&ep->lock);

if (!eavail)
if (!eavail && ep_schedule_timeout(to))
timed_out = !schedule_hrtimeout_range(to, slack,
HRTIMER_MODE_ABS);
__set_current_state(TASK_RUNNING);
Expand Down
81 changes: 58 additions & 23 deletions fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -1665,27 +1665,20 @@ static struct dentry *lookup_dcache(const struct qstr *name,
return dentry;
}

/*
* Parent directory has inode locked exclusive. This is one
* and only case when ->lookup() gets called on non in-lookup
* dentries - as the matter of fact, this only gets called
* when directory is guaranteed to have no in-lookup children
* at all.
* Will return -ENOENT if name isn't found and LOOKUP_CREATE wasn't passed.
* Will return -EEXIST if name is found and LOOKUP_EXCL was passed.
*/
struct dentry *lookup_one_qstr_excl(const struct qstr *name,
struct dentry *base,
unsigned int flags)
static struct dentry *lookup_one_qstr_excl_raw(const struct qstr *name,
struct dentry *base,
unsigned int flags)
{
struct dentry *dentry = lookup_dcache(name, base, flags);
struct dentry *dentry;
struct dentry *old;
struct inode *dir = base->d_inode;
struct inode *dir;

dentry = lookup_dcache(name, base, flags);
if (dentry)
goto found;
return dentry;

/* Don't create child dentry for a dead directory. */
dir = base->d_inode;
if (unlikely(IS_DEADDIR(dir)))
return ERR_PTR(-ENOENT);

Expand All @@ -1698,7 +1691,24 @@ struct dentry *lookup_one_qstr_excl(const struct qstr *name,
dput(dentry);
dentry = old;
}
found:
return dentry;
}

/*
* Parent directory has inode locked exclusive. This is one
* and only case when ->lookup() gets called on non in-lookup
* dentries - as the matter of fact, this only gets called
* when directory is guaranteed to have no in-lookup children
* at all.
* Will return -ENOENT if name isn't found and LOOKUP_CREATE wasn't passed.
* Will return -EEXIST if name is found and LOOKUP_EXCL was passed.
*/
struct dentry *lookup_one_qstr_excl(const struct qstr *name,
struct dentry *base, unsigned int flags)
{
struct dentry *dentry;

dentry = lookup_one_qstr_excl_raw(name, base, flags);
if (IS_ERR(dentry))
return dentry;
if (d_is_negative(dentry) && !(flags & LOOKUP_CREATE)) {
Expand Down Expand Up @@ -2742,23 +2752,48 @@ static int filename_parentat(int dfd, struct filename *name,
/* does lookup, returns the object with parent locked */
static struct dentry *__kern_path_locked(int dfd, struct filename *name, struct path *path)
{
struct path parent_path __free(path_put) = {};
struct dentry *d;
struct qstr last;
int type, error;

error = filename_parentat(dfd, name, 0, path, &last, &type);
error = filename_parentat(dfd, name, 0, &parent_path, &last, &type);
if (error)
return ERR_PTR(error);
if (unlikely(type != LAST_NORM)) {
path_put(path);
if (unlikely(type != LAST_NORM))
return ERR_PTR(-EINVAL);
inode_lock_nested(parent_path.dentry->d_inode, I_MUTEX_PARENT);
d = lookup_one_qstr_excl(&last, parent_path.dentry, 0);
if (IS_ERR(d)) {
inode_unlock(parent_path.dentry->d_inode);
return d;
}
inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT);
d = lookup_one_qstr_excl(&last, path->dentry, 0);
path->dentry = no_free_ptr(parent_path.dentry);
path->mnt = no_free_ptr(parent_path.mnt);
return d;
}

struct dentry *kern_path_locked_negative(const char *name, struct path *path)
{
struct path parent_path __free(path_put) = {};
struct filename *filename __free(putname) = getname_kernel(name);
struct dentry *d;
struct qstr last;
int type, error;

error = filename_parentat(AT_FDCWD, filename, 0, &parent_path, &last, &type);
if (error)
return ERR_PTR(error);
if (unlikely(type != LAST_NORM))
return ERR_PTR(-EINVAL);
inode_lock_nested(parent_path.dentry->d_inode, I_MUTEX_PARENT);
d = lookup_one_qstr_excl_raw(&last, parent_path.dentry, 0);
if (IS_ERR(d)) {
inode_unlock(path->dentry->d_inode);
path_put(path);
inode_unlock(parent_path.dentry->d_inode);
return d;
}
path->dentry = no_free_ptr(parent_path.dentry);
path->mnt = no_free_ptr(parent_path.mnt);
return d;
}

Expand Down
2 changes: 1 addition & 1 deletion fs/netfs/fscache_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ void fscache_withdraw_cache(struct fscache_cache *cache)
EXPORT_SYMBOL(fscache_withdraw_cache);

#ifdef CONFIG_PROC_FS
static const char fscache_cache_states[NR__FSCACHE_CACHE_STATE] = "-PAEW";
static const char fscache_cache_states[NR__FSCACHE_CACHE_STATE] __nonstring = "-PAEW";

/*
* Generate a list of caches in /proc/fs/fscache/caches
Expand Down
2 changes: 1 addition & 1 deletion fs/netfs/fscache_cookie.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ static LIST_HEAD(fscache_cookie_lru);
static DEFINE_SPINLOCK(fscache_cookie_lru_lock);
DEFINE_TIMER(fscache_cookie_lru_timer, fscache_cookie_lru_timed_out);
static DECLARE_WORK(fscache_cookie_lru_work, fscache_cookie_lru_worker);
static const char fscache_cookie_states[FSCACHE_COOKIE_STATE__NR] = "-LCAIFUWRD";
static const char fscache_cookie_states[FSCACHE_COOKIE_STATE__NR] __nonstring = "-LCAIFUWRD";
static unsigned int fscache_lru_cookie_timeout = 10 * HZ;

void fscache_print_cookie(struct fscache_cookie *cookie, char prefix)
Expand Down
32 changes: 18 additions & 14 deletions fs/stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,25 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat,
STATX_ATTR_DAX);

idmap = mnt_idmap(path->mnt);
if (inode->i_op->getattr)
return inode->i_op->getattr(idmap, path, stat,
request_mask,
query_flags);
if (inode->i_op->getattr) {
int ret;

ret = inode->i_op->getattr(idmap, path, stat, request_mask,
query_flags);
if (ret)
return ret;
} else {
generic_fillattr(idmap, request_mask, inode, stat);
}

/*
* If this is a block device inode, override the filesystem attributes
* with the block device specific parameters that need to be obtained
* from the bdev backing inode.
*/
if (S_ISBLK(stat->mode))
bdev_statx(path, stat, request_mask);

generic_fillattr(idmap, request_mask, inode, stat);
return 0;
}
EXPORT_SYMBOL(vfs_getattr_nosec);
Expand Down Expand Up @@ -295,15 +308,6 @@ static int vfs_statx_path(struct path *path, int flags, struct kstat *stat,
if (path_mounted(path))
stat->attributes |= STATX_ATTR_MOUNT_ROOT;
stat->attributes_mask |= STATX_ATTR_MOUNT_ROOT;

/*
* If this is a block device inode, override the filesystem
* attributes with the block device specific parameters that need to be
* obtained from the bdev backing inode.
*/
if (S_ISBLK(stat->mode))
bdev_statx(path, stat, request_mask);

return 0;
}

Expand Down
6 changes: 3 additions & 3 deletions include/linux/blkdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -1685,7 +1685,7 @@ int sync_blockdev(struct block_device *bdev);
int sync_blockdev_range(struct block_device *bdev, loff_t lstart, loff_t lend);
int sync_blockdev_nowait(struct block_device *bdev);
void sync_bdevs(bool wait);
void bdev_statx(struct path *, struct kstat *, u32);
void bdev_statx(const struct path *path, struct kstat *stat, u32 request_mask);
void printk_all_partitions(void);
int __init early_lookup_bdev(const char *pathname, dev_t *dev);
#else
Expand All @@ -1703,8 +1703,8 @@ static inline int sync_blockdev_nowait(struct block_device *bdev)
static inline void sync_bdevs(bool wait)
{
}
static inline void bdev_statx(struct path *path, struct kstat *stat,
u32 request_mask)
static inline void bdev_statx(const struct path *path, struct kstat *stat,
u32 request_mask)
{
}
static inline void printk_all_partitions(void)
Expand Down
1 change: 1 addition & 0 deletions include/linux/namei.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ extern struct dentry *kern_path_create(int, const char *, struct path *, unsigne
extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
extern void done_path_create(struct path *, struct dentry *);
extern struct dentry *kern_path_locked(const char *, struct path *);
extern struct dentry *kern_path_locked_negative(const char *, struct path *);
extern struct dentry *user_path_locked_at(int , const char __user *, struct path *);
int vfs_path_parent_lookup(struct filename *filename, unsigned int flags,
struct path *parent, struct qstr *last, int *type,
Expand Down
20 changes: 10 additions & 10 deletions init/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1555,6 +1555,16 @@ config SYSCTL_ARCH_UNALIGN_ALLOW
the unaligned access emulation.
see arch/parisc/kernel/unaligned.c for reference

config SYSFS_SYSCALL
bool "Sysfs syscall support"
default n
help
sys_sysfs is an obsolete system call no longer supported in libc.
Note that disabling this option is more secure but might break
compatibility with some systems.

If unsure say N here.

config HAVE_PCSPKR_PLATFORM
bool

Expand Down Expand Up @@ -1599,16 +1609,6 @@ config SGETMASK_SYSCALL

If unsure, leave the default option here.

config SYSFS_SYSCALL
bool "Sysfs syscall support" if EXPERT
default y
help
sys_sysfs is an obsolete system call no longer supported in libc.
Note that disabling this option is more secure but might break
compatibility with some systems.

If unsure say Y here.

config FHANDLE
bool "open by fhandle syscalls" if EXPERT
select EXPORTFS
Expand Down
16 changes: 10 additions & 6 deletions kernel/audit_watch.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,12 +347,17 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
/* Get path information necessary for adding watches. */
static int audit_get_nd(struct audit_watch *watch, struct path *parent)
{
struct dentry *d = kern_path_locked(watch->path, parent);
struct dentry *d;

d = kern_path_locked_negative(watch->path, parent);
if (IS_ERR(d))
return PTR_ERR(d);
/* update watch filter fields */
watch->dev = d->d_sb->s_dev;
watch->ino = d_backing_inode(d)->i_ino;

if (d_is_positive(d)) {
/* update watch filter fields */
watch->dev = d->d_sb->s_dev;
watch->ino = d_backing_inode(d)->i_ino;
}

inode_unlock(d_backing_inode(parent->dentry));
dput(d);
Expand Down Expand Up @@ -418,11 +423,10 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
/* caller expects mutex locked */
mutex_lock(&audit_filter_mutex);

if (ret && ret != -ENOENT) {
if (ret) {
audit_put_watch(watch);
return ret;
}
ret = 0;

/* either find an old parent or attach a new one */
parent = audit_find_parent(d_backing_inode(parent_path.dentry));
Expand Down

0 comments on commit 119009d

Please sign in to comment.