• 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  * 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