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