xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/fanotify/fanotify18.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) 2018 Matthew Bobrowski. All Rights Reserved.
4*49cdfc7eSAndroid Build Coastguard Worker  *
5*49cdfc7eSAndroid Build Coastguard Worker  * Started by Matthew Bobrowski <[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  * This set of tests is to ensure that the unprivileged listener feature of
11*49cdfc7eSAndroid Build Coastguard Worker  * fanotify is functioning as expected. The objective this test case file
12*49cdfc7eSAndroid Build Coastguard Worker  * is to validate whether any forbidden flags that are passed by an
13*49cdfc7eSAndroid Build Coastguard Worker  * unprivileged user return the correct error result.
14*49cdfc7eSAndroid Build Coastguard Worker  */
15*49cdfc7eSAndroid Build Coastguard Worker 
16*49cdfc7eSAndroid Build Coastguard Worker #define _GNU_SOURCE
17*49cdfc7eSAndroid Build Coastguard Worker #include "config.h"
18*49cdfc7eSAndroid Build Coastguard Worker 
19*49cdfc7eSAndroid Build Coastguard Worker #include <pwd.h>
20*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
21*49cdfc7eSAndroid Build Coastguard Worker #include <errno.h>
22*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
23*49cdfc7eSAndroid Build Coastguard Worker 
24*49cdfc7eSAndroid Build Coastguard Worker #ifdef HAVE_SYS_FANOTIFY_H
25*49cdfc7eSAndroid Build Coastguard Worker #include "fanotify.h"
26*49cdfc7eSAndroid Build Coastguard Worker 
27*49cdfc7eSAndroid Build Coastguard Worker /*
28*49cdfc7eSAndroid Build Coastguard Worker  * This is a set of intialization flags that are not permitted to be used by an
29*49cdfc7eSAndroid Build Coastguard Worker  * unprivileged user. Thus, if supplied, either EPERM or EINVAL should be
30*49cdfc7eSAndroid Build Coastguard Worker  * returned to the calling process respectively.
31*49cdfc7eSAndroid Build Coastguard Worker  */
32*49cdfc7eSAndroid Build Coastguard Worker #define DISALLOWED_INIT_FLAGS	(FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS | \
33*49cdfc7eSAndroid Build Coastguard Worker 				 FAN_CLASS_CONTENT | FAN_CLASS_PRE_CONTENT | \
34*49cdfc7eSAndroid Build Coastguard Worker 				 FAN_REPORT_TID)
35*49cdfc7eSAndroid Build Coastguard Worker 
36*49cdfc7eSAndroid Build Coastguard Worker /*
37*49cdfc7eSAndroid Build Coastguard Worker  * This is a set of mark flags that are not permitted to be used with an
38*49cdfc7eSAndroid Build Coastguard Worker  * unprivileged listener.
39*49cdfc7eSAndroid Build Coastguard Worker  */
40*49cdfc7eSAndroid Build Coastguard Worker #define DISALLOWED_MARK_FLAGS	(FAN_MARK_MOUNT | FAN_MARK_FILESYSTEM)
41*49cdfc7eSAndroid Build Coastguard Worker 
42*49cdfc7eSAndroid Build Coastguard Worker #define MOUNT_PATH	"fs_mnt"
43*49cdfc7eSAndroid Build Coastguard Worker #define TEST_FILE	MOUNT_PATH "/testfile"
44*49cdfc7eSAndroid Build Coastguard Worker 
45*49cdfc7eSAndroid Build Coastguard Worker static int fd_notify;
46*49cdfc7eSAndroid Build Coastguard Worker 
47*49cdfc7eSAndroid Build Coastguard Worker static struct test_case_t {
48*49cdfc7eSAndroid Build Coastguard Worker 	const char *name;
49*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long init_flags;
50*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long mark_flags;
51*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long long mark_mask;
52*49cdfc7eSAndroid Build Coastguard Worker } test_cases[] = {
53*49cdfc7eSAndroid Build Coastguard Worker 	{
54*49cdfc7eSAndroid Build Coastguard Worker 		"init_flags: missing FAN_REPORT_FID",
55*49cdfc7eSAndroid Build Coastguard Worker 		FAN_CLASS_NOTIF,
56*49cdfc7eSAndroid Build Coastguard Worker 		0, 0
57*49cdfc7eSAndroid Build Coastguard Worker 	},
58*49cdfc7eSAndroid Build Coastguard Worker 	{
59*49cdfc7eSAndroid Build Coastguard Worker 		"init_flags: FAN_CLASS_CONTENT",
60*49cdfc7eSAndroid Build Coastguard Worker 		FANOTIFY_REQUIRED_USER_INIT_FLAGS | FAN_CLASS_CONTENT,
61*49cdfc7eSAndroid Build Coastguard Worker 		0, 0
62*49cdfc7eSAndroid Build Coastguard Worker 	},
63*49cdfc7eSAndroid Build Coastguard Worker 	{
64*49cdfc7eSAndroid Build Coastguard Worker 		"init_flags: FAN_CLASS_PRE_CONTENT",
65*49cdfc7eSAndroid Build Coastguard Worker 		FANOTIFY_REQUIRED_USER_INIT_FLAGS | FAN_CLASS_PRE_CONTENT,
66*49cdfc7eSAndroid Build Coastguard Worker 		0, 0
67*49cdfc7eSAndroid Build Coastguard Worker 	},
68*49cdfc7eSAndroid Build Coastguard Worker 	{
69*49cdfc7eSAndroid Build Coastguard Worker 		"init_flags: FAN_UNLIMITED_QUEUE",
70*49cdfc7eSAndroid Build Coastguard Worker 		FANOTIFY_REQUIRED_USER_INIT_FLAGS | FAN_UNLIMITED_QUEUE,
71*49cdfc7eSAndroid Build Coastguard Worker 		0, 0
72*49cdfc7eSAndroid Build Coastguard Worker 	},
73*49cdfc7eSAndroid Build Coastguard Worker 	{
74*49cdfc7eSAndroid Build Coastguard Worker 		"init_flags: FAN_UNLIMITED_MARKS",
75*49cdfc7eSAndroid Build Coastguard Worker 		FANOTIFY_REQUIRED_USER_INIT_FLAGS | FAN_UNLIMITED_MARKS,
76*49cdfc7eSAndroid Build Coastguard Worker 		0, 0
77*49cdfc7eSAndroid Build Coastguard Worker 	},
78*49cdfc7eSAndroid Build Coastguard Worker 	{
79*49cdfc7eSAndroid Build Coastguard Worker 		"init_flags: FAN_REPORT_TID",
80*49cdfc7eSAndroid Build Coastguard Worker 		FANOTIFY_REQUIRED_USER_INIT_FLAGS | FAN_REPORT_TID,
81*49cdfc7eSAndroid Build Coastguard Worker 		0, 0
82*49cdfc7eSAndroid Build Coastguard Worker 	},
83*49cdfc7eSAndroid Build Coastguard Worker 	{
84*49cdfc7eSAndroid Build Coastguard Worker 		"init_flags: FAN_CLASS_NOTIF, "
85*49cdfc7eSAndroid Build Coastguard Worker 		"mark_flags: FAN_MARK_ADD | FAN_MARK_MOUNT",
86*49cdfc7eSAndroid Build Coastguard Worker 		FANOTIFY_REQUIRED_USER_INIT_FLAGS | FAN_CLASS_NOTIF,
87*49cdfc7eSAndroid Build Coastguard Worker 		FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_ALL_EVENTS
88*49cdfc7eSAndroid Build Coastguard Worker 	},
89*49cdfc7eSAndroid Build Coastguard Worker 	{
90*49cdfc7eSAndroid Build Coastguard Worker 		"init_flags: FAN_CLASS_NOTIF, "
91*49cdfc7eSAndroid Build Coastguard Worker 		"mark_flags: FAN_MARK_ADD | FAN_MARK_FILESYSTEM",
92*49cdfc7eSAndroid Build Coastguard Worker 		FANOTIFY_REQUIRED_USER_INIT_FLAGS | FAN_CLASS_NOTIF,
93*49cdfc7eSAndroid Build Coastguard Worker 		FAN_MARK_ADD | FAN_MARK_FILESYSTEM, FAN_ALL_EVENTS
94*49cdfc7eSAndroid Build Coastguard Worker 	},
95*49cdfc7eSAndroid Build Coastguard Worker 	{
96*49cdfc7eSAndroid Build Coastguard Worker 		"init_flags: FAN_CLASS_NOTIF, "
97*49cdfc7eSAndroid Build Coastguard Worker 		"mark_flags: FAN_MARK_ADD, "
98*49cdfc7eSAndroid Build Coastguard Worker 		"mark_mask: FAN_ALL_EVENTS",
99*49cdfc7eSAndroid Build Coastguard Worker 		FANOTIFY_REQUIRED_USER_INIT_FLAGS | FAN_CLASS_NOTIF,
100*49cdfc7eSAndroid Build Coastguard Worker 		FAN_MARK_ADD, FAN_ALL_EVENTS
101*49cdfc7eSAndroid Build Coastguard Worker 	}
102*49cdfc7eSAndroid Build Coastguard Worker };
103*49cdfc7eSAndroid Build Coastguard Worker 
test_fanotify(unsigned int n)104*49cdfc7eSAndroid Build Coastguard Worker static void test_fanotify(unsigned int n)
105*49cdfc7eSAndroid Build Coastguard Worker {
106*49cdfc7eSAndroid Build Coastguard Worker 	struct test_case_t *tc = &test_cases[n];
107*49cdfc7eSAndroid Build Coastguard Worker 
108*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "Test #%d %s", n, tc->name);
109*49cdfc7eSAndroid Build Coastguard Worker 
110*49cdfc7eSAndroid Build Coastguard Worker 	/* Initialize fanotify */
111*49cdfc7eSAndroid Build Coastguard Worker 	fd_notify = fanotify_init(tc->init_flags, O_RDONLY);
112*49cdfc7eSAndroid Build Coastguard Worker 
113*49cdfc7eSAndroid Build Coastguard Worker 	if (fd_notify < 0) {
114*49cdfc7eSAndroid Build Coastguard Worker 		if (errno == EPERM &&
115*49cdfc7eSAndroid Build Coastguard Worker 		    ((tc->init_flags & DISALLOWED_INIT_FLAGS) ||
116*49cdfc7eSAndroid Build Coastguard Worker 		     (tc->init_flags & FANOTIFY_REQUIRED_USER_INIT_FLAGS) !=
117*49cdfc7eSAndroid Build Coastguard Worker 		      FANOTIFY_REQUIRED_USER_INIT_FLAGS)) {
118*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TPASS, "Received result EPERM, as expected");
119*49cdfc7eSAndroid Build Coastguard Worker 			return;
120*49cdfc7eSAndroid Build Coastguard Worker 		}
121*49cdfc7eSAndroid Build Coastguard Worker 
122*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK | TERRNO,
123*49cdfc7eSAndroid Build Coastguard Worker 			"fanotify_init(0x%lx, O_RDONLY) failed",
124*49cdfc7eSAndroid Build Coastguard Worker 			tc->init_flags);
125*49cdfc7eSAndroid Build Coastguard Worker 	}
126*49cdfc7eSAndroid Build Coastguard Worker 
127*49cdfc7eSAndroid Build Coastguard Worker 	/* Attempt to place mark on object */
128*49cdfc7eSAndroid Build Coastguard Worker 	if (fanotify_mark(fd_notify, tc->mark_flags, tc->mark_mask, AT_FDCWD,
129*49cdfc7eSAndroid Build Coastguard Worker 				TEST_FILE) < 0) {
130*49cdfc7eSAndroid Build Coastguard Worker 		/*
131*49cdfc7eSAndroid Build Coastguard Worker 		 * Unprivileged users are only allowed to mark inodes and not
132*49cdfc7eSAndroid Build Coastguard Worker 		 * permitted to use access permissions
133*49cdfc7eSAndroid Build Coastguard Worker 		 */
134*49cdfc7eSAndroid Build Coastguard Worker 		if (errno == EPERM &&
135*49cdfc7eSAndroid Build Coastguard Worker 			(tc->mark_flags & DISALLOWED_MARK_FLAGS ||
136*49cdfc7eSAndroid Build Coastguard Worker 			 tc->mark_mask & FAN_ALL_PERM_EVENTS)) {
137*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TPASS, "Received result EPERM, as expected");
138*49cdfc7eSAndroid Build Coastguard Worker 			goto out;
139*49cdfc7eSAndroid Build Coastguard Worker 		}
140*49cdfc7eSAndroid Build Coastguard Worker 
141*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK | TERRNO,
142*49cdfc7eSAndroid Build Coastguard Worker 			"fanotify_mark(%d, %lx, %llx, AT_FDCWD, %s) "
143*49cdfc7eSAndroid Build Coastguard Worker 			"failed",
144*49cdfc7eSAndroid Build Coastguard Worker 			fd_notify,
145*49cdfc7eSAndroid Build Coastguard Worker 			tc->mark_flags,
146*49cdfc7eSAndroid Build Coastguard Worker 			tc->mark_mask,
147*49cdfc7eSAndroid Build Coastguard Worker 			TEST_FILE);
148*49cdfc7eSAndroid Build Coastguard Worker 	}
149*49cdfc7eSAndroid Build Coastguard Worker 
150*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TPASS,
151*49cdfc7eSAndroid Build Coastguard Worker 		"fanotify_init() and fanotify_mark() returned successfully, "
152*49cdfc7eSAndroid Build Coastguard Worker 		"as expected");
153*49cdfc7eSAndroid Build Coastguard Worker 
154*49cdfc7eSAndroid Build Coastguard Worker out:
155*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_CLOSE(fd_notify);
156*49cdfc7eSAndroid Build Coastguard Worker }
157*49cdfc7eSAndroid Build Coastguard Worker 
setup(void)158*49cdfc7eSAndroid Build Coastguard Worker static void setup(void)
159*49cdfc7eSAndroid Build Coastguard Worker {
160*49cdfc7eSAndroid Build Coastguard Worker 	int fd;
161*49cdfc7eSAndroid Build Coastguard Worker 	struct passwd *nobody;
162*49cdfc7eSAndroid Build Coastguard Worker 
163*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_TOUCH(TEST_FILE, 0666, NULL);
164*49cdfc7eSAndroid Build Coastguard Worker 
165*49cdfc7eSAndroid Build Coastguard Worker 	/* Check for kernel fanotify support */
166*49cdfc7eSAndroid Build Coastguard Worker 	REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_FID, TEST_FILE);
167*49cdfc7eSAndroid Build Coastguard Worker 
168*49cdfc7eSAndroid Build Coastguard Worker 	/* Relinquish privileged user */
169*49cdfc7eSAndroid Build Coastguard Worker 	if (geteuid() == 0) {
170*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO,
171*49cdfc7eSAndroid Build Coastguard Worker 			"Running as privileged user, revoking permissions.");
172*49cdfc7eSAndroid Build Coastguard Worker 		nobody = SAFE_GETPWNAM("nobody");
173*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_SETUID(nobody->pw_uid);
174*49cdfc7eSAndroid Build Coastguard Worker 	}
175*49cdfc7eSAndroid Build Coastguard Worker 
176*49cdfc7eSAndroid Build Coastguard Worker 	/* Check for unprivileged fanotify support */
177*49cdfc7eSAndroid Build Coastguard Worker 	fd = fanotify_init(FANOTIFY_REQUIRED_USER_INIT_FLAGS, O_RDONLY);
178*49cdfc7eSAndroid Build Coastguard Worker 	if (fd < 0) {
179*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TCONF,
180*49cdfc7eSAndroid Build Coastguard Worker 			"unprivileged fanotify not supported by kernel?");
181*49cdfc7eSAndroid Build Coastguard Worker 	}
182*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_CLOSE(fd);
183*49cdfc7eSAndroid Build Coastguard Worker }
184*49cdfc7eSAndroid Build Coastguard Worker 
cleanup(void)185*49cdfc7eSAndroid Build Coastguard Worker static void cleanup(void)
186*49cdfc7eSAndroid Build Coastguard Worker {
187*49cdfc7eSAndroid Build Coastguard Worker 	if (fd_notify > 0)
188*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(fd_notify);
189*49cdfc7eSAndroid Build Coastguard Worker }
190*49cdfc7eSAndroid Build Coastguard Worker 
191*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
192*49cdfc7eSAndroid Build Coastguard Worker 	.test = test_fanotify,
193*49cdfc7eSAndroid Build Coastguard Worker 	.tcnt = ARRAY_SIZE(test_cases),
194*49cdfc7eSAndroid Build Coastguard Worker 	.setup = setup,
195*49cdfc7eSAndroid Build Coastguard Worker 	.cleanup = cleanup,
196*49cdfc7eSAndroid Build Coastguard Worker 	.needs_root = 1,
197*49cdfc7eSAndroid Build Coastguard Worker 	.mount_device = 1,
198*49cdfc7eSAndroid Build Coastguard Worker 	.mntpoint = MOUNT_PATH,
199*49cdfc7eSAndroid Build Coastguard Worker };
200*49cdfc7eSAndroid Build Coastguard Worker 
201*49cdfc7eSAndroid Build Coastguard Worker #else
202*49cdfc7eSAndroid Build Coastguard Worker 	TST_TEST_TCONF("system doesn't have required fanotify support");
203*49cdfc7eSAndroid Build Coastguard Worker #endif
204