.. | .. |
---|
17 | 17 | #include <linux/compat.h> |
---|
18 | 18 | #include <linux/sched/signal.h> |
---|
19 | 19 | #include <linux/memcontrol.h> |
---|
| 20 | +#include <linux/statfs.h> |
---|
| 21 | +#include <linux/exportfs.h> |
---|
20 | 22 | |
---|
21 | 23 | #include <asm/ioctls.h> |
---|
22 | 24 | |
---|
.. | .. |
---|
44 | 46 | extern const struct fsnotify_ops fanotify_fsnotify_ops; |
---|
45 | 47 | |
---|
46 | 48 | struct kmem_cache *fanotify_mark_cache __read_mostly; |
---|
47 | | -struct kmem_cache *fanotify_event_cachep __read_mostly; |
---|
| 49 | +struct kmem_cache *fanotify_fid_event_cachep __read_mostly; |
---|
| 50 | +struct kmem_cache *fanotify_path_event_cachep __read_mostly; |
---|
48 | 51 | struct kmem_cache *fanotify_perm_event_cachep __read_mostly; |
---|
49 | 52 | |
---|
| 53 | +#define FANOTIFY_EVENT_ALIGN 4 |
---|
| 54 | +#define FANOTIFY_INFO_HDR_LEN \ |
---|
| 55 | + (sizeof(struct fanotify_event_info_fid) + sizeof(struct file_handle)) |
---|
| 56 | + |
---|
| 57 | +static int fanotify_fid_info_len(int fh_len, int name_len) |
---|
| 58 | +{ |
---|
| 59 | + int info_len = fh_len; |
---|
| 60 | + |
---|
| 61 | + if (name_len) |
---|
| 62 | + info_len += name_len + 1; |
---|
| 63 | + |
---|
| 64 | + return roundup(FANOTIFY_INFO_HDR_LEN + info_len, FANOTIFY_EVENT_ALIGN); |
---|
| 65 | +} |
---|
| 66 | + |
---|
| 67 | +static int fanotify_event_info_len(unsigned int fid_mode, |
---|
| 68 | + struct fanotify_event *event) |
---|
| 69 | +{ |
---|
| 70 | + struct fanotify_info *info = fanotify_event_info(event); |
---|
| 71 | + int dir_fh_len = fanotify_event_dir_fh_len(event); |
---|
| 72 | + int fh_len = fanotify_event_object_fh_len(event); |
---|
| 73 | + int info_len = 0; |
---|
| 74 | + int dot_len = 0; |
---|
| 75 | + |
---|
| 76 | + if (dir_fh_len) { |
---|
| 77 | + info_len += fanotify_fid_info_len(dir_fh_len, info->name_len); |
---|
| 78 | + } else if ((fid_mode & FAN_REPORT_NAME) && (event->mask & FAN_ONDIR)) { |
---|
| 79 | + /* |
---|
| 80 | + * With group flag FAN_REPORT_NAME, if name was not recorded in |
---|
| 81 | + * event on a directory, we will report the name ".". |
---|
| 82 | + */ |
---|
| 83 | + dot_len = 1; |
---|
| 84 | + } |
---|
| 85 | + |
---|
| 86 | + if (fh_len) |
---|
| 87 | + info_len += fanotify_fid_info_len(fh_len, dot_len); |
---|
| 88 | + |
---|
| 89 | + return info_len; |
---|
| 90 | +} |
---|
| 91 | + |
---|
50 | 92 | /* |
---|
51 | | - * Get an fsnotify notification event if one exists and is small |
---|
| 93 | + * Get an fanotify notification event if one exists and is small |
---|
52 | 94 | * enough to fit in "count". Return an error pointer if the count |
---|
53 | | - * is not large enough. |
---|
54 | | - * |
---|
55 | | - * Called with the group->notification_lock held. |
---|
| 95 | + * is not large enough. When permission event is dequeued, its state is |
---|
| 96 | + * updated accordingly. |
---|
56 | 97 | */ |
---|
57 | | -static struct fsnotify_event *get_one_event(struct fsnotify_group *group, |
---|
| 98 | +static struct fanotify_event *get_one_event(struct fsnotify_group *group, |
---|
58 | 99 | size_t count) |
---|
59 | 100 | { |
---|
60 | | - assert_spin_locked(&group->notification_lock); |
---|
| 101 | + size_t event_size = FAN_EVENT_METADATA_LEN; |
---|
| 102 | + struct fanotify_event *event = NULL; |
---|
| 103 | + unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); |
---|
61 | 104 | |
---|
62 | 105 | pr_debug("%s: group=%p count=%zd\n", __func__, group, count); |
---|
63 | 106 | |
---|
| 107 | + spin_lock(&group->notification_lock); |
---|
64 | 108 | if (fsnotify_notify_queue_is_empty(group)) |
---|
65 | | - return NULL; |
---|
| 109 | + goto out; |
---|
66 | 110 | |
---|
67 | | - if (FAN_EVENT_METADATA_LEN > count) |
---|
68 | | - return ERR_PTR(-EINVAL); |
---|
| 111 | + if (fid_mode) { |
---|
| 112 | + event_size += fanotify_event_info_len(fid_mode, |
---|
| 113 | + FANOTIFY_E(fsnotify_peek_first_event(group))); |
---|
| 114 | + } |
---|
69 | 115 | |
---|
70 | | - /* held the notification_lock the whole time, so this is the |
---|
71 | | - * same event we peeked above */ |
---|
72 | | - return fsnotify_remove_first_event(group); |
---|
| 116 | + if (event_size > count) { |
---|
| 117 | + event = ERR_PTR(-EINVAL); |
---|
| 118 | + goto out; |
---|
| 119 | + } |
---|
| 120 | + event = FANOTIFY_E(fsnotify_remove_first_event(group)); |
---|
| 121 | + if (fanotify_is_perm_event(event->mask)) |
---|
| 122 | + FANOTIFY_PERM(event)->state = FAN_EVENT_REPORTED; |
---|
| 123 | +out: |
---|
| 124 | + spin_unlock(&group->notification_lock); |
---|
| 125 | + return event; |
---|
73 | 126 | } |
---|
74 | 127 | |
---|
75 | | -static int create_fd(struct fsnotify_group *group, |
---|
76 | | - struct fanotify_event_info *event, |
---|
| 128 | +static int create_fd(struct fsnotify_group *group, struct path *path, |
---|
77 | 129 | struct file **file) |
---|
78 | 130 | { |
---|
79 | 131 | int client_fd; |
---|
80 | 132 | struct file *new_file; |
---|
81 | | - |
---|
82 | | - pr_debug("%s: group=%p event=%p\n", __func__, group, event); |
---|
83 | 133 | |
---|
84 | 134 | client_fd = get_unused_fd_flags(group->fanotify_data.f_flags); |
---|
85 | 135 | if (client_fd < 0) |
---|
.. | .. |
---|
89 | 139 | * we need a new file handle for the userspace program so it can read even if it was |
---|
90 | 140 | * originally opened O_WRONLY. |
---|
91 | 141 | */ |
---|
92 | | - /* it's possible this event was an overflow event. in that case dentry and mnt |
---|
93 | | - * are NULL; That's fine, just don't call dentry open */ |
---|
94 | | - if (event->path.dentry && event->path.mnt) |
---|
95 | | - new_file = dentry_open(&event->path, |
---|
96 | | - group->fanotify_data.f_flags | FMODE_NONOTIFY, |
---|
97 | | - current_cred()); |
---|
98 | | - else |
---|
99 | | - new_file = ERR_PTR(-EOVERFLOW); |
---|
| 142 | + new_file = dentry_open(path, |
---|
| 143 | + group->fanotify_data.f_flags | FMODE_NONOTIFY, |
---|
| 144 | + current_cred()); |
---|
100 | 145 | if (IS_ERR(new_file)) { |
---|
101 | 146 | /* |
---|
102 | 147 | * we still send an event even if we can't open the file. this |
---|
.. | .. |
---|
114 | 159 | return client_fd; |
---|
115 | 160 | } |
---|
116 | 161 | |
---|
117 | | -static int fill_event_metadata(struct fsnotify_group *group, |
---|
118 | | - struct fanotify_event_metadata *metadata, |
---|
119 | | - struct fsnotify_event *fsn_event, |
---|
120 | | - struct file **file) |
---|
| 162 | +/* |
---|
| 163 | + * Finish processing of permission event by setting it to ANSWERED state and |
---|
| 164 | + * drop group->notification_lock. |
---|
| 165 | + */ |
---|
| 166 | +static void finish_permission_event(struct fsnotify_group *group, |
---|
| 167 | + struct fanotify_perm_event *event, |
---|
| 168 | + unsigned int response) |
---|
| 169 | + __releases(&group->notification_lock) |
---|
121 | 170 | { |
---|
122 | | - int ret = 0; |
---|
123 | | - struct fanotify_event_info *event; |
---|
| 171 | + bool destroy = false; |
---|
124 | 172 | |
---|
125 | | - pr_debug("%s: group=%p metadata=%p event=%p\n", __func__, |
---|
126 | | - group, metadata, fsn_event); |
---|
127 | | - |
---|
128 | | - *file = NULL; |
---|
129 | | - event = container_of(fsn_event, struct fanotify_event_info, fse); |
---|
130 | | - metadata->event_len = FAN_EVENT_METADATA_LEN; |
---|
131 | | - metadata->metadata_len = FAN_EVENT_METADATA_LEN; |
---|
132 | | - metadata->vers = FANOTIFY_METADATA_VERSION; |
---|
133 | | - metadata->reserved = 0; |
---|
134 | | - metadata->mask = fsn_event->mask & FAN_ALL_OUTGOING_EVENTS; |
---|
135 | | - metadata->pid = pid_vnr(event->tgid); |
---|
136 | | - if (unlikely(fsn_event->mask & FAN_Q_OVERFLOW)) |
---|
137 | | - metadata->fd = FAN_NOFD; |
---|
138 | | - else { |
---|
139 | | - metadata->fd = create_fd(group, event, file); |
---|
140 | | - if (metadata->fd < 0) |
---|
141 | | - ret = metadata->fd; |
---|
142 | | - } |
---|
143 | | - |
---|
144 | | - return ret; |
---|
145 | | -} |
---|
146 | | - |
---|
147 | | -static struct fanotify_perm_event_info *dequeue_event( |
---|
148 | | - struct fsnotify_group *group, int fd) |
---|
149 | | -{ |
---|
150 | | - struct fanotify_perm_event_info *event, *return_e = NULL; |
---|
151 | | - |
---|
152 | | - spin_lock(&group->notification_lock); |
---|
153 | | - list_for_each_entry(event, &group->fanotify_data.access_list, |
---|
154 | | - fae.fse.list) { |
---|
155 | | - if (event->fd != fd) |
---|
156 | | - continue; |
---|
157 | | - |
---|
158 | | - list_del_init(&event->fae.fse.list); |
---|
159 | | - return_e = event; |
---|
160 | | - break; |
---|
161 | | - } |
---|
| 173 | + assert_spin_locked(&group->notification_lock); |
---|
| 174 | + event->response = response; |
---|
| 175 | + if (event->state == FAN_EVENT_CANCELED) |
---|
| 176 | + destroy = true; |
---|
| 177 | + else |
---|
| 178 | + event->state = FAN_EVENT_ANSWERED; |
---|
162 | 179 | spin_unlock(&group->notification_lock); |
---|
163 | | - |
---|
164 | | - pr_debug("%s: found return_re=%p\n", __func__, return_e); |
---|
165 | | - |
---|
166 | | - return return_e; |
---|
| 180 | + if (destroy) |
---|
| 181 | + fsnotify_destroy_event(group, &event->fae.fse); |
---|
167 | 182 | } |
---|
168 | 183 | |
---|
169 | 184 | static int process_access_response(struct fsnotify_group *group, |
---|
170 | 185 | struct fanotify_response *response_struct) |
---|
171 | 186 | { |
---|
172 | | - struct fanotify_perm_event_info *event; |
---|
| 187 | + struct fanotify_perm_event *event; |
---|
173 | 188 | int fd = response_struct->fd; |
---|
174 | 189 | int response = response_struct->response; |
---|
175 | 190 | |
---|
.. | .. |
---|
191 | 206 | if (fd < 0) |
---|
192 | 207 | return -EINVAL; |
---|
193 | 208 | |
---|
194 | | - if ((response & FAN_AUDIT) && !group->fanotify_data.audit) |
---|
| 209 | + if ((response & FAN_AUDIT) && !FAN_GROUP_FLAG(group, FAN_ENABLE_AUDIT)) |
---|
195 | 210 | return -EINVAL; |
---|
196 | 211 | |
---|
197 | | - event = dequeue_event(group, fd); |
---|
198 | | - if (!event) |
---|
199 | | - return -ENOENT; |
---|
| 212 | + spin_lock(&group->notification_lock); |
---|
| 213 | + list_for_each_entry(event, &group->fanotify_data.access_list, |
---|
| 214 | + fae.fse.list) { |
---|
| 215 | + if (event->fd != fd) |
---|
| 216 | + continue; |
---|
200 | 217 | |
---|
201 | | - event->response = response; |
---|
202 | | - wake_up(&group->fanotify_data.access_waitq); |
---|
| 218 | + list_del_init(&event->fae.fse.list); |
---|
| 219 | + finish_permission_event(group, event, response); |
---|
| 220 | + wake_up(&group->fanotify_data.access_waitq); |
---|
| 221 | + return 0; |
---|
| 222 | + } |
---|
| 223 | + spin_unlock(&group->notification_lock); |
---|
203 | 224 | |
---|
204 | | - return 0; |
---|
| 225 | + return -ENOENT; |
---|
| 226 | +} |
---|
| 227 | + |
---|
| 228 | +static int copy_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, |
---|
| 229 | + int info_type, const char *name, size_t name_len, |
---|
| 230 | + char __user *buf, size_t count) |
---|
| 231 | +{ |
---|
| 232 | + struct fanotify_event_info_fid info = { }; |
---|
| 233 | + struct file_handle handle = { }; |
---|
| 234 | + unsigned char bounce[FANOTIFY_INLINE_FH_LEN], *fh_buf; |
---|
| 235 | + size_t fh_len = fh ? fh->len : 0; |
---|
| 236 | + size_t info_len = fanotify_fid_info_len(fh_len, name_len); |
---|
| 237 | + size_t len = info_len; |
---|
| 238 | + |
---|
| 239 | + pr_debug("%s: fh_len=%zu name_len=%zu, info_len=%zu, count=%zu\n", |
---|
| 240 | + __func__, fh_len, name_len, info_len, count); |
---|
| 241 | + |
---|
| 242 | + if (!fh_len) |
---|
| 243 | + return 0; |
---|
| 244 | + |
---|
| 245 | + if (WARN_ON_ONCE(len < sizeof(info) || len > count)) |
---|
| 246 | + return -EFAULT; |
---|
| 247 | + |
---|
| 248 | + /* |
---|
| 249 | + * Copy event info fid header followed by variable sized file handle |
---|
| 250 | + * and optionally followed by variable sized filename. |
---|
| 251 | + */ |
---|
| 252 | + switch (info_type) { |
---|
| 253 | + case FAN_EVENT_INFO_TYPE_FID: |
---|
| 254 | + case FAN_EVENT_INFO_TYPE_DFID: |
---|
| 255 | + if (WARN_ON_ONCE(name_len)) |
---|
| 256 | + return -EFAULT; |
---|
| 257 | + break; |
---|
| 258 | + case FAN_EVENT_INFO_TYPE_DFID_NAME: |
---|
| 259 | + if (WARN_ON_ONCE(!name || !name_len)) |
---|
| 260 | + return -EFAULT; |
---|
| 261 | + break; |
---|
| 262 | + default: |
---|
| 263 | + return -EFAULT; |
---|
| 264 | + } |
---|
| 265 | + |
---|
| 266 | + info.hdr.info_type = info_type; |
---|
| 267 | + info.hdr.len = len; |
---|
| 268 | + info.fsid = *fsid; |
---|
| 269 | + if (copy_to_user(buf, &info, sizeof(info))) |
---|
| 270 | + return -EFAULT; |
---|
| 271 | + |
---|
| 272 | + buf += sizeof(info); |
---|
| 273 | + len -= sizeof(info); |
---|
| 274 | + if (WARN_ON_ONCE(len < sizeof(handle))) |
---|
| 275 | + return -EFAULT; |
---|
| 276 | + |
---|
| 277 | + handle.handle_type = fh->type; |
---|
| 278 | + handle.handle_bytes = fh_len; |
---|
| 279 | + if (copy_to_user(buf, &handle, sizeof(handle))) |
---|
| 280 | + return -EFAULT; |
---|
| 281 | + |
---|
| 282 | + buf += sizeof(handle); |
---|
| 283 | + len -= sizeof(handle); |
---|
| 284 | + if (WARN_ON_ONCE(len < fh_len)) |
---|
| 285 | + return -EFAULT; |
---|
| 286 | + |
---|
| 287 | + /* |
---|
| 288 | + * For an inline fh and inline file name, copy through stack to exclude |
---|
| 289 | + * the copy from usercopy hardening protections. |
---|
| 290 | + */ |
---|
| 291 | + fh_buf = fanotify_fh_buf(fh); |
---|
| 292 | + if (fh_len <= FANOTIFY_INLINE_FH_LEN) { |
---|
| 293 | + memcpy(bounce, fh_buf, fh_len); |
---|
| 294 | + fh_buf = bounce; |
---|
| 295 | + } |
---|
| 296 | + if (copy_to_user(buf, fh_buf, fh_len)) |
---|
| 297 | + return -EFAULT; |
---|
| 298 | + |
---|
| 299 | + buf += fh_len; |
---|
| 300 | + len -= fh_len; |
---|
| 301 | + |
---|
| 302 | + if (name_len) { |
---|
| 303 | + /* Copy the filename with terminating null */ |
---|
| 304 | + name_len++; |
---|
| 305 | + if (WARN_ON_ONCE(len < name_len)) |
---|
| 306 | + return -EFAULT; |
---|
| 307 | + |
---|
| 308 | + if (copy_to_user(buf, name, name_len)) |
---|
| 309 | + return -EFAULT; |
---|
| 310 | + |
---|
| 311 | + buf += name_len; |
---|
| 312 | + len -= name_len; |
---|
| 313 | + } |
---|
| 314 | + |
---|
| 315 | + /* Pad with 0's */ |
---|
| 316 | + WARN_ON_ONCE(len < 0 || len >= FANOTIFY_EVENT_ALIGN); |
---|
| 317 | + if (len > 0 && clear_user(buf, len)) |
---|
| 318 | + return -EFAULT; |
---|
| 319 | + |
---|
| 320 | + return info_len; |
---|
205 | 321 | } |
---|
206 | 322 | |
---|
207 | 323 | static ssize_t copy_event_to_user(struct fsnotify_group *group, |
---|
208 | | - struct fsnotify_event *event, |
---|
209 | | - char __user *buf) |
---|
| 324 | + struct fanotify_event *event, |
---|
| 325 | + char __user *buf, size_t count) |
---|
210 | 326 | { |
---|
211 | | - struct fanotify_event_metadata fanotify_event_metadata; |
---|
212 | | - struct file *f; |
---|
213 | | - int fd, ret; |
---|
| 327 | + struct fanotify_event_metadata metadata; |
---|
| 328 | + struct path *path = fanotify_event_path(event); |
---|
| 329 | + struct fanotify_info *info = fanotify_event_info(event); |
---|
| 330 | + unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); |
---|
| 331 | + struct file *f = NULL; |
---|
| 332 | + int ret, fd = FAN_NOFD; |
---|
| 333 | + int info_type = 0; |
---|
214 | 334 | |
---|
215 | 335 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); |
---|
216 | 336 | |
---|
217 | | - ret = fill_event_metadata(group, &fanotify_event_metadata, event, &f); |
---|
218 | | - if (ret < 0) |
---|
219 | | - return ret; |
---|
| 337 | + metadata.event_len = FAN_EVENT_METADATA_LEN + |
---|
| 338 | + fanotify_event_info_len(fid_mode, event); |
---|
| 339 | + metadata.metadata_len = FAN_EVENT_METADATA_LEN; |
---|
| 340 | + metadata.vers = FANOTIFY_METADATA_VERSION; |
---|
| 341 | + metadata.reserved = 0; |
---|
| 342 | + metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS; |
---|
| 343 | + metadata.pid = pid_vnr(event->pid); |
---|
220 | 344 | |
---|
221 | | - fd = fanotify_event_metadata.fd; |
---|
| 345 | + if (path && path->mnt && path->dentry) { |
---|
| 346 | + fd = create_fd(group, path, &f); |
---|
| 347 | + if (fd < 0) |
---|
| 348 | + return fd; |
---|
| 349 | + } |
---|
| 350 | + metadata.fd = fd; |
---|
| 351 | + |
---|
222 | 352 | ret = -EFAULT; |
---|
223 | | - if (copy_to_user(buf, &fanotify_event_metadata, |
---|
224 | | - fanotify_event_metadata.event_len)) |
---|
| 353 | + /* |
---|
| 354 | + * Sanity check copy size in case get_one_event() and |
---|
| 355 | + * event_len sizes ever get out of sync. |
---|
| 356 | + */ |
---|
| 357 | + if (WARN_ON_ONCE(metadata.event_len > count)) |
---|
225 | 358 | goto out_close_fd; |
---|
226 | 359 | |
---|
227 | | - if (fanotify_is_perm_event(event->mask)) |
---|
228 | | - FANOTIFY_PE(event)->fd = fd; |
---|
| 360 | + if (copy_to_user(buf, &metadata, FAN_EVENT_METADATA_LEN)) |
---|
| 361 | + goto out_close_fd; |
---|
229 | 362 | |
---|
230 | | - if (fd != FAN_NOFD) |
---|
| 363 | + buf += FAN_EVENT_METADATA_LEN; |
---|
| 364 | + count -= FAN_EVENT_METADATA_LEN; |
---|
| 365 | + |
---|
| 366 | + if (fanotify_is_perm_event(event->mask)) |
---|
| 367 | + FANOTIFY_PERM(event)->fd = fd; |
---|
| 368 | + |
---|
| 369 | + /* Event info records order is: dir fid + name, child fid */ |
---|
| 370 | + if (fanotify_event_dir_fh_len(event)) { |
---|
| 371 | + info_type = info->name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME : |
---|
| 372 | + FAN_EVENT_INFO_TYPE_DFID; |
---|
| 373 | + ret = copy_info_to_user(fanotify_event_fsid(event), |
---|
| 374 | + fanotify_info_dir_fh(info), |
---|
| 375 | + info_type, fanotify_info_name(info), |
---|
| 376 | + info->name_len, buf, count); |
---|
| 377 | + if (ret < 0) |
---|
| 378 | + goto out_close_fd; |
---|
| 379 | + |
---|
| 380 | + buf += ret; |
---|
| 381 | + count -= ret; |
---|
| 382 | + } |
---|
| 383 | + |
---|
| 384 | + if (fanotify_event_object_fh_len(event)) { |
---|
| 385 | + const char *dot = NULL; |
---|
| 386 | + int dot_len = 0; |
---|
| 387 | + |
---|
| 388 | + if (fid_mode == FAN_REPORT_FID || info_type) { |
---|
| 389 | + /* |
---|
| 390 | + * With only group flag FAN_REPORT_FID only type FID is |
---|
| 391 | + * reported. Second info record type is always FID. |
---|
| 392 | + */ |
---|
| 393 | + info_type = FAN_EVENT_INFO_TYPE_FID; |
---|
| 394 | + } else if ((fid_mode & FAN_REPORT_NAME) && |
---|
| 395 | + (event->mask & FAN_ONDIR)) { |
---|
| 396 | + /* |
---|
| 397 | + * With group flag FAN_REPORT_NAME, if name was not |
---|
| 398 | + * recorded in an event on a directory, report the |
---|
| 399 | + * name "." with info type DFID_NAME. |
---|
| 400 | + */ |
---|
| 401 | + info_type = FAN_EVENT_INFO_TYPE_DFID_NAME; |
---|
| 402 | + dot = "."; |
---|
| 403 | + dot_len = 1; |
---|
| 404 | + } else if ((event->mask & ALL_FSNOTIFY_DIRENT_EVENTS) || |
---|
| 405 | + (event->mask & FAN_ONDIR)) { |
---|
| 406 | + /* |
---|
| 407 | + * With group flag FAN_REPORT_DIR_FID, a single info |
---|
| 408 | + * record has type DFID for directory entry modification |
---|
| 409 | + * event and for event on a directory. |
---|
| 410 | + */ |
---|
| 411 | + info_type = FAN_EVENT_INFO_TYPE_DFID; |
---|
| 412 | + } else { |
---|
| 413 | + /* |
---|
| 414 | + * With group flags FAN_REPORT_DIR_FID|FAN_REPORT_FID, |
---|
| 415 | + * a single info record has type FID for event on a |
---|
| 416 | + * non-directory, when there is no directory to report. |
---|
| 417 | + * For example, on FAN_DELETE_SELF event. |
---|
| 418 | + */ |
---|
| 419 | + info_type = FAN_EVENT_INFO_TYPE_FID; |
---|
| 420 | + } |
---|
| 421 | + |
---|
| 422 | + ret = copy_info_to_user(fanotify_event_fsid(event), |
---|
| 423 | + fanotify_event_object_fh(event), |
---|
| 424 | + info_type, dot, dot_len, buf, count); |
---|
| 425 | + if (ret < 0) |
---|
| 426 | + goto out_close_fd; |
---|
| 427 | + |
---|
| 428 | + buf += ret; |
---|
| 429 | + count -= ret; |
---|
| 430 | + } |
---|
| 431 | + |
---|
| 432 | + if (f) |
---|
231 | 433 | fd_install(fd, f); |
---|
232 | | - return fanotify_event_metadata.event_len; |
---|
| 434 | + |
---|
| 435 | + return metadata.event_len; |
---|
233 | 436 | |
---|
234 | 437 | out_close_fd: |
---|
235 | 438 | if (fd != FAN_NOFD) { |
---|
.. | .. |
---|
258 | 461 | size_t count, loff_t *pos) |
---|
259 | 462 | { |
---|
260 | 463 | struct fsnotify_group *group; |
---|
261 | | - struct fsnotify_event *kevent; |
---|
| 464 | + struct fanotify_event *event; |
---|
262 | 465 | char __user *start; |
---|
263 | 466 | int ret; |
---|
264 | 467 | DEFINE_WAIT_FUNC(wait, woken_wake_function); |
---|
.. | .. |
---|
270 | 473 | |
---|
271 | 474 | add_wait_queue(&group->notification_waitq, &wait); |
---|
272 | 475 | while (1) { |
---|
273 | | - spin_lock(&group->notification_lock); |
---|
274 | | - kevent = get_one_event(group, count); |
---|
275 | | - spin_unlock(&group->notification_lock); |
---|
276 | | - |
---|
277 | | - if (IS_ERR(kevent)) { |
---|
278 | | - ret = PTR_ERR(kevent); |
---|
| 476 | + /* |
---|
| 477 | + * User can supply arbitrarily large buffer. Avoid softlockups |
---|
| 478 | + * in case there are lots of available events. |
---|
| 479 | + */ |
---|
| 480 | + cond_resched(); |
---|
| 481 | + event = get_one_event(group, count); |
---|
| 482 | + if (IS_ERR(event)) { |
---|
| 483 | + ret = PTR_ERR(event); |
---|
279 | 484 | break; |
---|
280 | 485 | } |
---|
281 | 486 | |
---|
282 | | - if (!kevent) { |
---|
| 487 | + if (!event) { |
---|
283 | 488 | ret = -EAGAIN; |
---|
284 | 489 | if (file->f_flags & O_NONBLOCK) |
---|
285 | 490 | break; |
---|
.. | .. |
---|
295 | 500 | continue; |
---|
296 | 501 | } |
---|
297 | 502 | |
---|
298 | | - ret = copy_event_to_user(group, kevent, buf); |
---|
| 503 | + ret = copy_event_to_user(group, event, buf, count); |
---|
299 | 504 | if (unlikely(ret == -EOPENSTALE)) { |
---|
300 | 505 | /* |
---|
301 | 506 | * We cannot report events with stale fd so drop it. |
---|
.. | .. |
---|
310 | 515 | * Permission events get queued to wait for response. Other |
---|
311 | 516 | * events can be destroyed now. |
---|
312 | 517 | */ |
---|
313 | | - if (!fanotify_is_perm_event(kevent->mask)) { |
---|
314 | | - fsnotify_destroy_event(group, kevent); |
---|
| 518 | + if (!fanotify_is_perm_event(event->mask)) { |
---|
| 519 | + fsnotify_destroy_event(group, &event->fse); |
---|
315 | 520 | } else { |
---|
316 | 521 | if (ret <= 0) { |
---|
317 | | - FANOTIFY_PE(kevent)->response = FAN_DENY; |
---|
| 522 | + spin_lock(&group->notification_lock); |
---|
| 523 | + finish_permission_event(group, |
---|
| 524 | + FANOTIFY_PERM(event), FAN_DENY); |
---|
318 | 525 | wake_up(&group->fanotify_data.access_waitq); |
---|
319 | 526 | } else { |
---|
320 | 527 | spin_lock(&group->notification_lock); |
---|
321 | | - list_add_tail(&kevent->list, |
---|
| 528 | + list_add_tail(&event->fse.list, |
---|
322 | 529 | &group->fanotify_data.access_list); |
---|
323 | 530 | spin_unlock(&group->notification_lock); |
---|
324 | 531 | } |
---|
.. | .. |
---|
346 | 553 | |
---|
347 | 554 | group = file->private_data; |
---|
348 | 555 | |
---|
349 | | - if (count > sizeof(response)) |
---|
350 | | - count = sizeof(response); |
---|
| 556 | + if (count < sizeof(response)) |
---|
| 557 | + return -EINVAL; |
---|
| 558 | + |
---|
| 559 | + count = sizeof(response); |
---|
351 | 560 | |
---|
352 | 561 | pr_debug("%s: group=%p count=%zu\n", __func__, group, count); |
---|
353 | 562 | |
---|
.. | .. |
---|
364 | 573 | static int fanotify_release(struct inode *ignored, struct file *file) |
---|
365 | 574 | { |
---|
366 | 575 | struct fsnotify_group *group = file->private_data; |
---|
367 | | - struct fanotify_perm_event_info *event, *next; |
---|
368 | | - struct fsnotify_event *fsn_event; |
---|
369 | 576 | |
---|
370 | 577 | /* |
---|
371 | 578 | * Stop new events from arriving in the notification queue. since |
---|
.. | .. |
---|
379 | 586 | * and simulate reply from userspace. |
---|
380 | 587 | */ |
---|
381 | 588 | spin_lock(&group->notification_lock); |
---|
382 | | - list_for_each_entry_safe(event, next, &group->fanotify_data.access_list, |
---|
383 | | - fae.fse.list) { |
---|
384 | | - pr_debug("%s: found group=%p event=%p\n", __func__, group, |
---|
385 | | - event); |
---|
| 589 | + while (!list_empty(&group->fanotify_data.access_list)) { |
---|
| 590 | + struct fanotify_perm_event *event; |
---|
386 | 591 | |
---|
| 592 | + event = list_first_entry(&group->fanotify_data.access_list, |
---|
| 593 | + struct fanotify_perm_event, fae.fse.list); |
---|
387 | 594 | list_del_init(&event->fae.fse.list); |
---|
388 | | - event->response = FAN_ALLOW; |
---|
| 595 | + finish_permission_event(group, event, FAN_ALLOW); |
---|
| 596 | + spin_lock(&group->notification_lock); |
---|
389 | 597 | } |
---|
390 | 598 | |
---|
391 | 599 | /* |
---|
.. | .. |
---|
394 | 602 | * response is consumed and fanotify_get_response() returns. |
---|
395 | 603 | */ |
---|
396 | 604 | while (!fsnotify_notify_queue_is_empty(group)) { |
---|
397 | | - fsn_event = fsnotify_remove_first_event(group); |
---|
398 | | - if (!(fsn_event->mask & FAN_ALL_PERM_EVENTS)) { |
---|
| 605 | + struct fanotify_event *event; |
---|
| 606 | + |
---|
| 607 | + event = FANOTIFY_E(fsnotify_remove_first_event(group)); |
---|
| 608 | + if (!(event->mask & FANOTIFY_PERM_EVENTS)) { |
---|
399 | 609 | spin_unlock(&group->notification_lock); |
---|
400 | | - fsnotify_destroy_event(group, fsn_event); |
---|
401 | | - spin_lock(&group->notification_lock); |
---|
| 610 | + fsnotify_destroy_event(group, &event->fse); |
---|
402 | 611 | } else { |
---|
403 | | - FANOTIFY_PE(fsn_event)->response = FAN_ALLOW; |
---|
| 612 | + finish_permission_event(group, FANOTIFY_PERM(event), |
---|
| 613 | + FAN_ALLOW); |
---|
404 | 614 | } |
---|
| 615 | + spin_lock(&group->notification_lock); |
---|
405 | 616 | } |
---|
406 | 617 | spin_unlock(&group->notification_lock); |
---|
407 | 618 | |
---|
.. | .. |
---|
447 | 658 | .fasync = NULL, |
---|
448 | 659 | .release = fanotify_release, |
---|
449 | 660 | .unlocked_ioctl = fanotify_ioctl, |
---|
450 | | - .compat_ioctl = fanotify_ioctl, |
---|
| 661 | + .compat_ioctl = compat_ptr_ioctl, |
---|
451 | 662 | .llseek = noop_llseek, |
---|
452 | 663 | }; |
---|
453 | 664 | |
---|
454 | 665 | static int fanotify_find_path(int dfd, const char __user *filename, |
---|
455 | | - struct path *path, unsigned int flags) |
---|
| 666 | + struct path *path, unsigned int flags, __u64 mask, |
---|
| 667 | + unsigned int obj_type) |
---|
456 | 668 | { |
---|
457 | 669 | int ret; |
---|
458 | 670 | |
---|
.. | .. |
---|
490 | 702 | } |
---|
491 | 703 | |
---|
492 | 704 | /* you can only watch an inode if you have read permissions on it */ |
---|
493 | | - ret = inode_permission2(path->mnt, path->dentry->d_inode, MAY_READ); |
---|
| 705 | + ret = inode_permission(path->dentry->d_inode, MAY_READ); |
---|
| 706 | + if (ret) { |
---|
| 707 | + path_put(path); |
---|
| 708 | + goto out; |
---|
| 709 | + } |
---|
| 710 | + |
---|
| 711 | + ret = security_path_notify(path, mask, obj_type); |
---|
494 | 712 | if (ret) |
---|
495 | 713 | path_put(path); |
---|
| 714 | + |
---|
496 | 715 | out: |
---|
497 | 716 | return ret; |
---|
498 | 717 | } |
---|
499 | 718 | |
---|
500 | 719 | static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, |
---|
501 | | - __u32 mask, |
---|
502 | | - unsigned int flags, |
---|
503 | | - int *destroy) |
---|
| 720 | + __u32 mask, unsigned int flags, |
---|
| 721 | + __u32 umask, int *destroy) |
---|
504 | 722 | { |
---|
505 | 723 | __u32 oldmask = 0; |
---|
506 | 724 | |
---|
| 725 | + /* umask bits cannot be removed by user */ |
---|
| 726 | + mask &= ~umask; |
---|
507 | 727 | spin_lock(&fsn_mark->lock); |
---|
508 | 728 | if (!(flags & FAN_MARK_IGNORED_MASK)) { |
---|
509 | | - __u32 tmask = fsn_mark->mask & ~mask; |
---|
510 | | - |
---|
511 | | - if (flags & FAN_MARK_ONDIR) |
---|
512 | | - tmask &= ~FAN_ONDIR; |
---|
513 | | - |
---|
514 | 729 | oldmask = fsn_mark->mask; |
---|
515 | | - fsn_mark->mask = tmask; |
---|
| 730 | + fsn_mark->mask &= ~mask; |
---|
516 | 731 | } else { |
---|
517 | | - __u32 tmask = fsn_mark->ignored_mask & ~mask; |
---|
518 | | - if (flags & FAN_MARK_ONDIR) |
---|
519 | | - tmask &= ~FAN_ONDIR; |
---|
520 | | - fsn_mark->ignored_mask = tmask; |
---|
| 732 | + fsn_mark->ignored_mask &= ~mask; |
---|
521 | 733 | } |
---|
522 | | - *destroy = !(fsn_mark->mask | fsn_mark->ignored_mask); |
---|
| 734 | + /* |
---|
| 735 | + * We need to keep the mark around even if remaining mask cannot |
---|
| 736 | + * result in any events (e.g. mask == FAN_ONDIR) to support incremenal |
---|
| 737 | + * changes to the mask. |
---|
| 738 | + * Destroy mark when only umask bits remain. |
---|
| 739 | + */ |
---|
| 740 | + *destroy = !((fsn_mark->mask | fsn_mark->ignored_mask) & ~umask); |
---|
523 | 741 | spin_unlock(&fsn_mark->lock); |
---|
524 | 742 | |
---|
525 | 743 | return mask & oldmask; |
---|
.. | .. |
---|
527 | 745 | |
---|
528 | 746 | static int fanotify_remove_mark(struct fsnotify_group *group, |
---|
529 | 747 | fsnotify_connp_t *connp, __u32 mask, |
---|
530 | | - unsigned int flags) |
---|
| 748 | + unsigned int flags, __u32 umask) |
---|
531 | 749 | { |
---|
532 | 750 | struct fsnotify_mark *fsn_mark = NULL; |
---|
533 | 751 | __u32 removed; |
---|
.. | .. |
---|
541 | 759 | } |
---|
542 | 760 | |
---|
543 | 761 | removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags, |
---|
544 | | - &destroy_mark); |
---|
| 762 | + umask, &destroy_mark); |
---|
545 | 763 | if (removed & fsnotify_conn_mask(fsn_mark->connector)) |
---|
546 | 764 | fsnotify_recalc_mask(fsn_mark->connector); |
---|
547 | 765 | if (destroy_mark) |
---|
.. | .. |
---|
557 | 775 | |
---|
558 | 776 | static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group, |
---|
559 | 777 | struct vfsmount *mnt, __u32 mask, |
---|
560 | | - unsigned int flags) |
---|
| 778 | + unsigned int flags, __u32 umask) |
---|
561 | 779 | { |
---|
562 | 780 | return fanotify_remove_mark(group, &real_mount(mnt)->mnt_fsnotify_marks, |
---|
563 | | - mask, flags); |
---|
| 781 | + mask, flags, umask); |
---|
| 782 | +} |
---|
| 783 | + |
---|
| 784 | +static int fanotify_remove_sb_mark(struct fsnotify_group *group, |
---|
| 785 | + struct super_block *sb, __u32 mask, |
---|
| 786 | + unsigned int flags, __u32 umask) |
---|
| 787 | +{ |
---|
| 788 | + return fanotify_remove_mark(group, &sb->s_fsnotify_marks, mask, |
---|
| 789 | + flags, umask); |
---|
564 | 790 | } |
---|
565 | 791 | |
---|
566 | 792 | static int fanotify_remove_inode_mark(struct fsnotify_group *group, |
---|
567 | 793 | struct inode *inode, __u32 mask, |
---|
568 | | - unsigned int flags) |
---|
| 794 | + unsigned int flags, __u32 umask) |
---|
569 | 795 | { |
---|
570 | 796 | return fanotify_remove_mark(group, &inode->i_fsnotify_marks, mask, |
---|
571 | | - flags); |
---|
| 797 | + flags, umask); |
---|
572 | 798 | } |
---|
573 | 799 | |
---|
574 | 800 | static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, |
---|
.. | .. |
---|
579 | 805 | |
---|
580 | 806 | spin_lock(&fsn_mark->lock); |
---|
581 | 807 | if (!(flags & FAN_MARK_IGNORED_MASK)) { |
---|
582 | | - __u32 tmask = fsn_mark->mask | mask; |
---|
583 | | - |
---|
584 | | - if (flags & FAN_MARK_ONDIR) |
---|
585 | | - tmask |= FAN_ONDIR; |
---|
586 | | - |
---|
587 | 808 | oldmask = fsn_mark->mask; |
---|
588 | | - fsn_mark->mask = tmask; |
---|
| 809 | + fsn_mark->mask |= mask; |
---|
589 | 810 | } else { |
---|
590 | | - __u32 tmask = fsn_mark->ignored_mask | mask; |
---|
591 | | - if (flags & FAN_MARK_ONDIR) |
---|
592 | | - tmask |= FAN_ONDIR; |
---|
593 | | - |
---|
594 | | - fsn_mark->ignored_mask = tmask; |
---|
| 811 | + fsn_mark->ignored_mask |= mask; |
---|
595 | 812 | if (flags & FAN_MARK_IGNORED_SURV_MODIFY) |
---|
596 | 813 | fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY; |
---|
597 | 814 | } |
---|
.. | .. |
---|
602 | 819 | |
---|
603 | 820 | static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, |
---|
604 | 821 | fsnotify_connp_t *connp, |
---|
605 | | - unsigned int type) |
---|
| 822 | + unsigned int type, |
---|
| 823 | + __kernel_fsid_t *fsid) |
---|
606 | 824 | { |
---|
607 | 825 | struct fsnotify_mark *mark; |
---|
608 | 826 | int ret; |
---|
.. | .. |
---|
615 | 833 | return ERR_PTR(-ENOMEM); |
---|
616 | 834 | |
---|
617 | 835 | fsnotify_init_mark(mark, group); |
---|
618 | | - ret = fsnotify_add_mark_locked(mark, connp, type, 0); |
---|
| 836 | + ret = fsnotify_add_mark_locked(mark, connp, type, 0, fsid); |
---|
619 | 837 | if (ret) { |
---|
620 | 838 | fsnotify_put_mark(mark); |
---|
621 | 839 | return ERR_PTR(ret); |
---|
.. | .. |
---|
627 | 845 | |
---|
628 | 846 | static int fanotify_add_mark(struct fsnotify_group *group, |
---|
629 | 847 | fsnotify_connp_t *connp, unsigned int type, |
---|
630 | | - __u32 mask, unsigned int flags) |
---|
| 848 | + __u32 mask, unsigned int flags, |
---|
| 849 | + __kernel_fsid_t *fsid) |
---|
631 | 850 | { |
---|
632 | 851 | struct fsnotify_mark *fsn_mark; |
---|
633 | 852 | __u32 added; |
---|
.. | .. |
---|
635 | 854 | mutex_lock(&group->mark_mutex); |
---|
636 | 855 | fsn_mark = fsnotify_find_mark(connp, group); |
---|
637 | 856 | if (!fsn_mark) { |
---|
638 | | - fsn_mark = fanotify_add_new_mark(group, connp, type); |
---|
| 857 | + fsn_mark = fanotify_add_new_mark(group, connp, type, fsid); |
---|
639 | 858 | if (IS_ERR(fsn_mark)) { |
---|
640 | 859 | mutex_unlock(&group->mark_mutex); |
---|
641 | 860 | return PTR_ERR(fsn_mark); |
---|
.. | .. |
---|
652 | 871 | |
---|
653 | 872 | static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, |
---|
654 | 873 | struct vfsmount *mnt, __u32 mask, |
---|
655 | | - unsigned int flags) |
---|
| 874 | + unsigned int flags, __kernel_fsid_t *fsid) |
---|
656 | 875 | { |
---|
657 | 876 | return fanotify_add_mark(group, &real_mount(mnt)->mnt_fsnotify_marks, |
---|
658 | | - FSNOTIFY_OBJ_TYPE_VFSMOUNT, mask, flags); |
---|
| 877 | + FSNOTIFY_OBJ_TYPE_VFSMOUNT, mask, flags, fsid); |
---|
| 878 | +} |
---|
| 879 | + |
---|
| 880 | +static int fanotify_add_sb_mark(struct fsnotify_group *group, |
---|
| 881 | + struct super_block *sb, __u32 mask, |
---|
| 882 | + unsigned int flags, __kernel_fsid_t *fsid) |
---|
| 883 | +{ |
---|
| 884 | + return fanotify_add_mark(group, &sb->s_fsnotify_marks, |
---|
| 885 | + FSNOTIFY_OBJ_TYPE_SB, mask, flags, fsid); |
---|
659 | 886 | } |
---|
660 | 887 | |
---|
661 | 888 | static int fanotify_add_inode_mark(struct fsnotify_group *group, |
---|
662 | 889 | struct inode *inode, __u32 mask, |
---|
663 | | - unsigned int flags) |
---|
| 890 | + unsigned int flags, __kernel_fsid_t *fsid) |
---|
664 | 891 | { |
---|
665 | 892 | pr_debug("%s: group=%p inode=%p\n", __func__, group, inode); |
---|
666 | 893 | |
---|
.. | .. |
---|
671 | 898 | */ |
---|
672 | 899 | if ((flags & FAN_MARK_IGNORED_MASK) && |
---|
673 | 900 | !(flags & FAN_MARK_IGNORED_SURV_MODIFY) && |
---|
674 | | - (atomic_read(&inode->i_writecount) > 0)) |
---|
| 901 | + inode_is_open_for_write(inode)) |
---|
675 | 902 | return 0; |
---|
676 | 903 | |
---|
677 | 904 | return fanotify_add_mark(group, &inode->i_fsnotify_marks, |
---|
678 | | - FSNOTIFY_OBJ_TYPE_INODE, mask, flags); |
---|
| 905 | + FSNOTIFY_OBJ_TYPE_INODE, mask, flags, fsid); |
---|
| 906 | +} |
---|
| 907 | + |
---|
| 908 | +static struct fsnotify_event *fanotify_alloc_overflow_event(void) |
---|
| 909 | +{ |
---|
| 910 | + struct fanotify_event *oevent; |
---|
| 911 | + |
---|
| 912 | + oevent = kmalloc(sizeof(*oevent), GFP_KERNEL_ACCOUNT); |
---|
| 913 | + if (!oevent) |
---|
| 914 | + return NULL; |
---|
| 915 | + |
---|
| 916 | + fanotify_init_event(oevent, 0, FS_Q_OVERFLOW); |
---|
| 917 | + oevent->type = FANOTIFY_EVENT_TYPE_OVERFLOW; |
---|
| 918 | + |
---|
| 919 | + return &oevent->fse; |
---|
679 | 920 | } |
---|
680 | 921 | |
---|
681 | 922 | /* fanotify syscalls */ |
---|
.. | .. |
---|
684 | 925 | struct fsnotify_group *group; |
---|
685 | 926 | int f_flags, fd; |
---|
686 | 927 | struct user_struct *user; |
---|
687 | | - struct fanotify_event_info *oevent; |
---|
| 928 | + unsigned int fid_mode = flags & FANOTIFY_FID_BITS; |
---|
| 929 | + unsigned int class = flags & FANOTIFY_CLASS_BITS; |
---|
688 | 930 | |
---|
689 | | - pr_debug("%s: flags=%d event_f_flags=%d\n", |
---|
690 | | - __func__, flags, event_f_flags); |
---|
| 931 | + pr_debug("%s: flags=%x event_f_flags=%x\n", |
---|
| 932 | + __func__, flags, event_f_flags); |
---|
691 | 933 | |
---|
692 | 934 | if (!capable(CAP_SYS_ADMIN)) |
---|
693 | 935 | return -EPERM; |
---|
694 | 936 | |
---|
695 | 937 | #ifdef CONFIG_AUDITSYSCALL |
---|
696 | | - if (flags & ~(FAN_ALL_INIT_FLAGS | FAN_ENABLE_AUDIT)) |
---|
| 938 | + if (flags & ~(FANOTIFY_INIT_FLAGS | FAN_ENABLE_AUDIT)) |
---|
697 | 939 | #else |
---|
698 | | - if (flags & ~FAN_ALL_INIT_FLAGS) |
---|
| 940 | + if (flags & ~FANOTIFY_INIT_FLAGS) |
---|
699 | 941 | #endif |
---|
700 | 942 | return -EINVAL; |
---|
701 | 943 | |
---|
.. | .. |
---|
710 | 952 | default: |
---|
711 | 953 | return -EINVAL; |
---|
712 | 954 | } |
---|
| 955 | + |
---|
| 956 | + if (fid_mode && class != FAN_CLASS_NOTIF) |
---|
| 957 | + return -EINVAL; |
---|
| 958 | + |
---|
| 959 | + /* |
---|
| 960 | + * Child name is reported with parent fid so requires dir fid. |
---|
| 961 | + * We can report both child fid and dir fid with or without name. |
---|
| 962 | + */ |
---|
| 963 | + if ((fid_mode & FAN_REPORT_NAME) && !(fid_mode & FAN_REPORT_DIR_FID)) |
---|
| 964 | + return -EINVAL; |
---|
713 | 965 | |
---|
714 | 966 | user = get_current_user(); |
---|
715 | 967 | if (atomic_read(&user->fanotify_listeners) > FANOTIFY_DEFAULT_MAX_LISTENERS) { |
---|
.. | .. |
---|
731 | 983 | } |
---|
732 | 984 | |
---|
733 | 985 | group->fanotify_data.user = user; |
---|
| 986 | + group->fanotify_data.flags = flags; |
---|
734 | 987 | atomic_inc(&user->fanotify_listeners); |
---|
735 | 988 | group->memcg = get_mem_cgroup_from_mm(current->mm); |
---|
736 | 989 | |
---|
737 | | - oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL); |
---|
738 | | - if (unlikely(!oevent)) { |
---|
| 990 | + group->overflow_event = fanotify_alloc_overflow_event(); |
---|
| 991 | + if (unlikely(!group->overflow_event)) { |
---|
739 | 992 | fd = -ENOMEM; |
---|
740 | 993 | goto out_destroy_group; |
---|
741 | 994 | } |
---|
742 | | - group->overflow_event = &oevent->fse; |
---|
743 | 995 | |
---|
744 | 996 | if (force_o_largefile()) |
---|
745 | 997 | event_f_flags |= O_LARGEFILE; |
---|
746 | 998 | group->fanotify_data.f_flags = event_f_flags; |
---|
747 | 999 | init_waitqueue_head(&group->fanotify_data.access_waitq); |
---|
748 | 1000 | INIT_LIST_HEAD(&group->fanotify_data.access_list); |
---|
749 | | - switch (flags & FAN_ALL_CLASS_BITS) { |
---|
| 1001 | + switch (class) { |
---|
750 | 1002 | case FAN_CLASS_NOTIF: |
---|
751 | 1003 | group->priority = FS_PRIO_0; |
---|
752 | 1004 | break; |
---|
.. | .. |
---|
783 | 1035 | fd = -EPERM; |
---|
784 | 1036 | if (!capable(CAP_AUDIT_WRITE)) |
---|
785 | 1037 | goto out_destroy_group; |
---|
786 | | - group->fanotify_data.audit = true; |
---|
787 | 1038 | } |
---|
788 | 1039 | |
---|
789 | 1040 | fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags); |
---|
.. | .. |
---|
797 | 1048 | return fd; |
---|
798 | 1049 | } |
---|
799 | 1050 | |
---|
| 1051 | +/* Check if filesystem can encode a unique fid */ |
---|
| 1052 | +static int fanotify_test_fid(struct path *path, __kernel_fsid_t *fsid) |
---|
| 1053 | +{ |
---|
| 1054 | + __kernel_fsid_t root_fsid; |
---|
| 1055 | + int err; |
---|
| 1056 | + |
---|
| 1057 | + /* |
---|
| 1058 | + * Make sure path is not in filesystem with zero fsid (e.g. tmpfs). |
---|
| 1059 | + */ |
---|
| 1060 | + err = vfs_get_fsid(path->dentry, fsid); |
---|
| 1061 | + if (err) |
---|
| 1062 | + return err; |
---|
| 1063 | + |
---|
| 1064 | + if (!fsid->val[0] && !fsid->val[1]) |
---|
| 1065 | + return -ENODEV; |
---|
| 1066 | + |
---|
| 1067 | + /* |
---|
| 1068 | + * Make sure path is not inside a filesystem subvolume (e.g. btrfs) |
---|
| 1069 | + * which uses a different fsid than sb root. |
---|
| 1070 | + */ |
---|
| 1071 | + err = vfs_get_fsid(path->dentry->d_sb->s_root, &root_fsid); |
---|
| 1072 | + if (err) |
---|
| 1073 | + return err; |
---|
| 1074 | + |
---|
| 1075 | + if (root_fsid.val[0] != fsid->val[0] || |
---|
| 1076 | + root_fsid.val[1] != fsid->val[1]) |
---|
| 1077 | + return -EXDEV; |
---|
| 1078 | + |
---|
| 1079 | + /* |
---|
| 1080 | + * We need to make sure that the file system supports at least |
---|
| 1081 | + * encoding a file handle so user can use name_to_handle_at() to |
---|
| 1082 | + * compare fid returned with event to the file handle of watched |
---|
| 1083 | + * objects. However, name_to_handle_at() requires that the |
---|
| 1084 | + * filesystem also supports decoding file handles. |
---|
| 1085 | + */ |
---|
| 1086 | + if (!path->dentry->d_sb->s_export_op || |
---|
| 1087 | + !path->dentry->d_sb->s_export_op->fh_to_dentry) |
---|
| 1088 | + return -EOPNOTSUPP; |
---|
| 1089 | + |
---|
| 1090 | + return 0; |
---|
| 1091 | +} |
---|
| 1092 | + |
---|
| 1093 | +static int fanotify_events_supported(struct path *path, __u64 mask, |
---|
| 1094 | + unsigned int flags) |
---|
| 1095 | +{ |
---|
| 1096 | + unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; |
---|
| 1097 | + |
---|
| 1098 | + /* |
---|
| 1099 | + * Some filesystems such as 'proc' acquire unusual locks when opening |
---|
| 1100 | + * files. For them fanotify permission events have high chances of |
---|
| 1101 | + * deadlocking the system - open done when reporting fanotify event |
---|
| 1102 | + * blocks on this "unusual" lock while another process holding the lock |
---|
| 1103 | + * waits for fanotify permission event to be answered. Just disallow |
---|
| 1104 | + * permission events for such filesystems. |
---|
| 1105 | + */ |
---|
| 1106 | + if (mask & FANOTIFY_PERM_EVENTS && |
---|
| 1107 | + path->mnt->mnt_sb->s_type->fs_flags & FS_DISALLOW_NOTIFY_PERM) |
---|
| 1108 | + return -EINVAL; |
---|
| 1109 | + |
---|
| 1110 | + /* |
---|
| 1111 | + * mount and sb marks are not allowed on kernel internal pseudo fs, |
---|
| 1112 | + * like pipe_mnt, because that would subscribe to events on all the |
---|
| 1113 | + * anonynous pipes in the system. |
---|
| 1114 | + * |
---|
| 1115 | + * SB_NOUSER covers all of the internal pseudo fs whose objects are not |
---|
| 1116 | + * exposed to user's mount namespace, but there are other SB_KERNMOUNT |
---|
| 1117 | + * fs, like nsfs, debugfs, for which the value of allowing sb and mount |
---|
| 1118 | + * mark is questionable. For now we leave them alone. |
---|
| 1119 | + */ |
---|
| 1120 | + if (mark_type != FAN_MARK_INODE && |
---|
| 1121 | + path->mnt->mnt_sb->s_flags & SB_NOUSER) |
---|
| 1122 | + return -EINVAL; |
---|
| 1123 | + |
---|
| 1124 | + return 0; |
---|
| 1125 | +} |
---|
| 1126 | + |
---|
800 | 1127 | static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, |
---|
801 | 1128 | int dfd, const char __user *pathname) |
---|
802 | 1129 | { |
---|
.. | .. |
---|
805 | 1132 | struct fsnotify_group *group; |
---|
806 | 1133 | struct fd f; |
---|
807 | 1134 | struct path path; |
---|
808 | | - u32 valid_mask = FAN_ALL_EVENTS | FAN_EVENT_ON_CHILD; |
---|
| 1135 | + __kernel_fsid_t __fsid, *fsid = NULL; |
---|
| 1136 | + u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS; |
---|
| 1137 | + unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; |
---|
| 1138 | + bool ignored = flags & FAN_MARK_IGNORED_MASK; |
---|
| 1139 | + unsigned int obj_type, fid_mode; |
---|
| 1140 | + u32 umask = 0; |
---|
809 | 1141 | int ret; |
---|
810 | 1142 | |
---|
811 | 1143 | pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n", |
---|
.. | .. |
---|
815 | 1147 | if (mask & ((__u64)0xffffffff << 32)) |
---|
816 | 1148 | return -EINVAL; |
---|
817 | 1149 | |
---|
818 | | - if (flags & ~FAN_ALL_MARK_FLAGS) |
---|
| 1150 | + if (flags & ~FANOTIFY_MARK_FLAGS) |
---|
819 | 1151 | return -EINVAL; |
---|
| 1152 | + |
---|
| 1153 | + switch (mark_type) { |
---|
| 1154 | + case FAN_MARK_INODE: |
---|
| 1155 | + obj_type = FSNOTIFY_OBJ_TYPE_INODE; |
---|
| 1156 | + break; |
---|
| 1157 | + case FAN_MARK_MOUNT: |
---|
| 1158 | + obj_type = FSNOTIFY_OBJ_TYPE_VFSMOUNT; |
---|
| 1159 | + break; |
---|
| 1160 | + case FAN_MARK_FILESYSTEM: |
---|
| 1161 | + obj_type = FSNOTIFY_OBJ_TYPE_SB; |
---|
| 1162 | + break; |
---|
| 1163 | + default: |
---|
| 1164 | + return -EINVAL; |
---|
| 1165 | + } |
---|
| 1166 | + |
---|
820 | 1167 | switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) { |
---|
821 | | - case FAN_MARK_ADD: /* fallthrough */ |
---|
| 1168 | + case FAN_MARK_ADD: |
---|
822 | 1169 | case FAN_MARK_REMOVE: |
---|
823 | 1170 | if (!mask) |
---|
824 | 1171 | return -EINVAL; |
---|
825 | 1172 | break; |
---|
826 | 1173 | case FAN_MARK_FLUSH: |
---|
827 | | - if (flags & ~(FAN_MARK_MOUNT | FAN_MARK_FLUSH)) |
---|
| 1174 | + if (flags & ~(FANOTIFY_MARK_TYPE_BITS | FAN_MARK_FLUSH)) |
---|
828 | 1175 | return -EINVAL; |
---|
829 | 1176 | break; |
---|
830 | 1177 | default: |
---|
831 | 1178 | return -EINVAL; |
---|
832 | 1179 | } |
---|
833 | 1180 | |
---|
834 | | - if (mask & FAN_ONDIR) { |
---|
835 | | - flags |= FAN_MARK_ONDIR; |
---|
836 | | - mask &= ~FAN_ONDIR; |
---|
837 | | - } |
---|
838 | | - |
---|
839 | 1181 | if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS)) |
---|
840 | | - valid_mask |= FAN_ALL_PERM_EVENTS; |
---|
| 1182 | + valid_mask |= FANOTIFY_PERM_EVENTS; |
---|
841 | 1183 | |
---|
842 | 1184 | if (mask & ~valid_mask) |
---|
843 | 1185 | return -EINVAL; |
---|
| 1186 | + |
---|
| 1187 | + /* Event flags (ONDIR, ON_CHILD) are meaningless in ignored mask */ |
---|
| 1188 | + if (ignored) |
---|
| 1189 | + mask &= ~FANOTIFY_EVENT_FLAGS; |
---|
844 | 1190 | |
---|
845 | 1191 | f = fdget(fanotify_fd); |
---|
846 | 1192 | if (unlikely(!f.file)) |
---|
.. | .. |
---|
857 | 1203 | * allowed to set permissions events. |
---|
858 | 1204 | */ |
---|
859 | 1205 | ret = -EINVAL; |
---|
860 | | - if (mask & FAN_ALL_PERM_EVENTS && |
---|
| 1206 | + if (mask & FANOTIFY_PERM_EVENTS && |
---|
861 | 1207 | group->priority == FS_PRIO_0) |
---|
| 1208 | + goto fput_and_out; |
---|
| 1209 | + |
---|
| 1210 | + /* |
---|
| 1211 | + * Events with data type inode do not carry enough information to report |
---|
| 1212 | + * event->fd, so we do not allow setting a mask for inode events unless |
---|
| 1213 | + * group supports reporting fid. |
---|
| 1214 | + * inode events are not supported on a mount mark, because they do not |
---|
| 1215 | + * carry enough information (i.e. path) to be filtered by mount point. |
---|
| 1216 | + */ |
---|
| 1217 | + fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); |
---|
| 1218 | + if (mask & FANOTIFY_INODE_EVENTS && |
---|
| 1219 | + (!fid_mode || mark_type == FAN_MARK_MOUNT)) |
---|
862 | 1220 | goto fput_and_out; |
---|
863 | 1221 | |
---|
864 | 1222 | if (flags & FAN_MARK_FLUSH) { |
---|
865 | 1223 | ret = 0; |
---|
866 | | - if (flags & FAN_MARK_MOUNT) |
---|
| 1224 | + if (mark_type == FAN_MARK_MOUNT) |
---|
867 | 1225 | fsnotify_clear_vfsmount_marks_by_group(group); |
---|
| 1226 | + else if (mark_type == FAN_MARK_FILESYSTEM) |
---|
| 1227 | + fsnotify_clear_sb_marks_by_group(group); |
---|
868 | 1228 | else |
---|
869 | 1229 | fsnotify_clear_inode_marks_by_group(group); |
---|
870 | 1230 | goto fput_and_out; |
---|
871 | 1231 | } |
---|
872 | 1232 | |
---|
873 | | - ret = fanotify_find_path(dfd, pathname, &path, flags); |
---|
| 1233 | + ret = fanotify_find_path(dfd, pathname, &path, flags, |
---|
| 1234 | + (mask & ALL_FSNOTIFY_EVENTS), obj_type); |
---|
874 | 1235 | if (ret) |
---|
875 | 1236 | goto fput_and_out; |
---|
876 | 1237 | |
---|
| 1238 | + if (flags & FAN_MARK_ADD) { |
---|
| 1239 | + ret = fanotify_events_supported(&path, mask, flags); |
---|
| 1240 | + if (ret) |
---|
| 1241 | + goto path_put_and_out; |
---|
| 1242 | + } |
---|
| 1243 | + |
---|
| 1244 | + if (fid_mode) { |
---|
| 1245 | + ret = fanotify_test_fid(&path, &__fsid); |
---|
| 1246 | + if (ret) |
---|
| 1247 | + goto path_put_and_out; |
---|
| 1248 | + |
---|
| 1249 | + fsid = &__fsid; |
---|
| 1250 | + } |
---|
| 1251 | + |
---|
877 | 1252 | /* inode held in place by reference to path; group by fget on fd */ |
---|
878 | | - if (!(flags & FAN_MARK_MOUNT)) |
---|
| 1253 | + if (mark_type == FAN_MARK_INODE) |
---|
879 | 1254 | inode = path.dentry->d_inode; |
---|
880 | 1255 | else |
---|
881 | 1256 | mnt = path.mnt; |
---|
882 | 1257 | |
---|
| 1258 | + /* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */ |
---|
| 1259 | + if (mnt || !S_ISDIR(inode->i_mode)) { |
---|
| 1260 | + mask &= ~FAN_EVENT_ON_CHILD; |
---|
| 1261 | + umask = FAN_EVENT_ON_CHILD; |
---|
| 1262 | + /* |
---|
| 1263 | + * If group needs to report parent fid, register for getting |
---|
| 1264 | + * events with parent/name info for non-directory. |
---|
| 1265 | + */ |
---|
| 1266 | + if ((fid_mode & FAN_REPORT_DIR_FID) && |
---|
| 1267 | + (flags & FAN_MARK_ADD) && !ignored) |
---|
| 1268 | + mask |= FAN_EVENT_ON_CHILD; |
---|
| 1269 | + } |
---|
| 1270 | + |
---|
883 | 1271 | /* create/update an inode mark */ |
---|
884 | 1272 | switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) { |
---|
885 | 1273 | case FAN_MARK_ADD: |
---|
886 | | - if (flags & FAN_MARK_MOUNT) |
---|
887 | | - ret = fanotify_add_vfsmount_mark(group, mnt, mask, flags); |
---|
| 1274 | + if (mark_type == FAN_MARK_MOUNT) |
---|
| 1275 | + ret = fanotify_add_vfsmount_mark(group, mnt, mask, |
---|
| 1276 | + flags, fsid); |
---|
| 1277 | + else if (mark_type == FAN_MARK_FILESYSTEM) |
---|
| 1278 | + ret = fanotify_add_sb_mark(group, mnt->mnt_sb, mask, |
---|
| 1279 | + flags, fsid); |
---|
888 | 1280 | else |
---|
889 | | - ret = fanotify_add_inode_mark(group, inode, mask, flags); |
---|
| 1281 | + ret = fanotify_add_inode_mark(group, inode, mask, |
---|
| 1282 | + flags, fsid); |
---|
890 | 1283 | break; |
---|
891 | 1284 | case FAN_MARK_REMOVE: |
---|
892 | | - if (flags & FAN_MARK_MOUNT) |
---|
893 | | - ret = fanotify_remove_vfsmount_mark(group, mnt, mask, flags); |
---|
| 1285 | + if (mark_type == FAN_MARK_MOUNT) |
---|
| 1286 | + ret = fanotify_remove_vfsmount_mark(group, mnt, mask, |
---|
| 1287 | + flags, umask); |
---|
| 1288 | + else if (mark_type == FAN_MARK_FILESYSTEM) |
---|
| 1289 | + ret = fanotify_remove_sb_mark(group, mnt->mnt_sb, mask, |
---|
| 1290 | + flags, umask); |
---|
894 | 1291 | else |
---|
895 | | - ret = fanotify_remove_inode_mark(group, inode, mask, flags); |
---|
| 1292 | + ret = fanotify_remove_inode_mark(group, inode, mask, |
---|
| 1293 | + flags, umask); |
---|
896 | 1294 | break; |
---|
897 | 1295 | default: |
---|
898 | 1296 | ret = -EINVAL; |
---|
899 | 1297 | } |
---|
900 | 1298 | |
---|
| 1299 | +path_put_and_out: |
---|
901 | 1300 | path_put(&path); |
---|
902 | 1301 | fput_and_out: |
---|
903 | 1302 | fdput(f); |
---|
904 | 1303 | return ret; |
---|
905 | 1304 | } |
---|
906 | 1305 | |
---|
| 1306 | +#ifndef CONFIG_ARCH_SPLIT_ARG64 |
---|
907 | 1307 | SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags, |
---|
908 | 1308 | __u64, mask, int, dfd, |
---|
909 | 1309 | const char __user *, pathname) |
---|
910 | 1310 | { |
---|
911 | 1311 | return do_fanotify_mark(fanotify_fd, flags, mask, dfd, pathname); |
---|
912 | 1312 | } |
---|
| 1313 | +#endif |
---|
913 | 1314 | |
---|
914 | | -#ifdef CONFIG_COMPAT |
---|
915 | | -COMPAT_SYSCALL_DEFINE6(fanotify_mark, |
---|
| 1315 | +#if defined(CONFIG_ARCH_SPLIT_ARG64) || defined(CONFIG_COMPAT) |
---|
| 1316 | +SYSCALL32_DEFINE6(fanotify_mark, |
---|
916 | 1317 | int, fanotify_fd, unsigned int, flags, |
---|
917 | | - __u32, mask0, __u32, mask1, int, dfd, |
---|
| 1318 | + SC_ARG64(mask), int, dfd, |
---|
918 | 1319 | const char __user *, pathname) |
---|
919 | 1320 | { |
---|
920 | | - return do_fanotify_mark(fanotify_fd, flags, |
---|
921 | | -#ifdef __BIG_ENDIAN |
---|
922 | | - ((__u64)mask0 << 32) | mask1, |
---|
923 | | -#else |
---|
924 | | - ((__u64)mask1 << 32) | mask0, |
---|
925 | | -#endif |
---|
926 | | - dfd, pathname); |
---|
| 1321 | + return do_fanotify_mark(fanotify_fd, flags, SC_VAL64(__u64, mask), |
---|
| 1322 | + dfd, pathname); |
---|
927 | 1323 | } |
---|
928 | 1324 | #endif |
---|
929 | 1325 | |
---|
.. | .. |
---|
934 | 1330 | */ |
---|
935 | 1331 | static int __init fanotify_user_setup(void) |
---|
936 | 1332 | { |
---|
| 1333 | + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 10); |
---|
| 1334 | + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9); |
---|
| 1335 | + |
---|
937 | 1336 | fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, |
---|
938 | 1337 | SLAB_PANIC|SLAB_ACCOUNT); |
---|
939 | | - fanotify_event_cachep = KMEM_CACHE(fanotify_event_info, SLAB_PANIC); |
---|
| 1338 | + fanotify_fid_event_cachep = KMEM_CACHE(fanotify_fid_event, |
---|
| 1339 | + SLAB_PANIC); |
---|
| 1340 | + fanotify_path_event_cachep = KMEM_CACHE(fanotify_path_event, |
---|
| 1341 | + SLAB_PANIC); |
---|
940 | 1342 | if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS)) { |
---|
941 | 1343 | fanotify_perm_event_cachep = |
---|
942 | | - KMEM_CACHE(fanotify_perm_event_info, SLAB_PANIC); |
---|
| 1344 | + KMEM_CACHE(fanotify_perm_event, SLAB_PANIC); |
---|
943 | 1345 | } |
---|
944 | 1346 | |
---|
945 | 1347 | return 0; |
---|