• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2018 Matthew Bobrowski. All Rights Reserved.
4  *
5  * Started by Matthew Bobrowski <mbobrowski@mbobrowski.org>
6  */
7 
8 /*\
9  * [Description]
10  * This test file has been designed to ensure that the fanotify
11  * system calls fanotify_init(2) and fanotify_mark(2) return the
12  * correct error code to the calling process when an invalid flag or
13  * mask value has been specified in conjunction with FAN_REPORT_FID.
14  */
15 
16 #define _GNU_SOURCE
17 #include "tst_test.h"
18 #include <errno.h>
19 
20 #ifdef HAVE_SYS_FANOTIFY_H
21 #include "fanotify.h"
22 
23 #define MNTPOINT "mntpoint"
24 #define FILE1 MNTPOINT"/file1"
25 
26 /*
27  * List of inode events that are only available when notification group is
28  * set to report fid.
29  */
30 #define INODE_EVENTS (FAN_ATTRIB | FAN_CREATE | FAN_DELETE | FAN_MOVE | \
31 		      FAN_DELETE_SELF | FAN_MOVE_SELF)
32 
33 static int fanotify_fd;
34 
35 /*
36  * Each test case has been designed in a manner whereby the values defined
37  * within should result in the interface to return an error to the calling
38  * process.
39  */
40 static struct test_case_t {
41 	unsigned int init_flags;
42 	unsigned int mark_flags;
43 	unsigned long long mask;
44 } test_cases[] = {
45 	{
46 		FAN_CLASS_CONTENT | FAN_REPORT_FID, 0, 0
47 	},
48 	{
49 		FAN_CLASS_PRE_CONTENT | FAN_REPORT_FID, 0, 0
50 	},
51 	{
52 		FAN_CLASS_NOTIF, 0, INODE_EVENTS
53 	},
54 	{
55 		FAN_CLASS_NOTIF | FAN_REPORT_FID, FAN_MARK_MOUNT, INODE_EVENTS
56 	},
57 	{
58 		/* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */
59 		FAN_CLASS_NOTIF | FAN_REPORT_NAME, 0, 0
60 	},
61 	{
62 		/* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */
63 		FAN_CLASS_NOTIF | FAN_REPORT_FID | FAN_REPORT_NAME, 0, 0
64 	},
65 };
66 
do_test(unsigned int number)67 static void do_test(unsigned int number)
68 {
69 	int ret;
70 	struct test_case_t *tc = &test_cases[number];
71 
72 	fanotify_fd = fanotify_init(tc->init_flags, O_RDONLY);
73 	if (fanotify_fd < 0) {
74 		/*
75 		 * EINVAL is to be returned to the calling process when
76 		 * an invalid notification class is specified in
77 		 * conjunction with FAN_REPORT_FID.
78 		 */
79 		if (errno == EINVAL) {
80 			tst_res(TPASS,
81 				"fanotify_fd=%d, fanotify_init(%x, O_RDONLY) "
82 				"failed with error EINVAL as expected",
83 				fanotify_fd,
84 				tc->init_flags);
85 			return;
86 		}
87 		tst_brk(TBROK | TERRNO,
88 			"fanotify_fd=%d, fanotify_init(%x, O_RDONLY) failed",
89 			fanotify_fd,
90 			tc->init_flags);
91 	}
92 
93 	/*
94 	 * A test case with a mask set to zero indicate that they've been
95 	 * specifically designed to test and fail on the fanotify_init()
96 	 * system call.
97 	 */
98 	if (tc->mask == 0) {
99 		tst_res(TFAIL,
100 			"fanotify_fd=%d fanotify_init(%x, O_RDONLY) "
101 			"unexpectedly succeeded when tests with mask 0 are "
102 			"expected to fail when calling fanotify_init()",
103 			fanotify_fd,
104 			tc->init_flags);
105 		goto out;
106 	}
107 
108 	ret = fanotify_mark(fanotify_fd, FAN_MARK_ADD | tc->mark_flags,
109 				tc->mask, AT_FDCWD, FILE1);
110 	if (ret < 0) {
111 		/*
112 		 * EINVAL is to be returned to the calling process when
113 		 * attempting to use INODE_EVENTS without FAN_REPORT_FID
114 		 * specified on the notification group, or using
115 		 * INODE_EVENTS with mark type FAN_MARK_MOUNT.
116 		 */
117 		if (errno == EINVAL) {
118 			tst_res(TPASS,
119 				"ret=%d, fanotify_mark(%d, FAN_MARK_ADD | %x, "
120 				"%llx, AT_FDCWD, %s) failed with error EINVAL "
121 				"as expected",
122 				ret,
123 				fanotify_fd,
124 				tc->mark_flags,
125 				tc->mask,
126 				FILE1);
127 			goto out;
128 		}
129 		tst_brk(TBROK | TERRNO,
130 			"ret=%d, fanotify_mark(%d, FAN_MARK_ADD | %x, %llx, "
131 			"AT_FDCWD, %s) failed",
132 			ret,
133 			fanotify_fd,
134 			tc->mark_flags,
135 			tc->mask,
136 			FILE1);
137 	}
138 
139 	tst_res(TFAIL,
140 		"fanotify_fd=%d, ret=%d, fanotify_init(%x, O_RDONLY) and "
141 		"fanotify_mark(%d, FAN_MARK_ADD | %x, %llx, AT_FDCWD, %s) did "
142 		"not return any errors as expected",
143 		fanotify_fd,
144 		ret,
145 		tc->init_flags,
146 		fanotify_fd,
147 		tc->mark_flags,
148 		tc->mask,
149 		FILE1);
150 out:
151 	SAFE_CLOSE(fanotify_fd);
152 }
153 
do_setup(void)154 static void do_setup(void)
155 {
156 	int fd;
157 
158 	/* Check for kernel fanotify support */
159 	fd = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF, O_RDONLY);
160 	SAFE_CLOSE(fd);
161 
162 	/* Create temporary test file to place marks on */
163 	SAFE_FILE_PRINTF(FILE1, "0");
164 }
165 
do_cleanup(void)166 static void do_cleanup(void)
167 {
168 	if (fanotify_fd > 0)
169 		SAFE_CLOSE(fanotify_fd);
170 }
171 
172 static struct tst_test test = {
173 	.needs_root = 1,
174 	.test = do_test,
175 	.tcnt = ARRAY_SIZE(test_cases),
176 	.setup = do_setup,
177 	.cleanup = do_cleanup,
178 	.mount_device = 1,
179 	.mntpoint = MNTPOINT,
180 	.all_filesystems = 1
181 };
182 
183 #else
184 	TST_TEST_TCONF("System does not have required fanotify support");
185 #endif
186