summaryrefslogtreecommitdiffstats
path: root/fs/notify
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2019-01-08 08:02:44 -0500
committerJan Kara <jack@suse.cz>2019-02-18 06:41:16 -0500
commit40873284d7106fc0f0f4d2deae74b38fb18342cc (patch)
tree5d3965765a3d031321b026e576db2593242b77e0 /fs/notify
parentca6f86998d810d4a9fe172bf4cb6d3353636881f (diff)
fanotify: Track permission event state
Track whether permission event got already reported to userspace and whether userspace already answered to the permission event. Protect stores to this field together with updates to ->response field by group->notification_lock. This will allow aborting wait for reply to permission event from userspace. Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/notify')
-rw-r--r--fs/notify/fanotify/fanotify.c6
-rw-r--r--fs/notify/fanotify/fanotify.h10
-rw-r--r--fs/notify/fanotify/fanotify_user.c35
3 files changed, 40 insertions, 11 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 4ff84bc5772e..812c975df7ec 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -85,7 +85,8 @@ static int fanotify_get_response(struct fsnotify_group *group,
85 85
86 pr_debug("%s: group=%p event=%p\n", __func__, group, event); 86 pr_debug("%s: group=%p event=%p\n", __func__, group, event);
87 87
88 wait_event(group->fanotify_data.access_waitq, event->response); 88 wait_event(group->fanotify_data.access_waitq,
89 event->state == FAN_EVENT_ANSWERED);
89 90
90 /* userspace responded, convert to something usable */ 91 /* userspace responded, convert to something usable */
91 switch (event->response & ~FAN_AUDIT) { 92 switch (event->response & ~FAN_AUDIT) {
@@ -101,8 +102,6 @@ static int fanotify_get_response(struct fsnotify_group *group,
101 if (event->response & FAN_AUDIT) 102 if (event->response & FAN_AUDIT)
102 audit_fanotify(event->response & ~FAN_AUDIT); 103 audit_fanotify(event->response & ~FAN_AUDIT);
103 104
104 event->response = 0;
105
106 pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__, 105 pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__,
107 group, event, ret); 106 group, event, ret);
108 107
@@ -275,6 +274,7 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
275 goto out; 274 goto out;
276 event = &pevent->fae; 275 event = &pevent->fae;
277 pevent->response = 0; 276 pevent->response = 0;
277 pevent->state = FAN_EVENT_INIT;
278 goto init; 278 goto init;
279 } 279 }
280 event = kmem_cache_alloc(fanotify_event_cachep, gfp); 280 event = kmem_cache_alloc(fanotify_event_cachep, gfp);
diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h
index e84d68c6840a..480f281996d4 100644
--- a/fs/notify/fanotify/fanotify.h
+++ b/fs/notify/fanotify/fanotify.h
@@ -8,6 +8,13 @@ extern struct kmem_cache *fanotify_mark_cache;
8extern struct kmem_cache *fanotify_event_cachep; 8extern struct kmem_cache *fanotify_event_cachep;
9extern struct kmem_cache *fanotify_perm_event_cachep; 9extern struct kmem_cache *fanotify_perm_event_cachep;
10 10
11/* Possible states of the permission event */
12enum {
13 FAN_EVENT_INIT,
14 FAN_EVENT_REPORTED,
15 FAN_EVENT_ANSWERED
16};
17
11/* 18/*
12 * 3 dwords are sufficient for most local fs (64bit ino, 32bit generation). 19 * 3 dwords are sufficient for most local fs (64bit ino, 32bit generation).
13 * For 32bit arch, fid increases the size of fanotify_event by 12 bytes and 20 * For 32bit arch, fid increases the size of fanotify_event by 12 bytes and
@@ -109,7 +116,8 @@ static inline void *fanotify_event_fh(struct fanotify_event *event)
109 */ 116 */
110struct fanotify_perm_event { 117struct fanotify_perm_event {
111 struct fanotify_event fae; 118 struct fanotify_event fae;
112 int response; /* userspace answer to question */ 119 unsigned short response; /* userspace answer to the event */
120 unsigned short state; /* state of the event */
113 int fd; /* fd we passed to userspace for this event */ 121 int fd; /* fd we passed to userspace for this event */
114}; 122};
115 123
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index a73ada49fd3e..3c272f61d341 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -64,7 +64,8 @@ static int fanotify_event_info_len(struct fanotify_event *event)
64/* 64/*
65 * Get an fsnotify notification event if one exists and is small 65 * Get an fsnotify notification event if one exists and is small
66 * enough to fit in "count". Return an error pointer if the count 66 * enough to fit in "count". Return an error pointer if the count
67 * is not large enough. 67 * is not large enough. When permission event is dequeued, its state is
68 * updated accordingly.
68 */ 69 */
69static struct fsnotify_event *get_one_event(struct fsnotify_group *group, 70static struct fsnotify_event *get_one_event(struct fsnotify_group *group,
70 size_t count) 71 size_t count)
@@ -88,6 +89,8 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group,
88 goto out; 89 goto out;
89 } 90 }
90 fsn_event = fsnotify_remove_first_event(group); 91 fsn_event = fsnotify_remove_first_event(group);
92 if (fanotify_is_perm_event(FANOTIFY_E(fsn_event)->mask))
93 FANOTIFY_PE(fsn_event)->state = FAN_EVENT_REPORTED;
91out: 94out:
92 spin_unlock(&group->notification_lock); 95 spin_unlock(&group->notification_lock);
93 return fsn_event; 96 return fsn_event;
@@ -135,6 +138,21 @@ static int create_fd(struct fsnotify_group *group,
135 return client_fd; 138 return client_fd;
136} 139}
137 140
141/*
142 * Finish processing of permission event by setting it to ANSWERED state and
143 * drop group->notification_lock.
144 */
145static void finish_permission_event(struct fsnotify_group *group,
146 struct fanotify_perm_event *event,
147 unsigned int response)
148 __releases(&group->notification_lock)
149{
150 assert_spin_locked(&group->notification_lock);
151 event->response = response;
152 event->state = FAN_EVENT_ANSWERED;
153 spin_unlock(&group->notification_lock);
154}
155
138static int process_access_response(struct fsnotify_group *group, 156static int process_access_response(struct fsnotify_group *group,
139 struct fanotify_response *response_struct) 157 struct fanotify_response *response_struct)
140{ 158{
@@ -170,8 +188,7 @@ static int process_access_response(struct fsnotify_group *group,
170 continue; 188 continue;
171 189
172 list_del_init(&event->fae.fse.list); 190 list_del_init(&event->fae.fse.list);
173 event->response = response; 191 finish_permission_event(group, event, response);
174 spin_unlock(&group->notification_lock);
175 wake_up(&group->fanotify_data.access_waitq); 192 wake_up(&group->fanotify_data.access_waitq);
176 return 0; 193 return 0;
177 } 194 }
@@ -354,7 +371,9 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
354 fsnotify_destroy_event(group, kevent); 371 fsnotify_destroy_event(group, kevent);
355 } else { 372 } else {
356 if (ret <= 0) { 373 if (ret <= 0) {
357 FANOTIFY_PE(kevent)->response = FAN_DENY; 374 spin_lock(&group->notification_lock);
375 finish_permission_event(group,
376 FANOTIFY_PE(kevent), FAN_DENY);
358 wake_up(&group->fanotify_data.access_waitq); 377 wake_up(&group->fanotify_data.access_waitq);
359 } else { 378 } else {
360 spin_lock(&group->notification_lock); 379 spin_lock(&group->notification_lock);
@@ -423,7 +442,8 @@ static int fanotify_release(struct inode *ignored, struct file *file)
423 event = list_first_entry(&group->fanotify_data.access_list, 442 event = list_first_entry(&group->fanotify_data.access_list,
424 struct fanotify_perm_event, fae.fse.list); 443 struct fanotify_perm_event, fae.fse.list);
425 list_del_init(&event->fae.fse.list); 444 list_del_init(&event->fae.fse.list);
426 event->response = FAN_ALLOW; 445 finish_permission_event(group, event, FAN_ALLOW);
446 spin_lock(&group->notification_lock);
427 } 447 }
428 448
429 /* 449 /*
@@ -436,10 +456,11 @@ static int fanotify_release(struct inode *ignored, struct file *file)
436 if (!(FANOTIFY_E(fsn_event)->mask & FANOTIFY_PERM_EVENTS)) { 456 if (!(FANOTIFY_E(fsn_event)->mask & FANOTIFY_PERM_EVENTS)) {
437 spin_unlock(&group->notification_lock); 457 spin_unlock(&group->notification_lock);
438 fsnotify_destroy_event(group, fsn_event); 458 fsnotify_destroy_event(group, fsn_event);
439 spin_lock(&group->notification_lock);
440 } else { 459 } else {
441 FANOTIFY_PE(fsn_event)->response = FAN_ALLOW; 460 finish_permission_event(group, FANOTIFY_PE(fsn_event),
461 FAN_ALLOW);
442 } 462 }
463 spin_lock(&group->notification_lock);
443 } 464 }
444 spin_unlock(&group->notification_lock); 465 spin_unlock(&group->notification_lock);
445 466