[PATCH v4 4.17] inotify: Add flag IN_MASK_CREATE for inotify_add_watch()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Henry Wilson <henry.wilson@xxxxxxxxxxx>

inotify: Add flag IN_MASK_CREATE for inotify_add_watch()

The flag IN_MASK_CREATE is introduced as a flag for inotiy_add_watch() which
prevents inotify from modifying any existing watches when invoked. If the
pathname specified in the call has a watched inode associated with it and
IN_MASK_CREATE is specified, fail with an errno of EEXIST.

Use of IN_MASK_CREATE with IN_MASK_ADD is reserved for future use and will return
EINVAL.

RATIONALE

In the current implementation, there is no way to prevent inotify_add_watch()
from modifying existing watch descriptors. Even if the caller keeps a record of
all watch descriptors collected, this is only sufficient to detect that an
existing watch descriptor may have been modified.

The assumption that a particular path will map to the same inode over multiple
calls to inotify_add_watch() cannot be made as files can be renamed or deleted.
It is also not possible to assume that two distinct paths do no map to the same
inode, due to hard-links or a dereferenced symbolic link. Further uses of
inotify_add_watch() to revert the change may cause other watch descriptors to
be modified or created, merely compunding the problem. There is currently no
system call such as inotify_modify_watch() to explicity modify a watch
descriptor, which would be able to revert unwanted changes. Thus the caller
cannot guarantee to be able to revert any changes to existing watch decriptors.

Additionally the caller cannot assume that the events that are associated with a
watch descriptor are within the set requested, as any future calls to
inotify_add_watch() may unintentionally modify a watch descriptor's mask. Thus
it cannot currently be guaranteed that a watch descriptor will only generate
events which have been requested. The program must filter events which come
through its watch descriptor to within its expected range.

Signed-off-by: Henry Wilson <henry.wilson@xxxxxxxxxxx>
---

EXTENSIONS

A new system call inotify_modify_watch(fd, wd, mask) would be useful to modify
an existing watch directly to avoid similar problems when modifying a watch
descriptor's mask

CHANGELOG

v2: updated inotify_user_init() to the increased size of INOTIFY_ALL_BITS
v3: renamed IN_ONLY_CREATE to IN_EXCL_ADD
    additional rational for the change introduced to commit
v4: renamed IN_EXCL_ADD to IN_MASK_CREATE
    EINVAL returned when attempting to use IN_MASK_CREATE and IN_MASK_ADD
---
 fs/notify/inotify/inotify_user.c | 9 ++++++++-
 include/linux/inotify.h          | 2 +-
 include/uapi/linux/inotify.h     | 1 +
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index ef32f3657958..134e9c5308c8 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -506,6 +506,7 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,
 	__u32 old_mask, new_mask;
 	__u32 mask;
 	int add = (arg & IN_MASK_ADD);
+	int create = (arg & IN_MASK_CREATE);
 	int ret;
 
 	mask = inotify_arg_to_mask(arg);
@@ -513,6 +514,8 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,
 	fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, group);
 	if (!fsn_mark)
 		return -ENOENT;
+	else if (create)
+		return -EEXIST;
 
 	i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
 
@@ -714,6 +717,10 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
 	if (unlikely(!f.file))
 		return -EBADF;
 
+	/* IN_MASK_ADD and IN_MASK_CREATE don't make sense together */
+	if (unlikely((mask & IN_MASK_ADD) && (mask & IN_MASK_CREATE)))
+		return -EINVAL;
+
 	/* verify that this is indeed an inotify instance */
 	if (unlikely(f.file->f_op != &inotify_fops)) {
 		ret = -EINVAL;
@@ -802,7 +809,7 @@ static int __init inotify_user_setup(void)
 	BUILD_BUG_ON(IN_ISDIR != FS_ISDIR);
 	BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT);
 
-	BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21);
+	BUG_ON(hweight32(ALL_INOTIFY_BITS) != 22);
 
 	inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC);
 
diff --git a/include/linux/inotify.h b/include/linux/inotify.h
index 44f9ffe72c87..6a24905f6e1e 100644
--- a/include/linux/inotify.h
+++ b/include/linux/inotify.h
@@ -18,6 +18,6 @@ extern struct ctl_table inotify_table[]; /* for sysctl */
 			  IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT | \
 			  IN_Q_OVERFLOW | IN_IGNORED | IN_ONLYDIR | \
 			  IN_DONT_FOLLOW | IN_EXCL_UNLINK | IN_MASK_ADD | \
-			  IN_ISDIR | IN_ONESHOT)
+			  IN_MASK_CREATE | IN_ISDIR | IN_ONESHOT)
 
 #endif	/* _LINUX_INOTIFY_H */
diff --git a/include/uapi/linux/inotify.h b/include/uapi/linux/inotify.h
index 4800bf2a531d..884b4846b630 100644
--- a/include/uapi/linux/inotify.h
+++ b/include/uapi/linux/inotify.h
@@ -53,6 +53,7 @@ struct inotify_event {
 #define IN_ONLYDIR		0x01000000	/* only watch the path if it is a directory */
 #define IN_DONT_FOLLOW		0x02000000	/* don't follow a sym link */
 #define IN_EXCL_UNLINK		0x04000000	/* exclude events on unlinked objects */
+#define IN_MASK_CREATE		0x10000000	/* only create watches */
 #define IN_MASK_ADD		0x20000000	/* add to the mask of an already existing watch */
 #define IN_ISDIR		0x40000000	/* event occurred against dir */
 #define IN_ONESHOT		0x80000000	/* only send event once */
-- 
2.17.0




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux