Commit b9c55d29 authored by John McCutchan's avatar John McCutchan Committed by Linus Torvalds

[PATCH] inotify: fix race between the kernel and user space

When you rm a watch, an IN_IGNORED event is sent down the event queue
with the watch descriptor that you just rm'd.

If you then add a watch you could get the ignored watch's wd and if you
haven't read the entire event queue, user space will think that it's
newly created watch was just ignored.

To avoid this problem we just use idr_get_new_above instead of
idr_get_new.
Signed-off-by: default avatarJohn McCutchan <ttb@tentacle.dhs.org>
Signed-off-by: default avatarRobert Love <rml@novell.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 75449536
...@@ -90,6 +90,7 @@ struct inotify_device { ...@@ -90,6 +90,7 @@ struct inotify_device {
unsigned int queue_size; /* size of the queue (bytes) */ unsigned int queue_size; /* size of the queue (bytes) */
unsigned int event_count; /* number of pending events */ unsigned int event_count; /* number of pending events */
unsigned int max_events; /* maximum number of events */ unsigned int max_events; /* maximum number of events */
u32 last_wd; /* the last wd allocated */
}; };
/* /*
...@@ -352,7 +353,7 @@ static int inotify_dev_get_wd(struct inotify_device *dev, ...@@ -352,7 +353,7 @@ static int inotify_dev_get_wd(struct inotify_device *dev,
do { do {
if (unlikely(!idr_pre_get(&dev->idr, GFP_KERNEL))) if (unlikely(!idr_pre_get(&dev->idr, GFP_KERNEL)))
return -ENOSPC; return -ENOSPC;
ret = idr_get_new(&dev->idr, watch, &watch->wd); ret = idr_get_new_above(&dev->idr, watch, dev->last_wd, &watch->wd);
} while (ret == -EAGAIN); } while (ret == -EAGAIN);
return ret; return ret;
...@@ -401,6 +402,7 @@ static struct inotify_watch *create_watch(struct inotify_device *dev, ...@@ -401,6 +402,7 @@ static struct inotify_watch *create_watch(struct inotify_device *dev,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
dev->last_wd = ret;
watch->mask = mask; watch->mask = mask;
atomic_set(&watch->count, 0); atomic_set(&watch->count, 0);
INIT_LIST_HEAD(&watch->d_list); INIT_LIST_HEAD(&watch->d_list);
...@@ -899,6 +901,7 @@ asmlinkage long sys_inotify_init(void) ...@@ -899,6 +901,7 @@ asmlinkage long sys_inotify_init(void)
dev->queue_size = 0; dev->queue_size = 0;
dev->max_events = inotify_max_queued_events; dev->max_events = inotify_max_queued_events;
dev->user = user; dev->user = user;
dev->last_wd = 0;
atomic_set(&dev->count, 0); atomic_set(&dev->count, 0);
get_inotify_dev(dev); get_inotify_dev(dev);
......
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