1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #include <linux/fsnotify_backend.h> |
3 | #include <linux/path.h> |
4 | #include <linux/slab.h> |
5 | #include <linux/exportfs.h> |
6 | #include <linux/hashtable.h> |
7 | |
8 | extern struct kmem_cache *fanotify_mark_cache; |
9 | extern struct kmem_cache *fanotify_fid_event_cachep; |
10 | extern struct kmem_cache *fanotify_path_event_cachep; |
11 | extern struct kmem_cache *fanotify_perm_event_cachep; |
12 | |
13 | /* Possible states of the permission event */ |
14 | enum { |
15 | FAN_EVENT_INIT, |
16 | FAN_EVENT_REPORTED, |
17 | FAN_EVENT_ANSWERED, |
18 | FAN_EVENT_CANCELED, |
19 | }; |
20 | |
21 | /* |
22 | * 3 dwords are sufficient for most local fs (64bit ino, 32bit generation). |
23 | * fh buf should be dword aligned. On 64bit arch, the ext_buf pointer is |
24 | * stored in either the first or last 2 dwords. |
25 | */ |
26 | #define FANOTIFY_INLINE_FH_LEN (3 << 2) |
27 | #define FANOTIFY_FH_HDR_LEN offsetof(struct fanotify_fh, buf) |
28 | |
29 | /* Fixed size struct for file handle */ |
30 | struct fanotify_fh { |
31 | u8 type; |
32 | u8 len; |
33 | #define FANOTIFY_FH_FLAG_EXT_BUF 1 |
34 | u8 flags; |
35 | u8 pad; |
36 | unsigned char buf[]; |
37 | } __aligned(4); |
38 | |
39 | /* Variable size struct for dir file handle + child file handle + name */ |
40 | struct fanotify_info { |
41 | /* size of dir_fh/file_fh including fanotify_fh hdr size */ |
42 | u8 dir_fh_totlen; |
43 | u8 dir2_fh_totlen; |
44 | u8 file_fh_totlen; |
45 | u8 name_len; |
46 | u8 name2_len; |
47 | u8 pad[3]; |
48 | unsigned char buf[]; |
49 | /* |
50 | * (struct fanotify_fh) dir_fh starts at buf[0] |
51 | * (optional) dir2_fh starts at buf[dir_fh_totlen] |
52 | * (optional) file_fh starts at buf[dir_fh_totlen + dir2_fh_totlen] |
53 | * name starts at buf[dir_fh_totlen + dir2_fh_totlen + file_fh_totlen] |
54 | * ... |
55 | */ |
56 | #define FANOTIFY_DIR_FH_SIZE(info) ((info)->dir_fh_totlen) |
57 | #define FANOTIFY_DIR2_FH_SIZE(info) ((info)->dir2_fh_totlen) |
58 | #define FANOTIFY_FILE_FH_SIZE(info) ((info)->file_fh_totlen) |
59 | #define FANOTIFY_NAME_SIZE(info) ((info)->name_len + 1) |
60 | #define FANOTIFY_NAME2_SIZE(info) ((info)->name2_len + 1) |
61 | |
62 | #define FANOTIFY_DIR_FH_OFFSET(info) 0 |
63 | #define FANOTIFY_DIR2_FH_OFFSET(info) \ |
64 | (FANOTIFY_DIR_FH_OFFSET(info) + FANOTIFY_DIR_FH_SIZE(info)) |
65 | #define FANOTIFY_FILE_FH_OFFSET(info) \ |
66 | (FANOTIFY_DIR2_FH_OFFSET(info) + FANOTIFY_DIR2_FH_SIZE(info)) |
67 | #define FANOTIFY_NAME_OFFSET(info) \ |
68 | (FANOTIFY_FILE_FH_OFFSET(info) + FANOTIFY_FILE_FH_SIZE(info)) |
69 | #define FANOTIFY_NAME2_OFFSET(info) \ |
70 | (FANOTIFY_NAME_OFFSET(info) + FANOTIFY_NAME_SIZE(info)) |
71 | |
72 | #define FANOTIFY_DIR_FH_BUF(info) \ |
73 | ((info)->buf + FANOTIFY_DIR_FH_OFFSET(info)) |
74 | #define FANOTIFY_DIR2_FH_BUF(info) \ |
75 | ((info)->buf + FANOTIFY_DIR2_FH_OFFSET(info)) |
76 | #define FANOTIFY_FILE_FH_BUF(info) \ |
77 | ((info)->buf + FANOTIFY_FILE_FH_OFFSET(info)) |
78 | #define FANOTIFY_NAME_BUF(info) \ |
79 | ((info)->buf + FANOTIFY_NAME_OFFSET(info)) |
80 | #define FANOTIFY_NAME2_BUF(info) \ |
81 | ((info)->buf + FANOTIFY_NAME2_OFFSET(info)) |
82 | } __aligned(4); |
83 | |
84 | static inline bool fanotify_fh_has_ext_buf(struct fanotify_fh *fh) |
85 | { |
86 | return (fh->flags & FANOTIFY_FH_FLAG_EXT_BUF); |
87 | } |
88 | |
89 | static inline char **fanotify_fh_ext_buf_ptr(struct fanotify_fh *fh) |
90 | { |
91 | BUILD_BUG_ON(FANOTIFY_FH_HDR_LEN % 4); |
92 | BUILD_BUG_ON(__alignof__(char *) - 4 + sizeof(char *) > |
93 | FANOTIFY_INLINE_FH_LEN); |
94 | return (char **)ALIGN((unsigned long)(fh->buf), __alignof__(char *)); |
95 | } |
96 | |
97 | static inline void *fanotify_fh_ext_buf(struct fanotify_fh *fh) |
98 | { |
99 | return *fanotify_fh_ext_buf_ptr(fh); |
100 | } |
101 | |
102 | static inline void *fanotify_fh_buf(struct fanotify_fh *fh) |
103 | { |
104 | return fanotify_fh_has_ext_buf(fh) ? fanotify_fh_ext_buf(fh) : fh->buf; |
105 | } |
106 | |
107 | static inline int fanotify_info_dir_fh_len(struct fanotify_info *info) |
108 | { |
109 | if (!info->dir_fh_totlen || |
110 | WARN_ON_ONCE(info->dir_fh_totlen < FANOTIFY_FH_HDR_LEN)) |
111 | return 0; |
112 | |
113 | return info->dir_fh_totlen - FANOTIFY_FH_HDR_LEN; |
114 | } |
115 | |
116 | static inline struct fanotify_fh *fanotify_info_dir_fh(struct fanotify_info *info) |
117 | { |
118 | BUILD_BUG_ON(offsetof(struct fanotify_info, buf) % 4); |
119 | |
120 | return (struct fanotify_fh *)FANOTIFY_DIR_FH_BUF(info); |
121 | } |
122 | |
123 | static inline int fanotify_info_dir2_fh_len(struct fanotify_info *info) |
124 | { |
125 | if (!info->dir2_fh_totlen || |
126 | WARN_ON_ONCE(info->dir2_fh_totlen < FANOTIFY_FH_HDR_LEN)) |
127 | return 0; |
128 | |
129 | return info->dir2_fh_totlen - FANOTIFY_FH_HDR_LEN; |
130 | } |
131 | |
132 | static inline struct fanotify_fh *fanotify_info_dir2_fh(struct fanotify_info *info) |
133 | { |
134 | return (struct fanotify_fh *)FANOTIFY_DIR2_FH_BUF(info); |
135 | } |
136 | |
137 | static inline int fanotify_info_file_fh_len(struct fanotify_info *info) |
138 | { |
139 | if (!info->file_fh_totlen || |
140 | WARN_ON_ONCE(info->file_fh_totlen < FANOTIFY_FH_HDR_LEN)) |
141 | return 0; |
142 | |
143 | return info->file_fh_totlen - FANOTIFY_FH_HDR_LEN; |
144 | } |
145 | |
146 | static inline struct fanotify_fh *fanotify_info_file_fh(struct fanotify_info *info) |
147 | { |
148 | return (struct fanotify_fh *)FANOTIFY_FILE_FH_BUF(info); |
149 | } |
150 | |
151 | static inline char *fanotify_info_name(struct fanotify_info *info) |
152 | { |
153 | if (!info->name_len) |
154 | return NULL; |
155 | |
156 | return FANOTIFY_NAME_BUF(info); |
157 | } |
158 | |
159 | static inline char *fanotify_info_name2(struct fanotify_info *info) |
160 | { |
161 | if (!info->name2_len) |
162 | return NULL; |
163 | |
164 | return FANOTIFY_NAME2_BUF(info); |
165 | } |
166 | |
167 | static inline void fanotify_info_init(struct fanotify_info *info) |
168 | { |
169 | BUILD_BUG_ON(FANOTIFY_FH_HDR_LEN + MAX_HANDLE_SZ > U8_MAX); |
170 | BUILD_BUG_ON(NAME_MAX > U8_MAX); |
171 | |
172 | info->dir_fh_totlen = 0; |
173 | info->dir2_fh_totlen = 0; |
174 | info->file_fh_totlen = 0; |
175 | info->name_len = 0; |
176 | info->name2_len = 0; |
177 | } |
178 | |
179 | /* These set/copy helpers MUST be called by order */ |
180 | static inline void fanotify_info_set_dir_fh(struct fanotify_info *info, |
181 | unsigned int totlen) |
182 | { |
183 | if (WARN_ON_ONCE(info->dir2_fh_totlen > 0) || |
184 | WARN_ON_ONCE(info->file_fh_totlen > 0) || |
185 | WARN_ON_ONCE(info->name_len > 0) || |
186 | WARN_ON_ONCE(info->name2_len > 0)) |
187 | return; |
188 | |
189 | info->dir_fh_totlen = totlen; |
190 | } |
191 | |
192 | static inline void fanotify_info_set_dir2_fh(struct fanotify_info *info, |
193 | unsigned int totlen) |
194 | { |
195 | if (WARN_ON_ONCE(info->file_fh_totlen > 0) || |
196 | WARN_ON_ONCE(info->name_len > 0) || |
197 | WARN_ON_ONCE(info->name2_len > 0)) |
198 | return; |
199 | |
200 | info->dir2_fh_totlen = totlen; |
201 | } |
202 | |
203 | static inline void fanotify_info_set_file_fh(struct fanotify_info *info, |
204 | unsigned int totlen) |
205 | { |
206 | if (WARN_ON_ONCE(info->name_len > 0) || |
207 | WARN_ON_ONCE(info->name2_len > 0)) |
208 | return; |
209 | |
210 | info->file_fh_totlen = totlen; |
211 | } |
212 | |
213 | static inline void fanotify_info_copy_name(struct fanotify_info *info, |
214 | const struct qstr *name) |
215 | { |
216 | if (WARN_ON_ONCE(name->len > NAME_MAX) || |
217 | WARN_ON_ONCE(info->name2_len > 0)) |
218 | return; |
219 | |
220 | info->name_len = name->len; |
221 | strcpy(p: fanotify_info_name(info), q: name->name); |
222 | } |
223 | |
224 | static inline void fanotify_info_copy_name2(struct fanotify_info *info, |
225 | const struct qstr *name) |
226 | { |
227 | if (WARN_ON_ONCE(name->len > NAME_MAX)) |
228 | return; |
229 | |
230 | info->name2_len = name->len; |
231 | strcpy(p: fanotify_info_name2(info), q: name->name); |
232 | } |
233 | |
234 | /* |
235 | * Common structure for fanotify events. Concrete structs are allocated in |
236 | * fanotify_handle_event() and freed when the information is retrieved by |
237 | * userspace. The type of event determines how it was allocated, how it will |
238 | * be freed and which concrete struct it may be cast to. |
239 | */ |
240 | enum fanotify_event_type { |
241 | FANOTIFY_EVENT_TYPE_FID, /* fixed length */ |
242 | FANOTIFY_EVENT_TYPE_FID_NAME, /* variable length */ |
243 | FANOTIFY_EVENT_TYPE_PATH, |
244 | FANOTIFY_EVENT_TYPE_PATH_PERM, |
245 | FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */ |
246 | FANOTIFY_EVENT_TYPE_FS_ERROR, /* struct fanotify_error_event */ |
247 | __FANOTIFY_EVENT_TYPE_NUM |
248 | }; |
249 | |
250 | #define FANOTIFY_EVENT_TYPE_BITS \ |
251 | (ilog2(__FANOTIFY_EVENT_TYPE_NUM - 1) + 1) |
252 | #define FANOTIFY_EVENT_HASH_BITS \ |
253 | (32 - FANOTIFY_EVENT_TYPE_BITS) |
254 | |
255 | struct fanotify_event { |
256 | struct fsnotify_event fse; |
257 | struct hlist_node merge_list; /* List for hashed merge */ |
258 | u32 mask; |
259 | struct { |
260 | unsigned int type : FANOTIFY_EVENT_TYPE_BITS; |
261 | unsigned int hash : FANOTIFY_EVENT_HASH_BITS; |
262 | }; |
263 | struct pid *pid; |
264 | }; |
265 | |
266 | static inline void fanotify_init_event(struct fanotify_event *event, |
267 | unsigned int hash, u32 mask) |
268 | { |
269 | fsnotify_init_event(event: &event->fse); |
270 | INIT_HLIST_NODE(h: &event->merge_list); |
271 | event->hash = hash; |
272 | event->mask = mask; |
273 | event->pid = NULL; |
274 | } |
275 | |
276 | #define FANOTIFY_INLINE_FH(name, size) \ |
277 | struct { \ |
278 | struct fanotify_fh name; \ |
279 | /* Space for object_fh.buf[] - access with fanotify_fh_buf() */ \ |
280 | unsigned char _inline_fh_buf[size]; \ |
281 | } |
282 | |
283 | struct fanotify_fid_event { |
284 | struct fanotify_event fae; |
285 | __kernel_fsid_t fsid; |
286 | |
287 | FANOTIFY_INLINE_FH(object_fh, FANOTIFY_INLINE_FH_LEN); |
288 | }; |
289 | |
290 | static inline struct fanotify_fid_event * |
291 | FANOTIFY_FE(struct fanotify_event *event) |
292 | { |
293 | return container_of(event, struct fanotify_fid_event, fae); |
294 | } |
295 | |
296 | struct fanotify_name_event { |
297 | struct fanotify_event fae; |
298 | __kernel_fsid_t fsid; |
299 | struct fanotify_info info; |
300 | }; |
301 | |
302 | static inline struct fanotify_name_event * |
303 | FANOTIFY_NE(struct fanotify_event *event) |
304 | { |
305 | return container_of(event, struct fanotify_name_event, fae); |
306 | } |
307 | |
308 | struct fanotify_error_event { |
309 | struct fanotify_event fae; |
310 | s32 error; /* Error reported by the Filesystem. */ |
311 | u32 err_count; /* Suppressed errors count */ |
312 | |
313 | __kernel_fsid_t fsid; /* FSID this error refers to. */ |
314 | |
315 | FANOTIFY_INLINE_FH(object_fh, MAX_HANDLE_SZ); |
316 | }; |
317 | |
318 | static inline struct fanotify_error_event * |
319 | FANOTIFY_EE(struct fanotify_event *event) |
320 | { |
321 | return container_of(event, struct fanotify_error_event, fae); |
322 | } |
323 | |
324 | static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event) |
325 | { |
326 | if (event->type == FANOTIFY_EVENT_TYPE_FID) |
327 | return &FANOTIFY_FE(event)->fsid; |
328 | else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME) |
329 | return &FANOTIFY_NE(event)->fsid; |
330 | else if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR) |
331 | return &FANOTIFY_EE(event)->fsid; |
332 | else |
333 | return NULL; |
334 | } |
335 | |
336 | static inline struct fanotify_fh *fanotify_event_object_fh( |
337 | struct fanotify_event *event) |
338 | { |
339 | if (event->type == FANOTIFY_EVENT_TYPE_FID) |
340 | return &FANOTIFY_FE(event)->object_fh; |
341 | else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME) |
342 | return fanotify_info_file_fh(info: &FANOTIFY_NE(event)->info); |
343 | else if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR) |
344 | return &FANOTIFY_EE(event)->object_fh; |
345 | else |
346 | return NULL; |
347 | } |
348 | |
349 | static inline struct fanotify_info *fanotify_event_info( |
350 | struct fanotify_event *event) |
351 | { |
352 | if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME) |
353 | return &FANOTIFY_NE(event)->info; |
354 | else |
355 | return NULL; |
356 | } |
357 | |
358 | static inline int fanotify_event_object_fh_len(struct fanotify_event *event) |
359 | { |
360 | struct fanotify_info *info = fanotify_event_info(event); |
361 | struct fanotify_fh *fh = fanotify_event_object_fh(event); |
362 | |
363 | if (info) |
364 | return info->file_fh_totlen ? fh->len : 0; |
365 | else |
366 | return fh ? fh->len : 0; |
367 | } |
368 | |
369 | static inline int fanotify_event_dir_fh_len(struct fanotify_event *event) |
370 | { |
371 | struct fanotify_info *info = fanotify_event_info(event); |
372 | |
373 | return info ? fanotify_info_dir_fh_len(info) : 0; |
374 | } |
375 | |
376 | static inline int fanotify_event_dir2_fh_len(struct fanotify_event *event) |
377 | { |
378 | struct fanotify_info *info = fanotify_event_info(event); |
379 | |
380 | return info ? fanotify_info_dir2_fh_len(info) : 0; |
381 | } |
382 | |
383 | static inline bool fanotify_event_has_object_fh(struct fanotify_event *event) |
384 | { |
385 | /* For error events, even zeroed fh are reported. */ |
386 | if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR) |
387 | return true; |
388 | return fanotify_event_object_fh_len(event) > 0; |
389 | } |
390 | |
391 | static inline bool fanotify_event_has_dir_fh(struct fanotify_event *event) |
392 | { |
393 | return fanotify_event_dir_fh_len(event) > 0; |
394 | } |
395 | |
396 | static inline bool fanotify_event_has_dir2_fh(struct fanotify_event *event) |
397 | { |
398 | return fanotify_event_dir2_fh_len(event) > 0; |
399 | } |
400 | |
401 | static inline bool fanotify_event_has_any_dir_fh(struct fanotify_event *event) |
402 | { |
403 | return fanotify_event_has_dir_fh(event) || |
404 | fanotify_event_has_dir2_fh(event); |
405 | } |
406 | |
407 | struct fanotify_path_event { |
408 | struct fanotify_event fae; |
409 | struct path path; |
410 | }; |
411 | |
412 | static inline struct fanotify_path_event * |
413 | FANOTIFY_PE(struct fanotify_event *event) |
414 | { |
415 | return container_of(event, struct fanotify_path_event, fae); |
416 | } |
417 | |
418 | /* |
419 | * Structure for permission fanotify events. It gets allocated and freed in |
420 | * fanotify_handle_event() since we wait there for user response. When the |
421 | * information is retrieved by userspace the structure is moved from |
422 | * group->notification_list to group->fanotify_data.access_list to wait for |
423 | * user response. |
424 | */ |
425 | struct fanotify_perm_event { |
426 | struct fanotify_event fae; |
427 | struct path path; |
428 | u32 response; /* userspace answer to the event */ |
429 | unsigned short state; /* state of the event */ |
430 | int fd; /* fd we passed to userspace for this event */ |
431 | union { |
432 | struct fanotify_response_info_header hdr; |
433 | struct fanotify_response_info_audit_rule audit_rule; |
434 | }; |
435 | }; |
436 | |
437 | static inline struct fanotify_perm_event * |
438 | FANOTIFY_PERM(struct fanotify_event *event) |
439 | { |
440 | return container_of(event, struct fanotify_perm_event, fae); |
441 | } |
442 | |
443 | static inline bool fanotify_is_perm_event(u32 mask) |
444 | { |
445 | return IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS) && |
446 | mask & FANOTIFY_PERM_EVENTS; |
447 | } |
448 | |
449 | static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse) |
450 | { |
451 | return container_of(fse, struct fanotify_event, fse); |
452 | } |
453 | |
454 | static inline bool fanotify_is_error_event(u32 mask) |
455 | { |
456 | return mask & FAN_FS_ERROR; |
457 | } |
458 | |
459 | static inline const struct path *fanotify_event_path(struct fanotify_event *event) |
460 | { |
461 | if (event->type == FANOTIFY_EVENT_TYPE_PATH) |
462 | return &FANOTIFY_PE(event)->path; |
463 | else if (event->type == FANOTIFY_EVENT_TYPE_PATH_PERM) |
464 | return &FANOTIFY_PERM(event)->path; |
465 | else |
466 | return NULL; |
467 | } |
468 | |
469 | /* |
470 | * Use 128 size hash table to speed up events merge. |
471 | */ |
472 | #define FANOTIFY_HTABLE_BITS (7) |
473 | #define FANOTIFY_HTABLE_SIZE (1 << FANOTIFY_HTABLE_BITS) |
474 | #define FANOTIFY_HTABLE_MASK (FANOTIFY_HTABLE_SIZE - 1) |
475 | |
476 | /* |
477 | * Permission events and overflow event do not get merged - don't hash them. |
478 | */ |
479 | static inline bool fanotify_is_hashed_event(u32 mask) |
480 | { |
481 | return !(fanotify_is_perm_event(mask) || |
482 | fsnotify_is_overflow_event(mask)); |
483 | } |
484 | |
485 | static inline unsigned int fanotify_event_hash_bucket( |
486 | struct fsnotify_group *group, |
487 | struct fanotify_event *event) |
488 | { |
489 | return event->hash & FANOTIFY_HTABLE_MASK; |
490 | } |
491 | |
492 | struct fanotify_mark { |
493 | struct fsnotify_mark fsn_mark; |
494 | __kernel_fsid_t fsid; |
495 | }; |
496 | |
497 | static inline struct fanotify_mark *FANOTIFY_MARK(struct fsnotify_mark *mark) |
498 | { |
499 | return container_of(mark, struct fanotify_mark, fsn_mark); |
500 | } |
501 | |
502 | static inline bool fanotify_fsid_equal(__kernel_fsid_t *fsid1, |
503 | __kernel_fsid_t *fsid2) |
504 | { |
505 | return fsid1->val[0] == fsid2->val[0] && fsid1->val[1] == fsid2->val[1]; |
506 | } |
507 | |
508 | static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark) |
509 | { |
510 | unsigned int mflags = 0; |
511 | |
512 | if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY) |
513 | mflags |= FAN_MARK_IGNORED_SURV_MODIFY; |
514 | if (mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF) |
515 | mflags |= FAN_MARK_EVICTABLE; |
516 | if (mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS) |
517 | mflags |= FAN_MARK_IGNORE; |
518 | |
519 | return mflags; |
520 | } |
521 | |