summaryrefslogtreecommitdiffstats
path: root/fs/notify/fsnotify.c
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2010-08-28 03:24:24 +0200
committerEric Paris <eparis@redhat.com>2010-08-28 03:41:26 +0200
commitf72adfd540bacc4f6ff57a7d708b1a6c8906bdb4 (patch)
treedffd43e47284095e98f2a2ab60f965fc68792008 /fs/notify/fsnotify.c
parentfanotify: Return EPERM when a process is not privileged (diff)
downloadlinux-f72adfd540bacc4f6ff57a7d708b1a6c8906bdb4.tar.xz
linux-f72adfd540bacc4f6ff57a7d708b1a6c8906bdb4.zip
fsnotify: fix list walk order
Marks were stored on the inode and vfsmonut mark list in order from highest memory address to lowest memory address. The code to walk those lists thought they were in order from lowest to highest with unpredictable results when trying to match up marks from each. It was possible that extra events would be sent to userspace when inode marks ignoring events wouldn't get matched with the vfsmount marks. This problem only affected fanotify when using both vfsmount and inode marks simultaneously. Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to '')
-rw-r--r--fs/notify/fsnotify.c11
1 files changed, 5 insertions, 6 deletions
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 6f2777ce87a1..2169aa593d5f 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -261,27 +261,26 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
while (inode_node || vfsmount_node) {
used_inode = used_vfsmount = false;
+ inode_group = vfsmount_group = NULL;
if (inode_node) {
inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu),
struct fsnotify_mark, i.i_list);
inode_group = inode_mark->group;
- } else
- inode_group = (void *)-1;
+ }
if (vfsmount_node) {
vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu),
struct fsnotify_mark, m.m_list);
vfsmount_group = vfsmount_mark->group;
- } else
- vfsmount_group = (void *)-1;
+ }
- if (inode_group < vfsmount_group) {
+ if (inode_group > vfsmount_group) {
/* handle inode */
send_to_group(to_tell, NULL, inode_mark, NULL, mask, data,
data_is, cookie, file_name, &event);
used_inode = true;
- } else if (vfsmount_group < inode_group) {
+ } else if (vfsmount_group > inode_group) {
send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data,
data_is, cookie, file_name, &event);
used_vfsmount = true;