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