.. | .. |
---|
2 | 2 | #include <linux/fsnotify_backend.h> |
---|
3 | 3 | #include <linux/path.h> |
---|
4 | 4 | #include <linux/slab.h> |
---|
| 5 | +#include <linux/exportfs.h> |
---|
5 | 6 | |
---|
6 | 7 | extern struct kmem_cache *fanotify_mark_cache; |
---|
7 | | -extern struct kmem_cache *fanotify_event_cachep; |
---|
| 8 | +extern struct kmem_cache *fanotify_fid_event_cachep; |
---|
| 9 | +extern struct kmem_cache *fanotify_path_event_cachep; |
---|
8 | 10 | extern struct kmem_cache *fanotify_perm_event_cachep; |
---|
9 | 11 | |
---|
10 | | -/* |
---|
11 | | - * Structure for normal fanotify events. It gets allocated in |
---|
12 | | - * fanotify_handle_event() and freed when the information is retrieved by |
---|
13 | | - * userspace |
---|
14 | | - */ |
---|
15 | | -struct fanotify_event_info { |
---|
16 | | - struct fsnotify_event fse; |
---|
17 | | - /* |
---|
18 | | - * We hold ref to this path so it may be dereferenced at any point |
---|
19 | | - * during this object's lifetime |
---|
20 | | - */ |
---|
21 | | - struct path path; |
---|
22 | | - struct pid *tgid; |
---|
| 12 | +/* Possible states of the permission event */ |
---|
| 13 | +enum { |
---|
| 14 | + FAN_EVENT_INIT, |
---|
| 15 | + FAN_EVENT_REPORTED, |
---|
| 16 | + FAN_EVENT_ANSWERED, |
---|
| 17 | + FAN_EVENT_CANCELED, |
---|
23 | 18 | }; |
---|
| 19 | + |
---|
| 20 | +/* |
---|
| 21 | + * 3 dwords are sufficient for most local fs (64bit ino, 32bit generation). |
---|
| 22 | + * fh buf should be dword aligned. On 64bit arch, the ext_buf pointer is |
---|
| 23 | + * stored in either the first or last 2 dwords. |
---|
| 24 | + */ |
---|
| 25 | +#define FANOTIFY_INLINE_FH_LEN (3 << 2) |
---|
| 26 | +#define FANOTIFY_FH_HDR_LEN offsetof(struct fanotify_fh, buf) |
---|
| 27 | + |
---|
| 28 | +/* Fixed size struct for file handle */ |
---|
| 29 | +struct fanotify_fh { |
---|
| 30 | + u8 type; |
---|
| 31 | + u8 len; |
---|
| 32 | +#define FANOTIFY_FH_FLAG_EXT_BUF 1 |
---|
| 33 | + u8 flags; |
---|
| 34 | + u8 pad; |
---|
| 35 | + unsigned char buf[]; |
---|
| 36 | +} __aligned(4); |
---|
| 37 | + |
---|
| 38 | +/* Variable size struct for dir file handle + child file handle + name */ |
---|
| 39 | +struct fanotify_info { |
---|
| 40 | + /* size of dir_fh/file_fh including fanotify_fh hdr size */ |
---|
| 41 | + u8 dir_fh_totlen; |
---|
| 42 | + u8 file_fh_totlen; |
---|
| 43 | + u8 name_len; |
---|
| 44 | + u8 pad; |
---|
| 45 | + unsigned char buf[]; |
---|
| 46 | + /* |
---|
| 47 | + * (struct fanotify_fh) dir_fh starts at buf[0] |
---|
| 48 | + * (optional) file_fh starts at buf[dir_fh_totlen] |
---|
| 49 | + * name starts at buf[dir_fh_totlen + file_fh_totlen] |
---|
| 50 | + */ |
---|
| 51 | +} __aligned(4); |
---|
| 52 | + |
---|
| 53 | +static inline bool fanotify_fh_has_ext_buf(struct fanotify_fh *fh) |
---|
| 54 | +{ |
---|
| 55 | + return (fh->flags & FANOTIFY_FH_FLAG_EXT_BUF); |
---|
| 56 | +} |
---|
| 57 | + |
---|
| 58 | +static inline char **fanotify_fh_ext_buf_ptr(struct fanotify_fh *fh) |
---|
| 59 | +{ |
---|
| 60 | + BUILD_BUG_ON(FANOTIFY_FH_HDR_LEN % 4); |
---|
| 61 | + BUILD_BUG_ON(__alignof__(char *) - 4 + sizeof(char *) > |
---|
| 62 | + FANOTIFY_INLINE_FH_LEN); |
---|
| 63 | + return (char **)ALIGN((unsigned long)(fh->buf), __alignof__(char *)); |
---|
| 64 | +} |
---|
| 65 | + |
---|
| 66 | +static inline void *fanotify_fh_ext_buf(struct fanotify_fh *fh) |
---|
| 67 | +{ |
---|
| 68 | + return *fanotify_fh_ext_buf_ptr(fh); |
---|
| 69 | +} |
---|
| 70 | + |
---|
| 71 | +static inline void *fanotify_fh_buf(struct fanotify_fh *fh) |
---|
| 72 | +{ |
---|
| 73 | + return fanotify_fh_has_ext_buf(fh) ? fanotify_fh_ext_buf(fh) : fh->buf; |
---|
| 74 | +} |
---|
| 75 | + |
---|
| 76 | +static inline int fanotify_info_dir_fh_len(struct fanotify_info *info) |
---|
| 77 | +{ |
---|
| 78 | + if (!info->dir_fh_totlen || |
---|
| 79 | + WARN_ON_ONCE(info->dir_fh_totlen < FANOTIFY_FH_HDR_LEN)) |
---|
| 80 | + return 0; |
---|
| 81 | + |
---|
| 82 | + return info->dir_fh_totlen - FANOTIFY_FH_HDR_LEN; |
---|
| 83 | +} |
---|
| 84 | + |
---|
| 85 | +static inline struct fanotify_fh *fanotify_info_dir_fh(struct fanotify_info *info) |
---|
| 86 | +{ |
---|
| 87 | + BUILD_BUG_ON(offsetof(struct fanotify_info, buf) % 4); |
---|
| 88 | + |
---|
| 89 | + return (struct fanotify_fh *)info->buf; |
---|
| 90 | +} |
---|
| 91 | + |
---|
| 92 | +static inline int fanotify_info_file_fh_len(struct fanotify_info *info) |
---|
| 93 | +{ |
---|
| 94 | + if (!info->file_fh_totlen || |
---|
| 95 | + WARN_ON_ONCE(info->file_fh_totlen < FANOTIFY_FH_HDR_LEN)) |
---|
| 96 | + return 0; |
---|
| 97 | + |
---|
| 98 | + return info->file_fh_totlen - FANOTIFY_FH_HDR_LEN; |
---|
| 99 | +} |
---|
| 100 | + |
---|
| 101 | +static inline struct fanotify_fh *fanotify_info_file_fh(struct fanotify_info *info) |
---|
| 102 | +{ |
---|
| 103 | + return (struct fanotify_fh *)(info->buf + info->dir_fh_totlen); |
---|
| 104 | +} |
---|
| 105 | + |
---|
| 106 | +static inline const char *fanotify_info_name(struct fanotify_info *info) |
---|
| 107 | +{ |
---|
| 108 | + return info->buf + info->dir_fh_totlen + info->file_fh_totlen; |
---|
| 109 | +} |
---|
| 110 | + |
---|
| 111 | +static inline void fanotify_info_init(struct fanotify_info *info) |
---|
| 112 | +{ |
---|
| 113 | + info->dir_fh_totlen = 0; |
---|
| 114 | + info->file_fh_totlen = 0; |
---|
| 115 | + info->name_len = 0; |
---|
| 116 | +} |
---|
| 117 | + |
---|
| 118 | +static inline void fanotify_info_copy_name(struct fanotify_info *info, |
---|
| 119 | + const struct qstr *name) |
---|
| 120 | +{ |
---|
| 121 | + info->name_len = name->len; |
---|
| 122 | + strcpy(info->buf + info->dir_fh_totlen + info->file_fh_totlen, |
---|
| 123 | + name->name); |
---|
| 124 | +} |
---|
| 125 | + |
---|
| 126 | +/* |
---|
| 127 | + * Common structure for fanotify events. Concrete structs are allocated in |
---|
| 128 | + * fanotify_handle_event() and freed when the information is retrieved by |
---|
| 129 | + * userspace. The type of event determines how it was allocated, how it will |
---|
| 130 | + * be freed and which concrete struct it may be cast to. |
---|
| 131 | + */ |
---|
| 132 | +enum fanotify_event_type { |
---|
| 133 | + FANOTIFY_EVENT_TYPE_FID, /* fixed length */ |
---|
| 134 | + FANOTIFY_EVENT_TYPE_FID_NAME, /* variable length */ |
---|
| 135 | + FANOTIFY_EVENT_TYPE_PATH, |
---|
| 136 | + FANOTIFY_EVENT_TYPE_PATH_PERM, |
---|
| 137 | + FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */ |
---|
| 138 | +}; |
---|
| 139 | + |
---|
| 140 | +struct fanotify_event { |
---|
| 141 | + struct fsnotify_event fse; |
---|
| 142 | + u32 mask; |
---|
| 143 | + enum fanotify_event_type type; |
---|
| 144 | + struct pid *pid; |
---|
| 145 | +}; |
---|
| 146 | + |
---|
| 147 | +static inline void fanotify_init_event(struct fanotify_event *event, |
---|
| 148 | + unsigned long id, u32 mask) |
---|
| 149 | +{ |
---|
| 150 | + fsnotify_init_event(&event->fse, id); |
---|
| 151 | + event->mask = mask; |
---|
| 152 | + event->pid = NULL; |
---|
| 153 | +} |
---|
| 154 | + |
---|
| 155 | +struct fanotify_fid_event { |
---|
| 156 | + struct fanotify_event fae; |
---|
| 157 | + __kernel_fsid_t fsid; |
---|
| 158 | + struct fanotify_fh object_fh; |
---|
| 159 | + /* Reserve space in object_fh.buf[] - access with fanotify_fh_buf() */ |
---|
| 160 | + unsigned char _inline_fh_buf[FANOTIFY_INLINE_FH_LEN]; |
---|
| 161 | +}; |
---|
| 162 | + |
---|
| 163 | +static inline struct fanotify_fid_event * |
---|
| 164 | +FANOTIFY_FE(struct fanotify_event *event) |
---|
| 165 | +{ |
---|
| 166 | + return container_of(event, struct fanotify_fid_event, fae); |
---|
| 167 | +} |
---|
| 168 | + |
---|
| 169 | +struct fanotify_name_event { |
---|
| 170 | + struct fanotify_event fae; |
---|
| 171 | + __kernel_fsid_t fsid; |
---|
| 172 | + struct fanotify_info info; |
---|
| 173 | +}; |
---|
| 174 | + |
---|
| 175 | +static inline struct fanotify_name_event * |
---|
| 176 | +FANOTIFY_NE(struct fanotify_event *event) |
---|
| 177 | +{ |
---|
| 178 | + return container_of(event, struct fanotify_name_event, fae); |
---|
| 179 | +} |
---|
| 180 | + |
---|
| 181 | +static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event) |
---|
| 182 | +{ |
---|
| 183 | + if (event->type == FANOTIFY_EVENT_TYPE_FID) |
---|
| 184 | + return &FANOTIFY_FE(event)->fsid; |
---|
| 185 | + else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME) |
---|
| 186 | + return &FANOTIFY_NE(event)->fsid; |
---|
| 187 | + else |
---|
| 188 | + return NULL; |
---|
| 189 | +} |
---|
| 190 | + |
---|
| 191 | +static inline struct fanotify_fh *fanotify_event_object_fh( |
---|
| 192 | + struct fanotify_event *event) |
---|
| 193 | +{ |
---|
| 194 | + if (event->type == FANOTIFY_EVENT_TYPE_FID) |
---|
| 195 | + return &FANOTIFY_FE(event)->object_fh; |
---|
| 196 | + else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME) |
---|
| 197 | + return fanotify_info_file_fh(&FANOTIFY_NE(event)->info); |
---|
| 198 | + else |
---|
| 199 | + return NULL; |
---|
| 200 | +} |
---|
| 201 | + |
---|
| 202 | +static inline struct fanotify_info *fanotify_event_info( |
---|
| 203 | + struct fanotify_event *event) |
---|
| 204 | +{ |
---|
| 205 | + if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME) |
---|
| 206 | + return &FANOTIFY_NE(event)->info; |
---|
| 207 | + else |
---|
| 208 | + return NULL; |
---|
| 209 | +} |
---|
| 210 | + |
---|
| 211 | +static inline int fanotify_event_object_fh_len(struct fanotify_event *event) |
---|
| 212 | +{ |
---|
| 213 | + struct fanotify_info *info = fanotify_event_info(event); |
---|
| 214 | + struct fanotify_fh *fh = fanotify_event_object_fh(event); |
---|
| 215 | + |
---|
| 216 | + if (info) |
---|
| 217 | + return info->file_fh_totlen ? fh->len : 0; |
---|
| 218 | + else |
---|
| 219 | + return fh ? fh->len : 0; |
---|
| 220 | +} |
---|
| 221 | + |
---|
| 222 | +static inline int fanotify_event_dir_fh_len(struct fanotify_event *event) |
---|
| 223 | +{ |
---|
| 224 | + struct fanotify_info *info = fanotify_event_info(event); |
---|
| 225 | + |
---|
| 226 | + return info ? fanotify_info_dir_fh_len(info) : 0; |
---|
| 227 | +} |
---|
| 228 | + |
---|
| 229 | +struct fanotify_path_event { |
---|
| 230 | + struct fanotify_event fae; |
---|
| 231 | + struct path path; |
---|
| 232 | +}; |
---|
| 233 | + |
---|
| 234 | +static inline struct fanotify_path_event * |
---|
| 235 | +FANOTIFY_PE(struct fanotify_event *event) |
---|
| 236 | +{ |
---|
| 237 | + return container_of(event, struct fanotify_path_event, fae); |
---|
| 238 | +} |
---|
24 | 239 | |
---|
25 | 240 | /* |
---|
26 | 241 | * Structure for permission fanotify events. It gets allocated and freed in |
---|
.. | .. |
---|
29 | 244 | * group->notification_list to group->fanotify_data.access_list to wait for |
---|
30 | 245 | * user response. |
---|
31 | 246 | */ |
---|
32 | | -struct fanotify_perm_event_info { |
---|
33 | | - struct fanotify_event_info fae; |
---|
34 | | - int response; /* userspace answer to question */ |
---|
| 247 | +struct fanotify_perm_event { |
---|
| 248 | + struct fanotify_event fae; |
---|
| 249 | + struct path path; |
---|
| 250 | + unsigned short response; /* userspace answer to the event */ |
---|
| 251 | + unsigned short state; /* state of the event */ |
---|
35 | 252 | int fd; /* fd we passed to userspace for this event */ |
---|
36 | 253 | }; |
---|
37 | 254 | |
---|
38 | | -static inline struct fanotify_perm_event_info * |
---|
39 | | -FANOTIFY_PE(struct fsnotify_event *fse) |
---|
| 255 | +static inline struct fanotify_perm_event * |
---|
| 256 | +FANOTIFY_PERM(struct fanotify_event *event) |
---|
40 | 257 | { |
---|
41 | | - return container_of(fse, struct fanotify_perm_event_info, fae.fse); |
---|
| 258 | + return container_of(event, struct fanotify_perm_event, fae); |
---|
42 | 259 | } |
---|
43 | 260 | |
---|
44 | 261 | static inline bool fanotify_is_perm_event(u32 mask) |
---|
45 | 262 | { |
---|
46 | 263 | return IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS) && |
---|
47 | | - mask & FAN_ALL_PERM_EVENTS; |
---|
| 264 | + mask & FANOTIFY_PERM_EVENTS; |
---|
48 | 265 | } |
---|
49 | 266 | |
---|
50 | | -static inline struct fanotify_event_info *FANOTIFY_E(struct fsnotify_event *fse) |
---|
| 267 | +static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse) |
---|
51 | 268 | { |
---|
52 | | - return container_of(fse, struct fanotify_event_info, fse); |
---|
| 269 | + return container_of(fse, struct fanotify_event, fse); |
---|
53 | 270 | } |
---|
54 | 271 | |
---|
55 | | -struct fanotify_event_info *fanotify_alloc_event(struct fsnotify_group *group, |
---|
56 | | - struct inode *inode, u32 mask, |
---|
57 | | - const struct path *path); |
---|
| 272 | +static inline bool fanotify_event_has_path(struct fanotify_event *event) |
---|
| 273 | +{ |
---|
| 274 | + return event->type == FANOTIFY_EVENT_TYPE_PATH || |
---|
| 275 | + event->type == FANOTIFY_EVENT_TYPE_PATH_PERM; |
---|
| 276 | +} |
---|
| 277 | + |
---|
| 278 | +static inline struct path *fanotify_event_path(struct fanotify_event *event) |
---|
| 279 | +{ |
---|
| 280 | + if (event->type == FANOTIFY_EVENT_TYPE_PATH) |
---|
| 281 | + return &FANOTIFY_PE(event)->path; |
---|
| 282 | + else if (event->type == FANOTIFY_EVENT_TYPE_PATH_PERM) |
---|
| 283 | + return &FANOTIFY_PERM(event)->path; |
---|
| 284 | + else |
---|
| 285 | + return NULL; |
---|
| 286 | +} |
---|