Commit 4b0a383a authored by Linus Torvalds's avatar Linus Torvalds

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

Pull fsnotify updates from Jan Kara:
 "Support for new FAN_OPEN_EXEC event and couple of cleanups around
  fsnotify"

* tag 'fsnotify_for_v4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  fanotify: Use inode_is_open_for_write
  fanotify: Make sure to check event_len when copying
  fsnotify/fdinfo: include fdinfo.h for inotify_show_fdinfo()
  fanotify: introduce new event mask FAN_OPEN_EXEC_PERM
  fsnotify: refactor fsnotify_parent()/fsnotify() paired calls when event is on path
  fanotify: introduce new event mask FAN_OPEN_EXEC
  fanotify: return only user requested event types in event mask
parents 4de3aea3 ac9498d6
...@@ -89,7 +89,13 @@ static int fanotify_get_response(struct fsnotify_group *group, ...@@ -89,7 +89,13 @@ static int fanotify_get_response(struct fsnotify_group *group,
return ret; return ret;
} }
static bool fanotify_should_send_event(struct fsnotify_iter_info *iter_info, /*
* This function returns a mask for an event that only contains the flags
* that have been specifically requested by the user. Flags that may have
* been included within the event mask, but have not been explicitly
* requested by the user, will not be present in the returned mask.
*/
static u32 fanotify_group_event_mask(struct fsnotify_iter_info *iter_info,
u32 event_mask, const void *data, u32 event_mask, const void *data,
int data_type) int data_type)
{ {
...@@ -101,14 +107,14 @@ static bool fanotify_should_send_event(struct fsnotify_iter_info *iter_info, ...@@ -101,14 +107,14 @@ static bool fanotify_should_send_event(struct fsnotify_iter_info *iter_info,
pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n", pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n",
__func__, iter_info->report_mask, event_mask, data, data_type); __func__, iter_info->report_mask, event_mask, data, data_type);
/* if we don't have enough info to send an event to userspace say no */ /* If we don't have enough info to send an event to userspace say no */
if (data_type != FSNOTIFY_EVENT_PATH) if (data_type != FSNOTIFY_EVENT_PATH)
return false; return 0;
/* sorry, fanotify only gives a damn about files and dirs */ /* Sorry, fanotify only gives a damn about files and dirs */
if (!d_is_reg(path->dentry) && if (!d_is_reg(path->dentry) &&
!d_can_lookup(path->dentry)) !d_can_lookup(path->dentry))
return false; return 0;
fsnotify_foreach_obj_type(type) { fsnotify_foreach_obj_type(type) {
if (!fsnotify_iter_should_report_type(iter_info, type)) if (!fsnotify_iter_should_report_type(iter_info, type))
...@@ -129,13 +135,10 @@ static bool fanotify_should_send_event(struct fsnotify_iter_info *iter_info, ...@@ -129,13 +135,10 @@ static bool fanotify_should_send_event(struct fsnotify_iter_info *iter_info,
if (d_is_dir(path->dentry) && if (d_is_dir(path->dentry) &&
!(marks_mask & FS_ISDIR & ~marks_ignored_mask)) !(marks_mask & FS_ISDIR & ~marks_ignored_mask))
return false; return 0;
if (event_mask & FANOTIFY_OUTGOING_EVENTS &
marks_mask & ~marks_ignored_mask)
return true;
return false; return event_mask & FANOTIFY_OUTGOING_EVENTS & marks_mask &
~marks_ignored_mask;
} }
struct fanotify_event_info *fanotify_alloc_event(struct fsnotify_group *group, struct fanotify_event_info *fanotify_alloc_event(struct fsnotify_group *group,
...@@ -207,10 +210,13 @@ static int fanotify_handle_event(struct fsnotify_group *group, ...@@ -207,10 +210,13 @@ static int fanotify_handle_event(struct fsnotify_group *group,
BUILD_BUG_ON(FAN_OPEN_PERM != FS_OPEN_PERM); BUILD_BUG_ON(FAN_OPEN_PERM != FS_OPEN_PERM);
BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM); BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM);
BUILD_BUG_ON(FAN_ONDIR != FS_ISDIR); BUILD_BUG_ON(FAN_ONDIR != FS_ISDIR);
BUILD_BUG_ON(FAN_OPEN_EXEC != FS_OPEN_EXEC);
BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM);
BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 10); BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 12);
if (!fanotify_should_send_event(iter_info, mask, data, data_type)) mask = fanotify_group_event_mask(iter_info, mask, data, data_type);
if (!mask)
return 0; return 0;
pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode, pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode,
......
...@@ -206,7 +206,7 @@ static int process_access_response(struct fsnotify_group *group, ...@@ -206,7 +206,7 @@ static int process_access_response(struct fsnotify_group *group,
static ssize_t copy_event_to_user(struct fsnotify_group *group, static ssize_t copy_event_to_user(struct fsnotify_group *group,
struct fsnotify_event *event, struct fsnotify_event *event,
char __user *buf) char __user *buf, size_t count)
{ {
struct fanotify_event_metadata fanotify_event_metadata; struct fanotify_event_metadata fanotify_event_metadata;
struct file *f; struct file *f;
...@@ -220,6 +220,12 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, ...@@ -220,6 +220,12 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
fd = fanotify_event_metadata.fd; fd = fanotify_event_metadata.fd;
ret = -EFAULT; ret = -EFAULT;
/*
* Sanity check copy size in case get_one_event() and
* fill_event_metadata() event_len sizes ever get out of sync.
*/
if (WARN_ON_ONCE(fanotify_event_metadata.event_len > count))
goto out_close_fd;
if (copy_to_user(buf, &fanotify_event_metadata, if (copy_to_user(buf, &fanotify_event_metadata,
fanotify_event_metadata.event_len)) fanotify_event_metadata.event_len))
goto out_close_fd; goto out_close_fd;
...@@ -295,7 +301,7 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, ...@@ -295,7 +301,7 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
continue; continue;
} }
ret = copy_event_to_user(group, kevent, buf); ret = copy_event_to_user(group, kevent, buf, count);
if (unlikely(ret == -EOPENSTALE)) { if (unlikely(ret == -EOPENSTALE)) {
/* /*
* We cannot report events with stale fd so drop it. * We cannot report events with stale fd so drop it.
...@@ -669,7 +675,7 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, ...@@ -669,7 +675,7 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,
*/ */
if ((flags & FAN_MARK_IGNORED_MASK) && if ((flags & FAN_MARK_IGNORED_MASK) &&
!(flags & FAN_MARK_IGNORED_SURV_MODIFY) && !(flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
(atomic_read(&inode->i_writecount) > 0)) inode_is_open_for_write(inode))
return 0; return 0;
return fanotify_add_mark(group, &inode->i_fsnotify_marks, return fanotify_add_mark(group, &inode->i_fsnotify_marks,
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/exportfs.h> #include <linux/exportfs.h>
#include "inotify/inotify.h" #include "inotify/inotify.h"
#include "fdinfo.h"
#include "fsnotify.h" #include "fsnotify.h"
#if defined(CONFIG_PROC_FS) #if defined(CONFIG_PROC_FS)
......
...@@ -401,7 +401,7 @@ static __init int fsnotify_init(void) ...@@ -401,7 +401,7 @@ static __init int fsnotify_init(void)
{ {
int ret; int ret;
BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 23); BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 25);
ret = init_srcu_struct(&fsnotify_mark_srcu); ret = init_srcu_struct(&fsnotify_mark_srcu);
if (ret) if (ret)
......
...@@ -37,10 +37,11 @@ ...@@ -37,10 +37,11 @@
/* Events that user can request to be notified on */ /* Events that user can request to be notified on */
#define FANOTIFY_EVENTS (FAN_ACCESS | FAN_MODIFY | \ #define FANOTIFY_EVENTS (FAN_ACCESS | FAN_MODIFY | \
FAN_CLOSE | FAN_OPEN) FAN_CLOSE | FAN_OPEN | FAN_OPEN_EXEC)
/* Events that require a permission response from user */ /* Events that require a permission response from user */
#define FANOTIFY_PERM_EVENTS (FAN_OPEN_PERM | FAN_ACCESS_PERM) #define FANOTIFY_PERM_EVENTS (FAN_OPEN_PERM | FAN_ACCESS_PERM | \
FAN_OPEN_EXEC_PERM)
/* Extra flags that may be reported with event or control handling of events */ /* Extra flags that may be reported with event or control handling of events */
#define FANOTIFY_EVENT_FLAGS (FAN_EVENT_ON_CHILD | FAN_ONDIR) #define FANOTIFY_EVENT_FLAGS (FAN_EVENT_ON_CHILD | FAN_ONDIR)
......
...@@ -26,30 +26,46 @@ static inline int fsnotify_parent(const struct path *path, struct dentry *dentry ...@@ -26,30 +26,46 @@ static inline int fsnotify_parent(const struct path *path, struct dentry *dentry
return __fsnotify_parent(path, dentry, mask); return __fsnotify_parent(path, dentry, mask);
} }
/* simple call site for access decisions */ /*
* Simple wrapper to consolidate calls fsnotify_parent()/fsnotify() when
* an event is on a path.
*/
static inline int fsnotify_path(struct inode *inode, const struct path *path,
__u32 mask)
{
int ret = fsnotify_parent(path, NULL, mask);
if (ret)
return ret;
return fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
}
/* Simple call site for access decisions */
static inline int fsnotify_perm(struct file *file, int mask) static inline int fsnotify_perm(struct file *file, int mask)
{ {
int ret;
const struct path *path = &file->f_path; const struct path *path = &file->f_path;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
__u32 fsnotify_mask = 0; __u32 fsnotify_mask = 0;
int ret;
if (file->f_mode & FMODE_NONOTIFY) if (file->f_mode & FMODE_NONOTIFY)
return 0; return 0;
if (!(mask & (MAY_READ | MAY_OPEN))) if (!(mask & (MAY_READ | MAY_OPEN)))
return 0; return 0;
if (mask & MAY_OPEN) if (mask & MAY_OPEN) {
fsnotify_mask = FS_OPEN_PERM; fsnotify_mask = FS_OPEN_PERM;
else if (mask & MAY_READ)
fsnotify_mask = FS_ACCESS_PERM;
else
BUG();
ret = fsnotify_parent(path, NULL, fsnotify_mask); if (file->f_flags & __FMODE_EXEC) {
ret = fsnotify_path(inode, path, FS_OPEN_EXEC_PERM);
if (ret) if (ret)
return ret; return ret;
}
} else if (mask & MAY_READ) {
fsnotify_mask = FS_ACCESS_PERM;
}
return fsnotify(inode, fsnotify_mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); return fsnotify_path(inode, path, fsnotify_mask);
} }
/* /*
...@@ -180,10 +196,8 @@ static inline void fsnotify_access(struct file *file) ...@@ -180,10 +196,8 @@ static inline void fsnotify_access(struct file *file)
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
mask |= FS_ISDIR; mask |= FS_ISDIR;
if (!(file->f_mode & FMODE_NONOTIFY)) { if (!(file->f_mode & FMODE_NONOTIFY))
fsnotify_parent(path, NULL, mask); fsnotify_path(inode, path, mask);
fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
}
} }
/* /*
...@@ -198,10 +212,8 @@ static inline void fsnotify_modify(struct file *file) ...@@ -198,10 +212,8 @@ static inline void fsnotify_modify(struct file *file)
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
mask |= FS_ISDIR; mask |= FS_ISDIR;
if (!(file->f_mode & FMODE_NONOTIFY)) { if (!(file->f_mode & FMODE_NONOTIFY))
fsnotify_parent(path, NULL, mask); fsnotify_path(inode, path, mask);
fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
}
} }
/* /*
...@@ -215,9 +227,10 @@ static inline void fsnotify_open(struct file *file) ...@@ -215,9 +227,10 @@ static inline void fsnotify_open(struct file *file)
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
mask |= FS_ISDIR; mask |= FS_ISDIR;
if (file->f_flags & __FMODE_EXEC)
mask |= FS_OPEN_EXEC;
fsnotify_parent(path, NULL, mask); fsnotify_path(inode, path, mask);
fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
} }
/* /*
...@@ -233,10 +246,8 @@ static inline void fsnotify_close(struct file *file) ...@@ -233,10 +246,8 @@ static inline void fsnotify_close(struct file *file)
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
mask |= FS_ISDIR; mask |= FS_ISDIR;
if (!(file->f_mode & FMODE_NONOTIFY)) { if (!(file->f_mode & FMODE_NONOTIFY))
fsnotify_parent(path, NULL, mask); fsnotify_path(inode, path, mask);
fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
}
} }
/* /*
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#define FS_DELETE 0x00000200 /* Subfile was deleted */ #define FS_DELETE 0x00000200 /* Subfile was deleted */
#define FS_DELETE_SELF 0x00000400 /* Self was deleted */ #define FS_DELETE_SELF 0x00000400 /* Self was deleted */
#define FS_MOVE_SELF 0x00000800 /* Self was moved */ #define FS_MOVE_SELF 0x00000800 /* Self was moved */
#define FS_OPEN_EXEC 0x00001000 /* File was opened for exec */
#define FS_UNMOUNT 0x00002000 /* inode on umount fs */ #define FS_UNMOUNT 0x00002000 /* inode on umount fs */
#define FS_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ #define FS_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
...@@ -45,6 +46,7 @@ ...@@ -45,6 +46,7 @@
#define FS_OPEN_PERM 0x00010000 /* open event in an permission hook */ #define FS_OPEN_PERM 0x00010000 /* open event in an permission hook */
#define FS_ACCESS_PERM 0x00020000 /* access event in a permissions hook */ #define FS_ACCESS_PERM 0x00020000 /* access event in a permissions hook */
#define FS_OPEN_EXEC_PERM 0x00040000 /* open/exec event in a permission hook */
#define FS_EXCL_UNLINK 0x04000000 /* do not send events if object is unlinked */ #define FS_EXCL_UNLINK 0x04000000 /* do not send events if object is unlinked */
#define FS_ISDIR 0x40000000 /* event occurred against dir */ #define FS_ISDIR 0x40000000 /* event occurred against dir */
...@@ -62,11 +64,13 @@ ...@@ -62,11 +64,13 @@
#define FS_EVENTS_POSS_ON_CHILD (FS_ACCESS | FS_MODIFY | FS_ATTRIB |\ #define FS_EVENTS_POSS_ON_CHILD (FS_ACCESS | FS_MODIFY | FS_ATTRIB |\
FS_CLOSE_WRITE | FS_CLOSE_NOWRITE | FS_OPEN |\ FS_CLOSE_WRITE | FS_CLOSE_NOWRITE | FS_OPEN |\
FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE |\ FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE |\
FS_DELETE | FS_OPEN_PERM | FS_ACCESS_PERM) FS_DELETE | FS_OPEN_PERM | FS_ACCESS_PERM | \
FS_OPEN_EXEC | FS_OPEN_EXEC_PERM)
#define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO) #define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO)
#define ALL_FSNOTIFY_PERM_EVENTS (FS_OPEN_PERM | FS_ACCESS_PERM) #define ALL_FSNOTIFY_PERM_EVENTS (FS_OPEN_PERM | FS_ACCESS_PERM | \
FS_OPEN_EXEC_PERM)
/* Events that can be reported to backends */ /* Events that can be reported to backends */
#define ALL_FSNOTIFY_EVENTS (FS_ACCESS | FS_MODIFY | FS_ATTRIB | \ #define ALL_FSNOTIFY_EVENTS (FS_ACCESS | FS_MODIFY | FS_ATTRIB | \
...@@ -74,7 +78,8 @@ ...@@ -74,7 +78,8 @@
FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE | \ FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE | \
FS_DELETE | FS_DELETE_SELF | FS_MOVE_SELF | \ FS_DELETE | FS_DELETE_SELF | FS_MOVE_SELF | \
FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \ FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \
FS_OPEN_PERM | FS_ACCESS_PERM | FS_DN_RENAME) FS_OPEN_PERM | FS_ACCESS_PERM | FS_DN_RENAME | \
FS_OPEN_EXEC | FS_OPEN_EXEC_PERM)
/* Extra flags that may be reported with event or control handling of events */ /* Extra flags that may be reported with event or control handling of events */
#define ALL_FSNOTIFY_FLAGS (FS_EXCL_UNLINK | FS_ISDIR | FS_IN_ONESHOT | \ #define ALL_FSNOTIFY_FLAGS (FS_EXCL_UNLINK | FS_ISDIR | FS_IN_ONESHOT | \
......
...@@ -10,11 +10,13 @@ ...@@ -10,11 +10,13 @@
#define FAN_CLOSE_WRITE 0x00000008 /* Writtable file closed */ #define FAN_CLOSE_WRITE 0x00000008 /* Writtable file closed */
#define FAN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */ #define FAN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */
#define FAN_OPEN 0x00000020 /* File was opened */ #define FAN_OPEN 0x00000020 /* File was opened */
#define FAN_OPEN_EXEC 0x00001000 /* File was opened for exec */
#define FAN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ #define FAN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
#define FAN_OPEN_PERM 0x00010000 /* File open in perm check */ #define FAN_OPEN_PERM 0x00010000 /* File open in perm check */
#define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */ #define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */
#define FAN_OPEN_EXEC_PERM 0x00040000 /* File open/exec in perm check */
#define FAN_ONDIR 0x40000000 /* event occurred against dir */ #define FAN_ONDIR 0x40000000 /* event occurred against dir */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment