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
7extern struct kmem_cache *fanotify_mark_cache;
8extern struct kmem_cache *fanotify_fid_event_cachep;
9extern struct kmem_cache *fanotify_path_event_cachep;
10extern struct kmem_cache *fanotify_perm_event_cachep;
11
12/* Possible states of the permission event */
13enum {
14	FAN_EVENT_INIT,
15	FAN_EVENT_REPORTED,
16	FAN_EVENT_ANSWERED,
17	FAN_EVENT_CANCELED,
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 */
29struct 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 */
39struct 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
53static inline bool fanotify_fh_has_ext_buf(struct fanotify_fh *fh)
54{
55	return (fh->flags & FANOTIFY_FH_FLAG_EXT_BUF);
56}
57
58static 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
66static inline void *fanotify_fh_ext_buf(struct fanotify_fh *fh)
67{
68	return *fanotify_fh_ext_buf_ptr(fh);
69}
70
71static 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
76static 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
85static 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
92static 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
101static 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
106static 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
111static 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
118static 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 */
132enum 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
140struct fanotify_event {
141	struct fsnotify_event fse;
142	u32 mask;
143	enum fanotify_event_type type;
144	struct pid *pid;
145};
146
147static 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
155struct 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
163static inline struct fanotify_fid_event *
164FANOTIFY_FE(struct fanotify_event *event)
165{
166	return container_of(event, struct fanotify_fid_event, fae);
167}
168
169struct fanotify_name_event {
170	struct fanotify_event fae;
171	__kernel_fsid_t fsid;
172	struct fanotify_info info;
173};
174
175static inline struct fanotify_name_event *
176FANOTIFY_NE(struct fanotify_event *event)
177{
178	return container_of(event, struct fanotify_name_event, fae);
179}
180
181static 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
191static 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
202static 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
211static 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
222static 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
229struct fanotify_path_event {
230	struct fanotify_event fae;
231	struct path path;
232};
233
234static inline struct fanotify_path_event *
235FANOTIFY_PE(struct fanotify_event *event)
236{
237	return container_of(event, struct fanotify_path_event, fae);
238}
239
240/*
241 * Structure for permission fanotify events. It gets allocated and freed in
242 * fanotify_handle_event() since we wait there for user response. When the
243 * information is retrieved by userspace the structure is moved from
244 * group->notification_list to group->fanotify_data.access_list to wait for
245 * user response.
246 */
247struct 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 */
252	int fd;		/* fd we passed to userspace for this event */
253};
254
255static inline struct fanotify_perm_event *
256FANOTIFY_PERM(struct fanotify_event *event)
257{
258	return container_of(event, struct fanotify_perm_event, fae);
259}
260
261static inline bool fanotify_is_perm_event(u32 mask)
262{
263	return IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS) &&
264		mask & FANOTIFY_PERM_EVENTS;
265}
266
267static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse)
268{
269	return container_of(fse, struct fanotify_event, fse);
270}
271
272static 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
278static 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}
287