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