Merge tag 'fsnotify_for_v7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull fsnotify updates from Jan Kara:
 "A couple of assorted fixes (mostly stuff spotted by Sashiko) for
  fsnotify subsystem.

  I'm also removing Matt as a reviewer because he was not active in
  fsnotify in last years and after he stopped working for Google I don't
  have a working contact to him"

* tag 'fsnotify_for_v7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  fsnotify: Fix stale object mask after concurrent mark updates
  fanotify: report full event length for FIONREAD
  fanotify: fix use-after-free of file range info
  fanotify: stop permission watchdog when timeout is zero
  fsnotify: Remove Matt Bobrowski as a reviewer
  fanotify: initialize permission event watchdog state
This commit is contained in:
Linus Torvalds
2026-08-20 12:47:41 -07:00
5 changed files with 25 additions and 30 deletions

View File

@@ -9915,7 +9915,6 @@ F: net/core/failover.c
FANOTIFY
M: Jan Kara <jack@suse.cz>
R: Amir Goldstein <amir73il@gmail.com>
R: Matthew Bobrowski <repnop@google.com>
L: linux-fsdevel@vger.kernel.org
S: Maintained
F: fs/notify/fanotify/

View File

@@ -599,9 +599,9 @@ static struct fanotify_event *fanotify_alloc_perm_event(const void *data,
pevent->hdr.pad = 0;
pevent->hdr.len = 0;
pevent->state = FAN_EVENT_INIT;
pevent->watchdog_cnt = 0;
pevent->path = *path;
/* NULL ppos means no range info */
pevent->ppos = range ? &range->pos : NULL;
pevent->pos = range ? range->pos : FANOTIFY_NO_RANGE;
pevent->count = range ? range->count : 0;
path_get(path);

View File

@@ -428,6 +428,8 @@ FANOTIFY_ME(struct fanotify_event *event)
return container_of(event, struct fanotify_mnt_event, fae);
}
#define FANOTIFY_NO_RANGE ((loff_t)-1)
/*
* Structure for permission fanotify events. It gets allocated and freed in
* fanotify_handle_event() since we wait there for user response. When the
@@ -438,7 +440,7 @@ FANOTIFY_ME(struct fanotify_event *event)
struct fanotify_perm_event {
struct fanotify_event fae;
struct path path;
const loff_t *ppos; /* optional file range info */
loff_t pos; /* FANOTIFY_NO_RANGE if unavailable */
size_t count;
u32 response; /* userspace answer to the event */
unsigned short state; /* state of the event */
@@ -468,7 +470,7 @@ static inline bool fanotify_event_has_access_range(struct fanotify_event *event)
if (!(event->mask & FANOTIFY_PRE_CONTENT_EVENTS))
return false;
return FANOTIFY_PERM(event)->ppos;
return FANOTIFY_PERM(event)->pos != FANOTIFY_NO_RANGE;
}
static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse)

View File

@@ -112,7 +112,12 @@ static DECLARE_DELAYED_WORK(perm_group_work, perm_group_watchdog);
static void perm_group_watchdog_schedule(void)
{
schedule_delayed_work(&perm_group_work, secs_to_jiffies(perm_group_timeout));
int timeout = READ_ONCE(perm_group_timeout);
if (!timeout)
return;
schedule_delayed_work(&perm_group_work, secs_to_jiffies(timeout));
}
static void perm_group_watchdog(struct work_struct *work)
@@ -675,12 +680,9 @@ static size_t copy_range_info_to_user(struct fanotify_event *event,
if (WARN_ON_ONCE(info_len > count))
return -EFAULT;
if (WARN_ON_ONCE(!pevent->ppos))
return -EINVAL;
info.hdr.info_type = FAN_EVENT_INFO_TYPE_RANGE;
info.hdr.len = info_len;
info.offset = *(pevent->ppos);
info.offset = pevent->pos;
info.count = pevent->count;
if (copy_to_user(buf, &info, info_len))
@@ -1145,11 +1147,13 @@ static long fanotify_ioctl(struct file *file, unsigned int cmd, unsigned long ar
{
struct fsnotify_group *group;
struct fsnotify_event *fsn_event;
unsigned int info_mode;
void __user *p;
int ret = -ENOTTY;
size_t send_len = 0;
group = file->private_data;
info_mode = FAN_GROUP_FLAG(group, FANOTIFY_INFO_MODES);
p = (void __user *) arg;
@@ -1157,7 +1161,8 @@ static long fanotify_ioctl(struct file *file, unsigned int cmd, unsigned long ar
case FIONREAD:
spin_lock(&group->notification_lock);
list_for_each_entry(fsn_event, &group->notification_list, list)
send_len += FAN_EVENT_METADATA_LEN;
send_len += fanotify_event_len(info_mode,
FANOTIFY_E(fsn_event));
spin_unlock(&group->notification_lock);
ret = put_user(send_len, (int __user *) p);
break;
@@ -1316,16 +1321,18 @@ static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark,
static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
__u32 mask, unsigned int fan_flags)
{
__u32 old_mask;
bool recalc;
spin_lock(&fsn_mark->lock);
if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS))
if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS)) {
old_mask = fsn_mark->mask;
fsn_mark->mask |= mask;
else
recalc = old_mask != fsn_mark->mask;
} else {
fsn_mark->ignore_mask |= mask;
recalc = fsnotify_calc_mask(fsn_mark) &
~fsnotify_conn_mask(fsn_mark->connector);
recalc = true;
}
recalc |= fanotify_mark_update_flags(fsn_mark, fan_flags);
spin_unlock(&fsn_mark->lock);

View File

@@ -539,7 +539,6 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,
{
struct fsnotify_mark *fsn_mark;
struct inotify_inode_mark *i_mark;
__u32 old_mask, new_mask;
int replace = !(arg & IN_MASK_ADD);
int create = (arg & IN_MASK_CREATE);
int ret;
@@ -555,27 +554,15 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,
i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
spin_lock(&fsn_mark->lock);
old_mask = fsn_mark->mask;
if (replace) {
fsn_mark->mask = 0;
fsn_mark->flags &= ~INOTIFY_MARK_FLAGS;
}
fsn_mark->mask |= inotify_arg_to_mask(inode, arg);
fsn_mark->flags |= inotify_arg_to_flags(arg);
new_mask = fsn_mark->mask;
spin_unlock(&fsn_mark->lock);
if (old_mask != new_mask) {
/* more bits in old than in new? */
int dropped = (old_mask & ~new_mask);
/* more bits in this fsn_mark than the inode's mask? */
int do_inode = (new_mask & ~READ_ONCE(inode->i_fsnotify_mask));
/* update the inode with this new fsn_mark */
if (dropped || do_inode)
fsnotify_recalc_mask(fsn_mark->connector);
}
fsnotify_recalc_mask(fsn_mark->connector);
/* return the wd */
ret = i_mark->wd;