xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/fanotify/fanotify06.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2014 SUSE.  All Rights Reserved.
4*49cdfc7eSAndroid Build Coastguard Worker  *
5*49cdfc7eSAndroid Build Coastguard Worker  * Started by Jan Kara <[email protected]>
6*49cdfc7eSAndroid Build Coastguard Worker  */
7*49cdfc7eSAndroid Build Coastguard Worker 
8*49cdfc7eSAndroid Build Coastguard Worker /*\
9*49cdfc7eSAndroid Build Coastguard Worker  * [Description]
10*49cdfc7eSAndroid Build Coastguard Worker  * Check that fanotify properly merges ignore mask of an inode and mountpoint.
11*49cdfc7eSAndroid Build Coastguard Worker  */
12*49cdfc7eSAndroid Build Coastguard Worker 
13*49cdfc7eSAndroid Build Coastguard Worker /*
14*49cdfc7eSAndroid Build Coastguard Worker  * This is a regression test for:
15*49cdfc7eSAndroid Build Coastguard Worker  *
16*49cdfc7eSAndroid Build Coastguard Worker  *  commit 8edc6e1688fc8f02c8c1f53a2ec4928cb1055f4d
17*49cdfc7eSAndroid Build Coastguard Worker  *  Author: Jan Kara <[email protected]>
18*49cdfc7eSAndroid Build Coastguard Worker  *  Date:   Thu Nov 13 15:19:33 2014 -0800
19*49cdfc7eSAndroid Build Coastguard Worker  *
20*49cdfc7eSAndroid Build Coastguard Worker  *      fanotify: fix notification of groups with inode & mount marks
21*49cdfc7eSAndroid Build Coastguard Worker  *
22*49cdfc7eSAndroid Build Coastguard Worker  * The overlayfs test case is a regression test for:
23*49cdfc7eSAndroid Build Coastguard Worker  *
24*49cdfc7eSAndroid Build Coastguard Worker  *  commit d989903058a83e8536cc7aadf9256a47d5c173fe
25*49cdfc7eSAndroid Build Coastguard Worker  *  Author: Amir Goldstein <[email protected]>
26*49cdfc7eSAndroid Build Coastguard Worker  *  Date:   Wed Apr 24 19:39:50 2019 +0300
27*49cdfc7eSAndroid Build Coastguard Worker  *
28*49cdfc7eSAndroid Build Coastguard Worker  *      ovl: do not generate duplicate fsnotify events for "fake" path
29*49cdfc7eSAndroid Build Coastguard Worker  */
30*49cdfc7eSAndroid Build Coastguard Worker 
31*49cdfc7eSAndroid Build Coastguard Worker #define _GNU_SOURCE
32*49cdfc7eSAndroid Build Coastguard Worker #include "config.h"
33*49cdfc7eSAndroid Build Coastguard Worker 
34*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
35*49cdfc7eSAndroid Build Coastguard Worker #include <sys/stat.h>
36*49cdfc7eSAndroid Build Coastguard Worker #include <sys/types.h>
37*49cdfc7eSAndroid Build Coastguard Worker #include <errno.h>
38*49cdfc7eSAndroid Build Coastguard Worker #include <string.h>
39*49cdfc7eSAndroid Build Coastguard Worker #include <sys/mount.h>
40*49cdfc7eSAndroid Build Coastguard Worker #include <sys/syscall.h>
41*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
42*49cdfc7eSAndroid Build Coastguard Worker 
43*49cdfc7eSAndroid Build Coastguard Worker #ifdef HAVE_SYS_FANOTIFY_H
44*49cdfc7eSAndroid Build Coastguard Worker #include "fanotify.h"
45*49cdfc7eSAndroid Build Coastguard Worker 
46*49cdfc7eSAndroid Build Coastguard Worker #define EVENT_MAX 1024
47*49cdfc7eSAndroid Build Coastguard Worker /* size of the event structure, not counting name */
48*49cdfc7eSAndroid Build Coastguard Worker #define EVENT_SIZE  (sizeof(struct fanotify_event_metadata))
49*49cdfc7eSAndroid Build Coastguard Worker /* reasonable guess as to size of 1024 events */
50*49cdfc7eSAndroid Build Coastguard Worker #define EVENT_BUF_LEN        (EVENT_MAX * EVENT_SIZE)
51*49cdfc7eSAndroid Build Coastguard Worker 
52*49cdfc7eSAndroid Build Coastguard Worker static unsigned int fanotify_prio[] = {
53*49cdfc7eSAndroid Build Coastguard Worker 	FAN_CLASS_PRE_CONTENT,
54*49cdfc7eSAndroid Build Coastguard Worker 	FAN_CLASS_CONTENT,
55*49cdfc7eSAndroid Build Coastguard Worker 	FAN_CLASS_NOTIF
56*49cdfc7eSAndroid Build Coastguard Worker };
57*49cdfc7eSAndroid Build Coastguard Worker #define FANOTIFY_PRIORITIES ARRAY_SIZE(fanotify_prio)
58*49cdfc7eSAndroid Build Coastguard Worker 
59*49cdfc7eSAndroid Build Coastguard Worker #define GROUPS_PER_PRIO 3
60*49cdfc7eSAndroid Build Coastguard Worker 
61*49cdfc7eSAndroid Build Coastguard Worker #define BUF_SIZE 256
62*49cdfc7eSAndroid Build Coastguard Worker static char fname[BUF_SIZE];
63*49cdfc7eSAndroid Build Coastguard Worker static int fd_notify[FANOTIFY_PRIORITIES][GROUPS_PER_PRIO];
64*49cdfc7eSAndroid Build Coastguard Worker 
65*49cdfc7eSAndroid Build Coastguard Worker static char event_buf[EVENT_BUF_LEN];
66*49cdfc7eSAndroid Build Coastguard Worker 
67*49cdfc7eSAndroid Build Coastguard Worker static const char mntpoint[] = OVL_BASE_MNTPOINT;
68*49cdfc7eSAndroid Build Coastguard Worker 
69*49cdfc7eSAndroid Build Coastguard Worker static int ovl_mounted;
70*49cdfc7eSAndroid Build Coastguard Worker 
71*49cdfc7eSAndroid Build Coastguard Worker static struct tcase {
72*49cdfc7eSAndroid Build Coastguard Worker 	const char *tname;
73*49cdfc7eSAndroid Build Coastguard Worker 	const char *mnt;
74*49cdfc7eSAndroid Build Coastguard Worker 	int use_overlay;
75*49cdfc7eSAndroid Build Coastguard Worker } tcases[] = {
76*49cdfc7eSAndroid Build Coastguard Worker 	{ "Fanotify merge mount mark", mntpoint, 0 },
77*49cdfc7eSAndroid Build Coastguard Worker 	{ "Fanotify merge overlayfs mount mark", OVL_MNT, 1 },
78*49cdfc7eSAndroid Build Coastguard Worker };
79*49cdfc7eSAndroid Build Coastguard Worker 
create_fanotify_groups(void)80*49cdfc7eSAndroid Build Coastguard Worker static void create_fanotify_groups(void)
81*49cdfc7eSAndroid Build Coastguard Worker {
82*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int p, i;
83*49cdfc7eSAndroid Build Coastguard Worker 
84*49cdfc7eSAndroid Build Coastguard Worker 	for (p = 0; p < FANOTIFY_PRIORITIES; p++) {
85*49cdfc7eSAndroid Build Coastguard Worker 		for (i = 0; i < GROUPS_PER_PRIO; i++) {
86*49cdfc7eSAndroid Build Coastguard Worker 			fd_notify[p][i] = SAFE_FANOTIFY_INIT(fanotify_prio[p] |
87*49cdfc7eSAndroid Build Coastguard Worker 							     FAN_NONBLOCK,
88*49cdfc7eSAndroid Build Coastguard Worker 							     O_RDONLY);
89*49cdfc7eSAndroid Build Coastguard Worker 
90*49cdfc7eSAndroid Build Coastguard Worker 			/* Add mount mark for each group */
91*49cdfc7eSAndroid Build Coastguard Worker 			SAFE_FANOTIFY_MARK(fd_notify[p][i],
92*49cdfc7eSAndroid Build Coastguard Worker 					    FAN_MARK_ADD | FAN_MARK_MOUNT,
93*49cdfc7eSAndroid Build Coastguard Worker 					    FAN_MODIFY,
94*49cdfc7eSAndroid Build Coastguard Worker 					    AT_FDCWD, fname);
95*49cdfc7eSAndroid Build Coastguard Worker 
96*49cdfc7eSAndroid Build Coastguard Worker 			/* Add ignore mark for groups with higher priority */
97*49cdfc7eSAndroid Build Coastguard Worker 			if (p == 0)
98*49cdfc7eSAndroid Build Coastguard Worker 				continue;
99*49cdfc7eSAndroid Build Coastguard Worker 
100*49cdfc7eSAndroid Build Coastguard Worker 			SAFE_FANOTIFY_MARK(fd_notify[p][i],
101*49cdfc7eSAndroid Build Coastguard Worker 					    FAN_MARK_ADD |
102*49cdfc7eSAndroid Build Coastguard Worker 					    FAN_MARK_IGNORED_MASK |
103*49cdfc7eSAndroid Build Coastguard Worker 					    FAN_MARK_IGNORED_SURV_MODIFY,
104*49cdfc7eSAndroid Build Coastguard Worker 					    FAN_MODIFY, AT_FDCWD, fname);
105*49cdfc7eSAndroid Build Coastguard Worker 		}
106*49cdfc7eSAndroid Build Coastguard Worker 	}
107*49cdfc7eSAndroid Build Coastguard Worker }
108*49cdfc7eSAndroid Build Coastguard Worker 
cleanup_fanotify_groups(void)109*49cdfc7eSAndroid Build Coastguard Worker static void cleanup_fanotify_groups(void)
110*49cdfc7eSAndroid Build Coastguard Worker {
111*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int i, p;
112*49cdfc7eSAndroid Build Coastguard Worker 
113*49cdfc7eSAndroid Build Coastguard Worker 	for (p = 0; p < FANOTIFY_PRIORITIES; p++) {
114*49cdfc7eSAndroid Build Coastguard Worker 		for (i = 0; i < GROUPS_PER_PRIO; i++) {
115*49cdfc7eSAndroid Build Coastguard Worker 			if (fd_notify[p][i] > 0)
116*49cdfc7eSAndroid Build Coastguard Worker 				SAFE_CLOSE(fd_notify[p][i]);
117*49cdfc7eSAndroid Build Coastguard Worker 		}
118*49cdfc7eSAndroid Build Coastguard Worker 	}
119*49cdfc7eSAndroid Build Coastguard Worker }
120*49cdfc7eSAndroid Build Coastguard Worker 
verify_event(int group,struct fanotify_event_metadata * event)121*49cdfc7eSAndroid Build Coastguard Worker static void verify_event(int group, struct fanotify_event_metadata *event)
122*49cdfc7eSAndroid Build Coastguard Worker {
123*49cdfc7eSAndroid Build Coastguard Worker 	if (event->mask != FAN_MODIFY) {
124*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TFAIL, "group %d got event: mask %llx (expected %llx) "
125*49cdfc7eSAndroid Build Coastguard Worker 			"pid=%u fd=%d", group, (unsigned long long)event->mask,
126*49cdfc7eSAndroid Build Coastguard Worker 			(unsigned long long)FAN_MODIFY,
127*49cdfc7eSAndroid Build Coastguard Worker 			(unsigned int)event->pid, event->fd);
128*49cdfc7eSAndroid Build Coastguard Worker 	} else if (event->pid != getpid()) {
129*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TFAIL, "group %d got event: mask %llx pid=%u "
130*49cdfc7eSAndroid Build Coastguard Worker 			"(expected %u) fd=%d", group,
131*49cdfc7eSAndroid Build Coastguard Worker 			(unsigned long long)event->mask, (unsigned int)event->pid,
132*49cdfc7eSAndroid Build Coastguard Worker 			(unsigned int)getpid(), event->fd);
133*49cdfc7eSAndroid Build Coastguard Worker 	} else {
134*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TPASS, "group %d got event: mask %llx pid=%u fd=%d",
135*49cdfc7eSAndroid Build Coastguard Worker 			group, (unsigned long long)event->mask,
136*49cdfc7eSAndroid Build Coastguard Worker 			(unsigned int)event->pid, event->fd);
137*49cdfc7eSAndroid Build Coastguard Worker 	}
138*49cdfc7eSAndroid Build Coastguard Worker }
139*49cdfc7eSAndroid Build Coastguard Worker 
140*49cdfc7eSAndroid Build Coastguard Worker /* Close all file descriptors of read events */
close_events_fd(struct fanotify_event_metadata * event,int buflen)141*49cdfc7eSAndroid Build Coastguard Worker static void close_events_fd(struct fanotify_event_metadata *event, int buflen)
142*49cdfc7eSAndroid Build Coastguard Worker {
143*49cdfc7eSAndroid Build Coastguard Worker 	while (buflen >= (int)FAN_EVENT_METADATA_LEN) {
144*49cdfc7eSAndroid Build Coastguard Worker 		if (event->fd != FAN_NOFD)
145*49cdfc7eSAndroid Build Coastguard Worker 			SAFE_CLOSE(event->fd);
146*49cdfc7eSAndroid Build Coastguard Worker 		buflen -= (int)FAN_EVENT_METADATA_LEN;
147*49cdfc7eSAndroid Build Coastguard Worker 		event++;
148*49cdfc7eSAndroid Build Coastguard Worker 	}
149*49cdfc7eSAndroid Build Coastguard Worker }
150*49cdfc7eSAndroid Build Coastguard Worker 
test_fanotify(unsigned int n)151*49cdfc7eSAndroid Build Coastguard Worker static void test_fanotify(unsigned int n)
152*49cdfc7eSAndroid Build Coastguard Worker {
153*49cdfc7eSAndroid Build Coastguard Worker 	int ret;
154*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int p, i;
155*49cdfc7eSAndroid Build Coastguard Worker 	struct fanotify_event_metadata *event;
156*49cdfc7eSAndroid Build Coastguard Worker 	struct tcase *tc = &tcases[n];
157*49cdfc7eSAndroid Build Coastguard Worker 
158*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "Test #%d: %s", n, tc->tname);
159*49cdfc7eSAndroid Build Coastguard Worker 
160*49cdfc7eSAndroid Build Coastguard Worker 	if (tc->use_overlay && !ovl_mounted) {
161*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TCONF, "overlayfs is not configured in this kernel");
162*49cdfc7eSAndroid Build Coastguard Worker 		return;
163*49cdfc7eSAndroid Build Coastguard Worker 	}
164*49cdfc7eSAndroid Build Coastguard Worker 
165*49cdfc7eSAndroid Build Coastguard Worker 	sprintf(fname, "%s/tfile_%d", tc->mnt, getpid());
166*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_TOUCH(fname, 0644, NULL);
167*49cdfc7eSAndroid Build Coastguard Worker 
168*49cdfc7eSAndroid Build Coastguard Worker 	create_fanotify_groups();
169*49cdfc7eSAndroid Build Coastguard Worker 
170*49cdfc7eSAndroid Build Coastguard Worker 	/*
171*49cdfc7eSAndroid Build Coastguard Worker 	 * generate sequence of events
172*49cdfc7eSAndroid Build Coastguard Worker 	 */
173*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FILE_PRINTF(fname, "1");
174*49cdfc7eSAndroid Build Coastguard Worker 
175*49cdfc7eSAndroid Build Coastguard Worker 	/* First verify all groups without ignore mask got the event */
176*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < GROUPS_PER_PRIO; i++) {
177*49cdfc7eSAndroid Build Coastguard Worker 		ret = read(fd_notify[0][i], event_buf, EVENT_BUF_LEN);
178*49cdfc7eSAndroid Build Coastguard Worker 		if (ret < 0) {
179*49cdfc7eSAndroid Build Coastguard Worker 			if (errno == EAGAIN) {
180*49cdfc7eSAndroid Build Coastguard Worker 				tst_res(TFAIL, "group %d did not get "
181*49cdfc7eSAndroid Build Coastguard Worker 					"event", i);
182*49cdfc7eSAndroid Build Coastguard Worker 			}
183*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK | TERRNO,
184*49cdfc7eSAndroid Build Coastguard Worker 				"reading fanotify events failed");
185*49cdfc7eSAndroid Build Coastguard Worker 		}
186*49cdfc7eSAndroid Build Coastguard Worker 		if (ret < (int)FAN_EVENT_METADATA_LEN) {
187*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK,
188*49cdfc7eSAndroid Build Coastguard Worker 				"short read when reading fanotify "
189*49cdfc7eSAndroid Build Coastguard Worker 				"events (%d < %d)", ret,
190*49cdfc7eSAndroid Build Coastguard Worker 				(int)EVENT_BUF_LEN);
191*49cdfc7eSAndroid Build Coastguard Worker 		}
192*49cdfc7eSAndroid Build Coastguard Worker 		event = (struct fanotify_event_metadata *)event_buf;
193*49cdfc7eSAndroid Build Coastguard Worker 		if (ret > (int)event->event_len) {
194*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TFAIL, "group %d got more than one "
195*49cdfc7eSAndroid Build Coastguard Worker 				"event (%d > %d)", i, ret,
196*49cdfc7eSAndroid Build Coastguard Worker 				event->event_len);
197*49cdfc7eSAndroid Build Coastguard Worker 		} else {
198*49cdfc7eSAndroid Build Coastguard Worker 			verify_event(i, event);
199*49cdfc7eSAndroid Build Coastguard Worker 		}
200*49cdfc7eSAndroid Build Coastguard Worker 		close_events_fd(event, ret);
201*49cdfc7eSAndroid Build Coastguard Worker 	}
202*49cdfc7eSAndroid Build Coastguard Worker 
203*49cdfc7eSAndroid Build Coastguard Worker 	for (p = 1; p < FANOTIFY_PRIORITIES; p++) {
204*49cdfc7eSAndroid Build Coastguard Worker 		for (i = 0; i < GROUPS_PER_PRIO; i++) {
205*49cdfc7eSAndroid Build Coastguard Worker 			ret = read(fd_notify[p][i], event_buf, EVENT_BUF_LEN);
206*49cdfc7eSAndroid Build Coastguard Worker 			if (ret > 0) {
207*49cdfc7eSAndroid Build Coastguard Worker 				tst_res(TFAIL, "group %d got event",
208*49cdfc7eSAndroid Build Coastguard Worker 					p*GROUPS_PER_PRIO + i);
209*49cdfc7eSAndroid Build Coastguard Worker 				close_events_fd((void *)event_buf, ret);
210*49cdfc7eSAndroid Build Coastguard Worker 			} else if (ret == 0) {
211*49cdfc7eSAndroid Build Coastguard Worker 				tst_brk(TBROK, "zero length "
212*49cdfc7eSAndroid Build Coastguard Worker 					"read from fanotify fd");
213*49cdfc7eSAndroid Build Coastguard Worker 			} else if (errno != EAGAIN) {
214*49cdfc7eSAndroid Build Coastguard Worker 				tst_brk(TBROK | TERRNO,
215*49cdfc7eSAndroid Build Coastguard Worker 					"reading fanotify events failed");
216*49cdfc7eSAndroid Build Coastguard Worker 			} else {
217*49cdfc7eSAndroid Build Coastguard Worker 				tst_res(TPASS, "group %d got no event",
218*49cdfc7eSAndroid Build Coastguard Worker 					p*GROUPS_PER_PRIO + i);
219*49cdfc7eSAndroid Build Coastguard Worker 			}
220*49cdfc7eSAndroid Build Coastguard Worker 		}
221*49cdfc7eSAndroid Build Coastguard Worker 	}
222*49cdfc7eSAndroid Build Coastguard Worker 	cleanup_fanotify_groups();
223*49cdfc7eSAndroid Build Coastguard Worker }
224*49cdfc7eSAndroid Build Coastguard Worker 
setup(void)225*49cdfc7eSAndroid Build Coastguard Worker static void setup(void)
226*49cdfc7eSAndroid Build Coastguard Worker {
227*49cdfc7eSAndroid Build Coastguard Worker 	ovl_mounted = TST_MOUNT_OVERLAY();
228*49cdfc7eSAndroid Build Coastguard Worker }
229*49cdfc7eSAndroid Build Coastguard Worker 
cleanup(void)230*49cdfc7eSAndroid Build Coastguard Worker static void cleanup(void)
231*49cdfc7eSAndroid Build Coastguard Worker {
232*49cdfc7eSAndroid Build Coastguard Worker 	cleanup_fanotify_groups();
233*49cdfc7eSAndroid Build Coastguard Worker 
234*49cdfc7eSAndroid Build Coastguard Worker 	if (ovl_mounted)
235*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_UMOUNT(OVL_MNT);
236*49cdfc7eSAndroid Build Coastguard Worker }
237*49cdfc7eSAndroid Build Coastguard Worker 
238*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
239*49cdfc7eSAndroid Build Coastguard Worker 	.test = test_fanotify,
240*49cdfc7eSAndroid Build Coastguard Worker 	.tcnt = ARRAY_SIZE(tcases),
241*49cdfc7eSAndroid Build Coastguard Worker 	.setup = setup,
242*49cdfc7eSAndroid Build Coastguard Worker 	.cleanup = cleanup,
243*49cdfc7eSAndroid Build Coastguard Worker 	.needs_root = 1,
244*49cdfc7eSAndroid Build Coastguard Worker 	.mount_device = 1,
245*49cdfc7eSAndroid Build Coastguard Worker 	.mntpoint = mntpoint,
246*49cdfc7eSAndroid Build Coastguard Worker 	.tags = (const struct tst_tag[]) {
247*49cdfc7eSAndroid Build Coastguard Worker 		{"linux-git", "8edc6e1688fc"},
248*49cdfc7eSAndroid Build Coastguard Worker 		{"linux-git", "d989903058a8"},
249*49cdfc7eSAndroid Build Coastguard Worker 		{}
250*49cdfc7eSAndroid Build Coastguard Worker 	}
251*49cdfc7eSAndroid Build Coastguard Worker };
252*49cdfc7eSAndroid Build Coastguard Worker 
253*49cdfc7eSAndroid Build Coastguard Worker #else
254*49cdfc7eSAndroid Build Coastguard Worker 	TST_TEST_TCONF("system doesn't have required fanotify support");
255*49cdfc7eSAndroid Build Coastguard Worker #endif
256