xref: /freebsd/tests/sys/audit/file-attribute-access.c (revision ae19b2ef9bd4ec7ac27230b8eb393f0aaf243e2c)
1 /*-
2  * Copyright (c) 2018 Aniket Pandey
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27 
28 #include <sys/param.h>
29 #include <sys/ucred.h>
30 #include <sys/mount.h>
31 #include <sys/stat.h>
32 #include <sys/syscall.h>
33 
34 #include <atf-c.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 
38 #include "utils.h"
39 
40 static struct pollfd fds[1];
41 static mode_t mode = 0777;
42 static pid_t pid;
43 static int filedesc;
44 static char extregex[80];
45 static struct stat statbuff;
46 static struct statfs statfsbuff;
47 static const char *auclass = "fa";
48 static const char *path = "fileforaudit";
49 static const char *errpath = "dirdoesnotexist/fileforaudit";
50 static const char *successreg = "fileforaudit.*return,success";
51 static const char *failurereg = "fileforaudit.*return,failure";
52 
53 
54 ATF_TC_WITH_CLEANUP(stat_success);
55 ATF_TC_HEAD(stat_success, tc)
56 {
57 	atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful "
58 					"stat(2) call");
59 }
60 
61 ATF_TC_BODY(stat_success, tc)
62 {
63 	/* File needs to exist to call stat(2) */
64 	ATF_REQUIRE((filedesc = open(path, O_CREAT, mode)) != -1);
65 	FILE *pipefd = setup(fds, auclass);
66 	ATF_REQUIRE_EQ(0, stat(path, &statbuff));
67 	check_audit(fds, successreg, pipefd);
68 	close(filedesc);
69 }
70 
71 ATF_TC_CLEANUP(stat_success, tc)
72 {
73 	cleanup();
74 }
75 
76 
77 ATF_TC_WITH_CLEANUP(stat_failure);
78 ATF_TC_HEAD(stat_failure, tc)
79 {
80 	atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful "
81 					"stat(2) call");
82 }
83 
84 ATF_TC_BODY(stat_failure, tc)
85 {
86 	FILE *pipefd = setup(fds, auclass);
87 	/* Failure reason: file does not exist */
88 	ATF_REQUIRE_EQ(-1, stat(errpath, &statbuff));
89 	check_audit(fds, failurereg, pipefd);
90 }
91 
92 ATF_TC_CLEANUP(stat_failure, tc)
93 {
94 	cleanup();
95 }
96 
97 
98 ATF_TC_WITH_CLEANUP(lstat_success);
99 ATF_TC_HEAD(lstat_success, tc)
100 {
101 	atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful "
102 					"lstat(2) call");
103 }
104 
105 ATF_TC_BODY(lstat_success, tc)
106 {
107 	/* Symbolic link needs to exist to call lstat(2) */
108 	ATF_REQUIRE_EQ(0, symlink("symlink", path));
109 	FILE *pipefd = setup(fds, auclass);
110 	ATF_REQUIRE_EQ(0, lstat(path, &statbuff));
111 	check_audit(fds, successreg, pipefd);
112 }
113 
114 ATF_TC_CLEANUP(lstat_success, tc)
115 {
116 	cleanup();
117 }
118 
119 
120 ATF_TC_WITH_CLEANUP(lstat_failure);
121 ATF_TC_HEAD(lstat_failure, tc)
122 {
123 	atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful "
124 					"lstat(2) call");
125 }
126 
127 ATF_TC_BODY(lstat_failure, tc)
128 {
129 	FILE *pipefd = setup(fds, auclass);
130 	/* Failure reason: symbolic link does not exist */
131 	ATF_REQUIRE_EQ(-1, lstat(errpath, &statbuff));
132 	check_audit(fds, failurereg, pipefd);
133 }
134 
135 ATF_TC_CLEANUP(lstat_failure, tc)
136 {
137 	cleanup();
138 }
139 
140 
141 ATF_TC_WITH_CLEANUP(fstat_success);
142 ATF_TC_HEAD(fstat_success, tc)
143 {
144 	atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful "
145 					"fstat(2) call");
146 }
147 
148 ATF_TC_BODY(fstat_success, tc)
149 {
150 	/* File needs to exist to call fstat(2) */
151 	ATF_REQUIRE((filedesc = open(path, O_CREAT | O_RDWR, mode)) != -1);
152 	FILE *pipefd = setup(fds, auclass);
153 	ATF_REQUIRE_EQ(0, fstat(filedesc, &statbuff));
154 
155 	snprintf(extregex, sizeof(extregex),
156 		"fstat.*%jd.*return,success", (intmax_t)statbuff.st_ino);
157 	check_audit(fds, extregex, pipefd);
158 	close(filedesc);
159 }
160 
161 ATF_TC_CLEANUP(fstat_success, tc)
162 {
163 	cleanup();
164 }
165 
166 
167 ATF_TC_WITH_CLEANUP(fstat_failure);
168 ATF_TC_HEAD(fstat_failure, tc)
169 {
170 	atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful "
171 					"fstat(2) call");
172 }
173 
174 ATF_TC_BODY(fstat_failure, tc)
175 {
176 	FILE *pipefd = setup(fds, auclass);
177 	const char *regex = "fstat.*return,failure : Bad file descriptor";
178 	/* Failure reason: bad file descriptor */
179 	ATF_REQUIRE_EQ(-1, fstat(-1, &statbuff));
180 	check_audit(fds, regex, pipefd);
181 }
182 
183 ATF_TC_CLEANUP(fstat_failure, tc)
184 {
185 	cleanup();
186 }
187 
188 
189 ATF_TC_WITH_CLEANUP(fstatat_success);
190 ATF_TC_HEAD(fstatat_success, tc)
191 {
192 	atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful "
193 					"fstatat(2) call");
194 }
195 
196 ATF_TC_BODY(fstatat_success, tc)
197 {
198 	/* File or Symbolic link needs to exist to call lstat(2) */
199 	ATF_REQUIRE_EQ(0, symlink("symlink", path));
200 	FILE *pipefd = setup(fds, auclass);
201 	ATF_REQUIRE_EQ(0, fstatat(AT_FDCWD, path, &statbuff,
202 		AT_SYMLINK_NOFOLLOW));
203 	check_audit(fds, successreg, pipefd);
204 }
205 
206 ATF_TC_CLEANUP(fstatat_success, tc)
207 {
208 	cleanup();
209 }
210 
211 
212 ATF_TC_WITH_CLEANUP(fstatat_failure);
213 ATF_TC_HEAD(fstatat_failure, tc)
214 {
215 	atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful "
216 					"fstatat(2) call");
217 }
218 
219 ATF_TC_BODY(fstatat_failure, tc)
220 {
221 	FILE *pipefd = setup(fds, auclass);
222 	/* Failure reason: symbolic link does not exist */
223 	ATF_REQUIRE_EQ(-1, fstatat(AT_FDCWD, path, &statbuff,
224 		AT_SYMLINK_NOFOLLOW));
225 	check_audit(fds, failurereg, pipefd);
226 }
227 
228 ATF_TC_CLEANUP(fstatat_failure, tc)
229 {
230 	cleanup();
231 }
232 
233 
234 ATF_TC_WITH_CLEANUP(statfs_success);
235 ATF_TC_HEAD(statfs_success, tc)
236 {
237 	atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful "
238 					"statfs(2) call");
239 }
240 
241 ATF_TC_BODY(statfs_success, tc)
242 {
243 	/* File needs to exist to call statfs(2) */
244 	ATF_REQUIRE((filedesc = open(path, O_CREAT, mode)) != -1);
245 	FILE *pipefd = setup(fds, auclass);
246 	ATF_REQUIRE_EQ(0, statfs(path, &statfsbuff));
247 	check_audit(fds, successreg, pipefd);
248 	close(filedesc);
249 }
250 
251 ATF_TC_CLEANUP(statfs_success, tc)
252 {
253 	cleanup();
254 }
255 
256 
257 ATF_TC_WITH_CLEANUP(statfs_failure);
258 ATF_TC_HEAD(statfs_failure, tc)
259 {
260 	atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful "
261 					"statfs(2) call");
262 }
263 
264 ATF_TC_BODY(statfs_failure, tc)
265 {
266 	FILE *pipefd = setup(fds, auclass);
267 	/* Failure reason: file does not exist */
268 	ATF_REQUIRE_EQ(-1, statfs(errpath, &statfsbuff));
269 	check_audit(fds, failurereg, pipefd);
270 }
271 
272 ATF_TC_CLEANUP(statfs_failure, tc)
273 {
274 	cleanup();
275 }
276 
277 
278 ATF_TC_WITH_CLEANUP(fstatfs_success);
279 ATF_TC_HEAD(fstatfs_success, tc)
280 {
281 	atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful "
282 					"fstatfs(2) call");
283 }
284 
285 ATF_TC_BODY(fstatfs_success, tc)
286 {
287 	/* File needs to exist to call fstat(2) */
288 	ATF_REQUIRE((filedesc = open(path, O_CREAT | O_RDWR, mode)) != -1);
289 	/* Call stat(2) to store the Inode number of 'path' */
290 	ATF_REQUIRE_EQ(0, stat(path, &statbuff));
291 	FILE *pipefd = setup(fds, auclass);
292 	ATF_REQUIRE_EQ(0, fstatfs(filedesc, &statfsbuff));
293 
294 	snprintf(extregex, sizeof(extregex), "fstatfs.*%jd.*return,success",
295 			(intmax_t)statbuff.st_ino);
296 	check_audit(fds, extregex, pipefd);
297 	close(filedesc);
298 }
299 
300 ATF_TC_CLEANUP(fstatfs_success, tc)
301 {
302 	cleanup();
303 }
304 
305 
306 ATF_TC_WITH_CLEANUP(fstatfs_failure);
307 ATF_TC_HEAD(fstatfs_failure, tc)
308 {
309 	atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful "
310 					"fstatfs(2) call");
311 }
312 
313 ATF_TC_BODY(fstatfs_failure, tc)
314 {
315 	FILE *pipefd = setup(fds, auclass);
316 	const char *regex = "fstatfs.*return,failure : Bad file descriptor";
317 	/* Failure reason: bad file descriptor */
318 	ATF_REQUIRE_EQ(-1, fstatfs(-1, &statfsbuff));
319 	check_audit(fds, regex, pipefd);
320 }
321 
322 ATF_TC_CLEANUP(fstatfs_failure, tc)
323 {
324 	cleanup();
325 }
326 
327 
328 ATF_TC_WITH_CLEANUP(getfsstat_success);
329 ATF_TC_HEAD(getfsstat_success, tc)
330 {
331 	atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful "
332 					"getfsstat(2) call");
333 }
334 
335 ATF_TC_BODY(getfsstat_success, tc)
336 {
337 	pid = getpid();
338 	snprintf(extregex, sizeof(extregex), "getfsstat.*%d.*success", pid);
339 
340 	FILE *pipefd = setup(fds, auclass);
341 	ATF_REQUIRE(getfsstat(NULL, 0, MNT_NOWAIT) != -1);
342 	check_audit(fds, extregex, pipefd);
343 }
344 
345 ATF_TC_CLEANUP(getfsstat_success, tc)
346 {
347 	cleanup();
348 }
349 
350 
351 ATF_TC_WITH_CLEANUP(getfsstat_failure);
352 ATF_TC_HEAD(getfsstat_failure, tc)
353 {
354 	atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful "
355 					"getfsstat(2) call");
356 }
357 
358 ATF_TC_BODY(getfsstat_failure, tc)
359 {
360 	const char *regex = "getfsstat.*return,failure : Invalid argument";
361 	FILE *pipefd = setup(fds, auclass);
362 	/* Failure reason: Invalid value for mode */
363 	ATF_REQUIRE_EQ(-1, getfsstat(NULL, 0, -1));
364 	check_audit(fds, regex, pipefd);
365 }
366 
367 ATF_TC_CLEANUP(getfsstat_failure, tc)
368 {
369 	cleanup();
370 }
371 
372 
373 ATF_TP_ADD_TCS(tp)
374 {
375 	ATF_TP_ADD_TC(tp, stat_success);
376 	ATF_TP_ADD_TC(tp, stat_failure);
377 	ATF_TP_ADD_TC(tp, lstat_success);
378 	ATF_TP_ADD_TC(tp, lstat_failure);
379 	ATF_TP_ADD_TC(tp, fstat_success);
380 	ATF_TP_ADD_TC(tp, fstat_failure);
381 	ATF_TP_ADD_TC(tp, fstatat_success);
382 	ATF_TP_ADD_TC(tp, fstatat_failure);
383 
384 	ATF_TP_ADD_TC(tp, statfs_success);
385 	ATF_TP_ADD_TC(tp, statfs_failure);
386 	ATF_TP_ADD_TC(tp, fstatfs_success);
387 	ATF_TP_ADD_TC(tp, fstatfs_failure);
388 
389 	ATF_TP_ADD_TC(tp, getfsstat_success);
390 	ATF_TP_ADD_TC(tp, getfsstat_failure);
391 
392 	return (atf_no_error());
393 }
394