1 /*
2 * Copyright (c) 2024 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /* compile: xcrun -sdk macosx.internal clang -ldarwintest -o resolve_beneath resolve_beneath.c -g -Weverything */
30
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <sys/mount.h>
35 #include <sys/attr.h>
36 #include <sys/stat.h>
37 #include <sys/param.h>
38 #include <sys/xattr.h>
39 #include <sys/clonefile.h>
40
41 #include <darwintest.h>
42 #include <darwintest/utils.h>
43
44 static char template[MAXPATHLEN];
45 static char *testdir = NULL;
46 static int testdir_fd = -1, test_fd = -1;
47
48 #ifndef ENOTCAPABLE
49 #define ENOTCAPABLE 107
50 #endif
51
52 #ifndef O_RESOLVE_BENEATH
53 #define O_RESOLVE_BENEATH 0x1000
54 #endif
55
56 #ifndef AT_RESOLVE_BENEATH
57 #define AT_RESOLVE_BENEATH 0x2000
58 #endif
59
60 #ifndef XATTR_RESOLVE_BENEATH
61 #define XATTR_RESOLVE_BENEATH 0x0080
62 #endif
63
64 #ifndef CLONE_RESOLVE_BENEATH
65 #define CLONE_RESOLVE_BENEATH 0x0010
66 #endif
67
68 #ifndef RENAME_RESOLVE_BENEATH
69 #define RENAME_RESOLVE_BENEATH 0x0020
70 #endif
71
72 #ifndef FSOPT_RESOLVE_BENEATH
73 #define FSOPT_RESOLVE_BENEATH 0x1000
74 #endif
75
76 #define TEST_DIR "test_dir"
77 #define NESTED_DIR "test_dir/nested"
78 #define OUTSIDE_FILE "outside_file.txt"
79 #define INSIDE_FILE "test_dir/inside_file.txt"
80 #define NESTED_FILE "test_dir/nested/nested_file.txt"
81 #define SYMLINK "test_dir/symlink"
82 #define SYMLINK_TO_NESTED "test_dir/symlink_to_nested"
83 #define PARENT_SYMLINK "test_dir/parent_symlink"
84 #define CIRCULAR_SYMLINK "test_dir/circular_symlink"
85 #define SYMLINK_ABSOLUTE "test_dir/symlink_absolute"
86
87 #define SYMLINK_FROM "../outside_file.txt"
88 #define SYMLINK_TO_NESTED_FROM "nested/nested_file.txt"
89 #define PARENT_SYMLINK_FROM ".."
90 #define CIRCULAR_SYMLINK_FROM "circular_symlink"
91
92 T_GLOBAL_META(
93 T_META_NAMESPACE("xnu.vfs"),
94 T_META_RADAR_COMPONENT_NAME("xnu"),
95 T_META_RADAR_COMPONENT_VERSION("vfs"),
96 T_META_ASROOT(false),
97 T_META_CHECK_LEAKS(false));
98
99 static void
setup(const char * dirname)100 setup(const char *dirname)
101 {
102 int fd;
103
104 testdir_fd = test_fd = -1;
105
106 /* Create test root directory */
107 snprintf(template, sizeof(template), "%s/%s-XXXXXX", dt_tmpdir(), dirname);
108 T_ASSERT_POSIX_NOTNULL((testdir = mkdtemp(template)), "Creating test root directory");
109 T_ASSERT_POSIX_SUCCESS((testdir_fd = open(testdir, O_SEARCH, 0777)), "Opening test root directory %s", testdir);
110
111 /* Create test directories */
112 T_ASSERT_POSIX_SUCCESS(mkdirat(testdir_fd, TEST_DIR, 0777), "Creating %s/%s", testdir, TEST_DIR);
113 T_ASSERT_POSIX_SUCCESS((test_fd = openat(testdir_fd, TEST_DIR, O_SEARCH, 0777)), "Opening test directory %s/%s", testdir, TEST_DIR);
114 T_ASSERT_POSIX_SUCCESS(mkdirat(testdir_fd, NESTED_DIR, 0777), "Creating %s/%s", testdir, NESTED_DIR);
115
116 /* Create test files */
117 T_ASSERT_POSIX_SUCCESS((fd = openat(testdir_fd, OUTSIDE_FILE, O_CREAT | O_RDWR, 0777)), "Creating file %s/%s", testdir, OUTSIDE_FILE);
118 T_ASSERT_POSIX_SUCCESS(close(fd), "Closing %s", OUTSIDE_FILE);
119
120 T_ASSERT_POSIX_SUCCESS((fd = openat(testdir_fd, INSIDE_FILE, O_CREAT | O_RDWR, 0777)), "Creating file %s/%s", testdir, INSIDE_FILE);
121 T_ASSERT_POSIX_SUCCESS(close(fd), "Closing %s", INSIDE_FILE);
122
123 T_ASSERT_POSIX_SUCCESS((fd = openat(testdir_fd, NESTED_FILE, O_CREAT | O_RDWR, 0777)), "Creating file %s/%s", testdir, NESTED_FILE);
124 T_ASSERT_POSIX_SUCCESS(close(fd), "Closing %s", NESTED_FILE);
125
126 /* Create test symlinks */
127 T_ASSERT_POSIX_SUCCESS(symlinkat(SYMLINK_FROM, testdir_fd, SYMLINK), "Creating symlink %s/%s -> %s", testdir, SYMLINK, SYMLINK_FROM);
128 T_ASSERT_POSIX_SUCCESS(symlinkat(SYMLINK_TO_NESTED_FROM, testdir_fd, SYMLINK_TO_NESTED), "Creating symlink %s/%s -> %s", testdir, SYMLINK_TO_NESTED, SYMLINK_TO_NESTED_FROM);
129 T_ASSERT_POSIX_SUCCESS(symlinkat(PARENT_SYMLINK_FROM, testdir_fd, PARENT_SYMLINK), "Creating symlink %s/%s -> %s", testdir, PARENT_SYMLINK, PARENT_SYMLINK_FROM);
130 T_ASSERT_POSIX_SUCCESS(symlinkat(CIRCULAR_SYMLINK_FROM, testdir_fd, CIRCULAR_SYMLINK), "Creating symlink %s/%s -> %s", testdir, CIRCULAR_SYMLINK, CIRCULAR_SYMLINK_FROM);
131 T_ASSERT_POSIX_SUCCESS(symlinkat(testdir, testdir_fd, SYMLINK_ABSOLUTE), "Creating symlink %s/%s -> %s", testdir, SYMLINK_ABSOLUTE, testdir);
132 }
133
134 static void
cleanup(void)135 cleanup(void)
136 {
137 if (test_fd != -1) {
138 close(test_fd);
139 }
140 if (testdir_fd != -1) {
141 unlinkat(testdir_fd, SYMLINK_ABSOLUTE, 0);
142 unlinkat(testdir_fd, CIRCULAR_SYMLINK, 0);
143 unlinkat(testdir_fd, PARENT_SYMLINK, 0);
144 unlinkat(testdir_fd, SYMLINK_TO_NESTED, 0);
145 unlinkat(testdir_fd, SYMLINK, 0);
146 unlinkat(testdir_fd, NESTED_FILE, 0);
147 unlinkat(testdir_fd, NESTED_DIR, AT_REMOVEDIR);
148 unlinkat(testdir_fd, INSIDE_FILE, 0);
149 unlinkat(testdir_fd, TEST_DIR, AT_REMOVEDIR);
150 unlinkat(testdir_fd, OUTSIDE_FILE, 0);
151
152 close(testdir_fd);
153 if (rmdir(testdir)) {
154 T_FAIL("Unable to remove the test directory (%s)", testdir);
155 }
156 }
157 }
158
159 T_DECL(resolve_beneath_open,
160 "test open()/openat() using the O_RESOLVE_BENEATH flag")
161 {
162 int fd, root_fd;
163 char path[MAXPATHLEN];
164
165 T_SETUPBEGIN;
166
167 T_ATEND(cleanup);
168 setup("resolve_beneath_open");
169
170 T_ASSERT_POSIX_SUCCESS((root_fd = open("/", O_SEARCH, 0777)), "Opening the root directory");
171
172 T_SETUPEND;
173
174 T_LOG("Testing the openat() syscall using O_RESOLVE_BENEATH");
175
176 /* Test Case 1: File within the directory */
177 T_EXPECT_POSIX_SUCCESS((fd = openat(test_fd, "inside_file.txt", O_RDONLY | O_RESOLVE_BENEATH, 0777)), "Test Case 1: File within the directory");
178 if (fd >= 0) {
179 close(fd);
180 }
181
182 /* Test Case 2: File using a symlink pointing outside */
183 T_EXPECT_POSIX_FAILURE(openat(test_fd, "symlink", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
184
185 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
186 T_EXPECT_POSIX_FAILURE(openat(test_fd, "../outside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
187
188 /* Test Case 4: File within a nested directory */
189 T_EXPECT_POSIX_SUCCESS((fd = openat(test_fd, "nested/nested_file.txt", O_RDONLY | O_RESOLVE_BENEATH, 0777)), "Test Case 4: File within a nested directory");
190 if (fd >= 0) {
191 close(fd);
192 }
193
194 /* Test Case 5: Symlink to a file in a nested directory */
195 T_EXPECT_POSIX_SUCCESS((fd = openat(test_fd, "symlink_to_nested", O_RDONLY | O_RESOLVE_BENEATH, 0777)), "Test Case 5: Symlink to a file within the same directory");
196 if (fd >= 0) {
197 close(fd);
198 }
199
200 /* Test Case 6: File using an absolute path */
201 T_EXPECT_POSIX_FAILURE(openat(test_fd, "/etc/passwd", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
202
203 /* Test Case 7: Valid symlink to parent directory */
204 T_EXPECT_POSIX_FAILURE(openat(test_fd, "parent_symlink/outside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
205
206 /* Test Case 8: Circular symlink within directory */
207 T_EXPECT_POSIX_FAILURE(openat(test_fd, "circular_symlink", O_RDONLY | O_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
208
209 /* Test Case 9: Path can not escape outside at any point of the resolution */
210 T_EXPECT_POSIX_FAILURE(openat(test_fd, "../test_dir/inside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
211
212 /* Test Case 10: File using a symlink pointing to absolute path */
213 T_EXPECT_POSIX_FAILURE(openat(test_fd, "symlink_absolute/test_dir/inside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
214
215 /* Test Case 11: Absolute path relative to the root directory */
216 T_EXPECT_POSIX_FAILURE(openat(root_fd, "/etc/passwd", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 11: Absolute path relative to the root directory");
217
218 /* Test Case 12: Path can not escape outside of the root directory using dotdot */
219 T_EXPECT_POSIX_FAILURE((fd = openat(root_fd, "../private", O_RESOLVE_BENEATH)), ENOTCAPABLE, "Test Case 12: Path can not escape outside of the root directory using dotdot");
220
221 /* Changing current directory to the test directory */
222 T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
223
224 T_LOG("Testing the open() syscall using O_RESOLVE_BENEATH");
225
226 /* Test Case 13: Open a file within the directory */
227 T_EXPECT_POSIX_SUCCESS((fd = open("inside_file.txt", O_RDONLY | O_RESOLVE_BENEATH, 0777)), "Test Case 13: Open a file within the directory");
228 if (fd >= 0) {
229 close(fd);
230 }
231
232 /* Test Case 14: Attempt to open a file using a symlink pointing outside */
233 T_EXPECT_POSIX_FAILURE(open("symlink", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 14: Attempt to open a file using a symlink pointing outside");
234
235 /* Test Case 15: Attempt to open a file using ".." to navigate outside */
236 T_EXPECT_POSIX_FAILURE(open("../outside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 15: Attempt to open a file using \"..\" to navigate outside");
237
238 /* Test Case 16: Open a file within a nested directory */
239 T_EXPECT_POSIX_SUCCESS((fd = open("nested/nested_file.txt", O_RDONLY | O_RESOLVE_BENEATH, 0777)), "Test Case 16: Open a file within a nested directory");
240 if (fd >= 0) {
241 close(fd);
242 }
243
244 /* Test Case 17: Symlink to a file in a nested directory */
245 T_EXPECT_POSIX_SUCCESS((fd = open("symlink_to_nested", O_RDONLY | O_RESOLVE_BENEATH, 0777)), "Test Case 17: Symlink to a file within the same directory");
246 if (fd >= 0) {
247 close(fd);
248 }
249
250 /* Test Case 18: Attempt to open a file using an absolute path */
251 T_EXPECT_POSIX_FAILURE(open("/etc/passwd", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 18: Attempt to open a file using an absolute path");
252
253 /* Test Case 19: Valid symlink to parent directory */
254 T_EXPECT_POSIX_FAILURE(open("parent_symlink/outside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 19: Valid symlink to parent directory");
255
256 /* Test Case 20: Circular symlink within directory */
257 T_EXPECT_POSIX_FAILURE(open("circular_symlink", O_RDONLY | O_RESOLVE_BENEATH), ELOOP, "Test Case 20: Circular symlink within directory");
258
259 /* Test Case 21: Path can not escape outside at any point of the resolution */
260 T_EXPECT_POSIX_FAILURE(open("../test_dir/inside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 21: Path can not escape outside at any point of the resolution");
261
262 /* Test Case 22: Attempt to open a file using a symlink pointing to absolute path */
263 T_EXPECT_POSIX_FAILURE(open("symlink_absolute/test_dir/inside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 22: Attempt to open a file using a symlink pointing to absolute path");
264
265 /* Test Case 23: Path can not escape outside at any point of the resolution using absolute path */
266 snprintf(path, sizeof(path), "%s/%s", testdir, INSIDE_FILE);
267 T_EXPECT_POSIX_FAILURE(open(path, O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 23: Path can not escape outside at any point of the resolution using absolute path");
268
269 T_EXPECT_POSIX_SUCCESS(close(root_fd), "Closing the root directory");
270 }
271
272 T_DECL(resolve_beneath_faccessat,
273 "test faccessat() using the AT_RESOLVE_BENEATH flag")
274 {
275 T_SETUPBEGIN;
276
277 T_ATEND(cleanup);
278 setup("resolve_beneath_faccessat");
279
280 T_SETUPEND;
281
282 T_LOG("Testing the faccessat() syscall using AT_RESOLVE_BENEATH");
283
284 /* Test Case 1: File within the directory */
285 T_EXPECT_POSIX_SUCCESS(faccessat(test_fd, "inside_file.txt", R_OK, AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
286
287 /* Test Case 2: File using a symlink pointing outside */
288 T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "symlink", R_OK, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
289
290 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
291 T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "../outside_file.txt", R_OK, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
292
293 /* Test Case 4: File within a nested directory */
294 T_EXPECT_POSIX_SUCCESS(faccessat(test_fd, "nested/nested_file.txt", R_OK, AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
295
296 /* Test Case 5: Symlink to a file in a nested directory */
297 T_EXPECT_POSIX_SUCCESS(faccessat(test_fd, "symlink_to_nested", R_OK, AT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
298
299 /* Test Case 6: File using an absolute path */
300 T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "/etc/passwd", R_OK, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
301
302 /* Test Case 7: Valid symlink to parent directory */
303 T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "parent_symlink/outside_file.txt", R_OK, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
304
305 /* Test Case 8: Circular symlink within directory */
306 T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "circular_symlink", R_OK, AT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
307
308 /* Test Case 9: Path can not escape outside at any point of the resolution */
309 T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "../test_dir/inside_file.txt", R_OK, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
310
311 /* Test Case 10: File using a symlink pointing to absolute path */
312 T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "symlink_absolute/test_dir/inside_file.txt", R_OK, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
313 }
314
315 T_DECL(resolve_beneath_fstatat,
316 "test fstatat() using the AT_RESOLVE_BENEATH flag")
317 {
318 struct stat buf;
319
320 T_SETUPBEGIN;
321
322 T_ATEND(cleanup);
323 setup("resolve_beneath_fstatat");
324
325 T_SETUPEND;
326
327 T_LOG("Testing the fstatat() syscall using AT_RESOLVE_BENEATH");
328
329 /* Test Case 1: File within the directory */
330 T_EXPECT_POSIX_SUCCESS(fstatat(test_fd, "inside_file.txt", &buf, AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
331
332 /* Test Case 2: File using a symlink pointing outside */
333 T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "symlink", &buf, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
334
335 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
336 T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "../outside_file.txt", &buf, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
337
338 /* Test Case 4: File within a nested directory */
339 T_EXPECT_POSIX_SUCCESS(fstatat(test_fd, "nested/nested_file.txt", &buf, AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
340
341 /* Test Case 5: Symlink to a file in a nested directory */
342 T_EXPECT_POSIX_SUCCESS(fstatat(test_fd, "symlink_to_nested", &buf, AT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
343
344 /* Test Case 6: File using an absolute path */
345 T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "/etc/passwd", &buf, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
346
347 /* Test Case 7: Valid symlink to parent directory */
348 T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "parent_symlink/outside_file.txt", &buf, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
349
350 /* Test Case 8: Circular symlink within directory */
351 T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "circular_symlink", &buf, AT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
352
353 /* Test Case 9: Path can not escape outside at any point of the resolution */
354 T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "../test_dir/inside_file.txt", &buf, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
355
356 /* Test Case 10: File using a symlink pointing to absolute path */
357 T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "symlink_absolute/test_dir/inside_file.txt", &buf, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
358 }
359
360 T_DECL(resolve_beneath_fchmodat,
361 "test fchmodat() using the AT_RESOLVE_BENEATH flag")
362 {
363 T_SETUPBEGIN;
364
365 T_ATEND(cleanup);
366 setup("resolve_beneath_fchmodat");
367
368 T_SETUPEND;
369
370 T_LOG("Testing the fchmodat() syscall using AT_RESOLVE_BENEATH");
371
372 /* Test Case 1: File within the directory */
373 T_EXPECT_POSIX_SUCCESS(fchmodat(test_fd, "inside_file.txt", S_IRWXU, AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
374
375 /* Test Case 2: File using a symlink pointing outside */
376 T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "symlink", S_IRWXU, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
377
378 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
379 T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "../outside_file.txt", S_IRWXU, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
380
381 /* Test Case 4: File within a nested directory */
382 T_EXPECT_POSIX_SUCCESS(fchmodat(test_fd, "nested/nested_file.txt", S_IRWXU, AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
383
384 /* Test Case 5: Symlink to a file in a nested directory */
385 T_EXPECT_POSIX_SUCCESS(fchmodat(test_fd, "symlink_to_nested", S_IRWXU, AT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
386
387 /* Test Case 6: File using an absolute path */
388 T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "/etc/passwd", S_IRWXU, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
389
390 /* Test Case 7: Valid symlink to parent directory */
391 T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "parent_symlink/outside_file.txt", S_IRWXU, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
392
393 /* Test Case 8: Circular symlink within directory */
394 T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "circular_symlink", S_IRWXU, AT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
395
396 /* Test Case 9: Path can not escape outside at any point of the resolution */
397 T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "../test_dir/inside_file.txt", S_IRWXU, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
398
399 /* Test Case 10: File using a symlink pointing to absolute path */
400 T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "symlink_absolute/test_dir/inside_file.txt", S_IRWXU, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
401 }
402
403 T_DECL(resolve_beneath_fchownat,
404 "test fchownat() using the AT_RESOLVE_BENEATH flag")
405 {
406 T_SETUPBEGIN;
407
408 T_ATEND(cleanup);
409 setup("resolve_beneath_fchownat");
410
411 T_SETUPEND;
412
413 T_LOG("Testing the fchownat() syscall using AT_RESOLVE_BENEATH");
414
415 /* Test Case 1: File within the directory */
416 T_EXPECT_POSIX_SUCCESS(fchownat(test_fd, "inside_file.txt", geteuid(), getgid(), AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
417
418 /* Test Case 2: File using a symlink pointing outside */
419 T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "symlink", geteuid(), getgid(), AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
420
421 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
422 T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "../outside_file.txt", geteuid(), getgid(), AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
423
424 /* Test Case 4: File within a nested directory */
425 T_EXPECT_POSIX_SUCCESS(fchownat(test_fd, "nested/nested_file.txt", geteuid(), getgid(), AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
426
427 /* Test Case 5: Symlink to a file in a nested directory */
428 T_EXPECT_POSIX_SUCCESS(fchownat(test_fd, "symlink_to_nested", geteuid(), getgid(), AT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
429
430 /* Test Case 6: File using an absolute path */
431 T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "/etc/passwd", geteuid(), getgid(), AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
432
433 /* Test Case 7: Valid symlink to parent directory */
434 T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "parent_symlink/outside_file.txt", geteuid(), getgid(), AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
435
436 /* Test Case 8: Circular symlink within directory */
437 T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "circular_symlink", geteuid(), getgid(), AT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
438
439 /* Test Case 9: Path can not escape outside at any point of the resolution */
440 T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "../test_dir/inside_file.txt", geteuid(), getgid(), AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
441
442 /* Test Case 10: File using a symlink pointing to absolute path */
443 T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "symlink_absolute/test_dir/inside_file.txt", geteuid(), getgid(), AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
444 }
445
446 T_DECL(resolve_beneath_linkat,
447 "test linkat() using the AT_RESOLVE_BENEATH flag")
448 {
449 T_SETUPBEGIN;
450
451 T_ATEND(cleanup);
452 setup("resolve_beneath_linkat");
453
454 T_SETUPEND;
455
456 T_LOG("Testing the linkat() syscall using AT_RESOLVE_BENEATH");
457
458 /* Test Case 1: File within the directory */
459 T_EXPECT_POSIX_SUCCESS(linkat(test_fd, "inside_file.txt", test_fd, "inside_file_2.txt", AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
460 unlinkat(test_fd, "inside_file_2.txt", 0);
461
462 /* Test Case 2: File using a symlink pointing outside */
463 T_EXPECT_POSIX_FAILURE(linkat(test_fd, "symlink/.", test_fd, "inside_file_2.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
464
465 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
466 T_EXPECT_POSIX_FAILURE(linkat(test_fd, "inside_file.txt", test_fd, "../outside_file.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
467
468 /* Test Case 4: File within a nested directory */
469 T_EXPECT_POSIX_SUCCESS(linkat(test_fd, "nested/nested_file.txt", test_fd, "nested/nested_file_2.txt", AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
470 unlinkat(test_fd, "nested/nested_file_2.txt", 0);
471
472 /* Test Case 5: Symlink to a file in a nested directory */
473 T_EXPECT_POSIX_SUCCESS(linkat(test_fd, "symlink_to_nested", test_fd, "nested/nested_file_2.txt", AT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
474 unlinkat(test_fd, "nested/nested_file_2.txt", 0);
475
476 /* Test Case 6: File using an absolute path */
477 T_EXPECT_POSIX_FAILURE(linkat(test_fd, "/etc/passwd", test_fd, "inside_file_2.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
478 }
479
480 T_DECL(resolve_beneath_unlinkat,
481 "test unlinkat() using the AT_RESOLVE_BENEATH flag")
482 {
483 int fd;
484
485 T_SETUPBEGIN;
486
487 T_ATEND(cleanup);
488 setup("resolve_beneath_unlinkat");
489
490 T_SETUPEND;
491
492 T_LOG("Testing the unlinkat() syscall using AT_RESOLVE_BENEATH");
493
494 /* Test Case 1: File within the directory */
495 T_EXPECT_POSIX_SUCCESS(unlinkat(test_fd, "inside_file.txt", AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
496 if ((fd = openat(testdir_fd, INSIDE_FILE, O_CREAT | O_RDWR, 0777)) < 0) {
497 T_FAIL("Unable to recreate %s", INSIDE_FILE);
498 }
499 close(fd);
500
501 /* Test Case 2: File using a symlink pointing outside */
502 T_EXPECT_POSIX_SUCCESS(unlinkat(test_fd, "symlink", AT_RESOLVE_BENEATH), "Test Case 2: File using a symlink pointing outside");
503 if (symlinkat(SYMLINK_FROM, testdir_fd, SYMLINK) < 0) {
504 T_FAIL("Unable to recreate %s", INSIDE_FILE);
505 }
506
507 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
508 T_EXPECT_POSIX_FAILURE(unlinkat(test_fd, "../outside_file.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
509
510 /* Test Case 4: File within a nested directory */
511 T_EXPECT_POSIX_SUCCESS(unlinkat(test_fd, "nested/nested_file.txt", AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
512 if ((fd = openat(testdir_fd, NESTED_FILE, O_CREAT | O_RDWR, 0777)) < 0) {
513 T_FAIL("Unable to recreate %s", NESTED_FILE);
514 }
515 close(fd);
516
517 /* Test Case 5: Symlink to a file in a nested directory */
518 T_EXPECT_POSIX_SUCCESS(unlinkat(test_fd, "symlink_to_nested", AT_RESOLVE_BENEATH), "Test Case 5: Symlink //to a file within the same directory");
519 if (symlinkat(SYMLINK_TO_NESTED_FROM, testdir_fd, SYMLINK_TO_NESTED) < 0) {
520 T_FAIL("Unable to recreate %s", SYMLINK_TO_NESTED);
521 }
522
523 /* Test Case 6: File using an absolute path */
524 T_EXPECT_POSIX_FAILURE(unlinkat(test_fd, "/etc/passwd", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
525
526 /* Test Case 7: Valid symlink to parent directory */
527 T_EXPECT_POSIX_FAILURE(unlinkat(test_fd, "parent_symlink/outside_file.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
528
529 /* Test Case 8: Circular symlink within directory */
530 T_EXPECT_POSIX_SUCCESS(unlinkat(test_fd, "circular_symlink", AT_RESOLVE_BENEATH), "Test Case 8: Circular symlink within directory");
531 if (symlinkat(CIRCULAR_SYMLINK_FROM, testdir_fd, CIRCULAR_SYMLINK) < 0) {
532 T_FAIL("Unable to recreate %s", CIRCULAR_SYMLINK);
533 }
534
535 /* Test Case 9: Path can not escape outside at any point of the resolution */
536 T_EXPECT_POSIX_FAILURE(unlinkat(test_fd, "../test_dir/inside_file.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
537
538 /* Test Case 10: File using a symlink pointing to absolute path */
539 T_EXPECT_POSIX_FAILURE(unlinkat(test_fd, "symlink_absolute/test_dir/inside_file.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
540 }
541
542 T_DECL(resolve_beneath_utimensat,
543 "test utimensat() using the AT_RESOLVE_BENEATH flag")
544 {
545 static const struct timespec tptr[] = {
546 { 0x12345678, 987654321 },
547 { 0x15263748, 123456789 },
548 };
549
550 T_SETUPBEGIN;
551
552 T_ATEND(cleanup);
553 setup("resolve_beneath_utimensat");
554
555 T_SETUPEND;
556
557 T_LOG("Testing the utimensat() syscall using AT_RESOLVE_BENEATH");
558
559 /* Test Case 1: File within the directory */
560 T_EXPECT_POSIX_SUCCESS(utimensat(test_fd, "inside_file.txt", tptr, AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
561
562 /* Test Case 2: File using a symlink pointing outside */
563 T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "symlink", tptr, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
564
565 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
566 T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "../outside_file.txt", tptr, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
567
568 /* Test Case 4: File within a nested directory */
569 T_EXPECT_POSIX_SUCCESS(utimensat(test_fd, "nested/nested_file.txt", tptr, AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
570
571 /* Test Case 5: Symlink to a file in a nested directory */
572 T_EXPECT_POSIX_SUCCESS(utimensat(test_fd, "symlink_to_nested", tptr, AT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
573
574 /* Test Case 6: File using an absolute path */
575 T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "/etc/passwd", tptr, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
576
577 /* Test Case 7: Valid symlink to parent directory */
578 T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "parent_symlink/outside_file.txt", tptr, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
579
580 /* Test Case 8: Circular symlink within directory */
581 T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "circular_symlink", tptr, AT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
582
583 /* Test Case 9: Path can not escape outside at any point of the resolution */
584 T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "../test_dir/inside_file.txt", tptr, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
585
586 /* Test Case 10: File using a symlink pointing to absolute path */
587 T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "symlink_absolute/test_dir/inside_file.txt", tptr, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
588 }
589
590 T_DECL(resolve_beneath_getxattr,
591 "test getxattr()/fgetxattr() using the XATTR_RESOLVE_BENEATH flag")
592 {
593 char xattr_buff[100];
594 const char *xattr = "test1234";
595 size_t xattr_len = strlen(xattr);
596
597 T_SETUPBEGIN;
598
599 T_ATEND(cleanup);
600 setup("resolve_beneath_getxattr");
601
602 /* Changing current directory to the test directory */
603 T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
604
605 /* Setting extended attributes */
606 T_ASSERT_POSIX_SUCCESS(setxattr("inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0), "Setting extended attributes to inside_file.txt");
607 T_ASSERT_POSIX_SUCCESS(setxattr("../outside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0), "Setting extended attributes to outside_file.txt");
608 T_ASSERT_POSIX_SUCCESS(setxattr("nested/nested_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0), "Setting extended attributes to nested_file.txt");
609
610 T_SETUPEND;
611
612 T_LOG("Testing the getxattr() syscall using XATTR_RESOLVE_BENEATH");
613
614 /* Test Case 1: File within the directory */
615 T_EXPECT_POSIX_SUCCESS(getxattr("inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), "Test Case 1: File within the directory");
616
617 /* Test Case 2: File using a symlink pointing outside */
618 T_EXPECT_POSIX_FAILURE(getxattr("symlink", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
619
620 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
621 T_EXPECT_POSIX_FAILURE(getxattr("../outside_file.txt", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
622
623 /* Test Case 4: File within a nested directory */
624 T_EXPECT_POSIX_SUCCESS(getxattr("nested/nested_file.txt", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
625
626 /* Test Case 5: Symlink to a file in a nested directory */
627 T_EXPECT_POSIX_SUCCESS(getxattr("symlink_to_nested", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
628
629 /* Test Case 6: File using an absolute path */
630 T_EXPECT_POSIX_FAILURE(getxattr("/etc/passwd", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
631
632 /* Test Case 7: Valid symlink to parent directory */
633 T_EXPECT_POSIX_FAILURE(getxattr("parent_symlink/outside_file.txt", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
634
635 /* Test Case 8: Circular symlink within directory */
636 T_EXPECT_POSIX_FAILURE(getxattr("circular_symlink", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
637
638 /* Test Case 9: Path can not escape outside at any point of the resolution */
639 T_EXPECT_POSIX_FAILURE(getxattr("../test_dir/inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
640
641 /* Test Case 10: File using a symlink pointing to absolute path */
642 T_EXPECT_POSIX_FAILURE(getxattr("symlink_absolute/test_dir/inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
643
644 T_LOG("Testing the fgetxattr() syscall using XATTR_RESOLVE_BENEATH");
645
646 /* Test Case 11: Verifying that fgetxattr() fails with EINVAL */
647 T_EXPECT_POSIX_FAILURE(fgetxattr(test_fd, XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), EINVAL, "Test Case 11: Verifying that fgetxattr() fails with EINVAL");
648 }
649
650 T_DECL(resolve_beneath_setxattr,
651 "test setxattr()/fsetxattr() using the XATTR_RESOLVE_BENEATH flag")
652 {
653 const char *xattr = "test1234";
654 size_t xattr_len = strlen(xattr);
655
656 T_SETUPBEGIN;
657
658 T_ATEND(cleanup);
659 setup("resolve_beneath_setxattr");
660
661 /* Changing current directory to the test directory */
662 T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
663
664 T_SETUPEND;
665
666 T_LOG("Testing the setxattr() syscall using XATTR_RESOLVE_BENEATH");
667
668 /* Test Case 1: File within the directory */
669 T_EXPECT_POSIX_SUCCESS(setxattr("inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), "Test Case 1: File within the directory");
670
671 /* Test Case 2: File using a symlink pointing outside */
672 T_EXPECT_POSIX_FAILURE(setxattr("symlink", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
673
674 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
675 T_EXPECT_POSIX_FAILURE(setxattr("../outside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
676
677 /* Test Case 4: File within a nested directory */
678 T_EXPECT_POSIX_SUCCESS(setxattr("nested/nested_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
679
680 /* Test Case 5: Symlink to a file in a nested directory */
681 T_EXPECT_POSIX_SUCCESS(setxattr("symlink_to_nested", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
682
683 /* Test Case 6: File using an absolute path */
684 T_EXPECT_POSIX_FAILURE(setxattr("/etc/passwd", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
685
686 /* Test Case 7: Valid symlink to parent directory */
687 T_EXPECT_POSIX_FAILURE(setxattr("parent_symlink/outside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
688
689 /* Test Case 8: Circular symlink within directory */
690 T_EXPECT_POSIX_FAILURE(setxattr("circular_symlink", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
691
692 /* Test Case 9: Path can not escape outside at any point of the resolution */
693 T_EXPECT_POSIX_FAILURE(setxattr("../test_dir/inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
694
695 /* Test Case 10: File using a symlink pointing to absolute path */
696 T_EXPECT_POSIX_FAILURE(setxattr("symlink_absolute/test_dir/inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
697
698 T_LOG("Testing the fsetxattr() syscall using XATTR_RESOLVE_BENEATH");
699
700 /* Test Case 11: Verifying that fsetxattr() fails with EINVAL */
701 T_EXPECT_POSIX_FAILURE(fsetxattr(test_fd, XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), EINVAL, "Test Case 11: Verifying that fsetxattr() fails with EINVAL");
702 }
703
704 T_DECL(resolve_beneath_listxattr,
705 "test listxattr()/flistxattr() using the XATTR_RESOLVE_BENEATH flag")
706 {
707 char xattr_buff[100];
708
709 T_SETUPBEGIN;
710
711 T_ATEND(cleanup);
712 setup("resolve_beneath_listxattr");
713
714 /* Changing current directory to the test directory */
715 T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
716
717 T_SETUPEND;
718
719 T_LOG("Testing the listxattr() syscall using XATTR_RESOLVE_BENEATH");
720
721 /* Test Case 1: File within the directory */
722 T_EXPECT_POSIX_SUCCESS(listxattr("inside_file.txt", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), "Test Case 1: File within the directory");
723
724 /* Test Case 2: File using a symlink pointing outside */
725 T_EXPECT_POSIX_FAILURE(listxattr("symlink", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
726
727 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
728 T_EXPECT_POSIX_FAILURE(listxattr("../outside_file.txt", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
729
730 /* Test Case 4: File within a nested directory */
731 T_EXPECT_POSIX_SUCCESS(listxattr("nested/nested_file.txt", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
732
733 /* Test Case 5: Symlink to a file in a nested directory */
734 T_EXPECT_POSIX_SUCCESS(listxattr("symlink_to_nested", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
735
736 /* Test Case 6: File using an absolute path */
737 T_EXPECT_POSIX_FAILURE(listxattr("/etc/passwd", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
738
739 /* Test Case 7: Valid symlink to parent directory */
740 T_EXPECT_POSIX_FAILURE(listxattr("parent_symlink/outside_file.txt", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
741
742 /* Test Case 8: Circular symlink within directory */
743 T_EXPECT_POSIX_FAILURE(listxattr("circular_symlink", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
744
745 /* Test Case 9: Path can not escape outside at any point of the resolution */
746 T_EXPECT_POSIX_FAILURE(listxattr("../test_dir/inside_file.txt", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
747
748 /* Test Case 10: File using a symlink pointing to absolute path */
749 T_EXPECT_POSIX_FAILURE(listxattr("symlink_absolute/test_dir/inside_file.txt", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
750
751 T_LOG("Testing the flistxattr() syscall using XATTR_RESOLVE_BENEATH");
752
753 /* Test Case 11: Verifying that flistxattr() fails with EINVAL */
754 T_EXPECT_POSIX_FAILURE(flistxattr(test_fd, xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), EINVAL, "Test Case 11: Verifying that flistxattr() fails with EINVAL");
755 }
756
757 T_DECL(resolve_beneath_removexattr,
758 "test removexattr()/fremovexattr() using the XATTR_RESOLVE_BENEATH flag")
759 {
760 const char *xattr = "test1234";
761 size_t xattr_len = strlen(xattr);
762
763 T_SETUPBEGIN;
764
765 T_ATEND(cleanup);
766 setup("resolve_beneath_removexattr");
767
768 /* Changing current directory to the test directory */
769 T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
770
771 /* Setting extended attributes */
772 T_ASSERT_POSIX_SUCCESS(setxattr("inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0), "Setting extended attributes to inside_file.txt");
773 T_ASSERT_POSIX_SUCCESS(setxattr("../outside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0), "Setting extended attributes to outside_file.txt");
774 T_ASSERT_POSIX_SUCCESS(setxattr("nested/nested_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0), "Setting extended attributes to nested_file.txt");
775
776 T_SETUPEND;
777
778 T_LOG("Testing the removexattr() syscall using XATTR_RESOLVE_BENEATH");
779
780 /* Test Case 1: File within the directory */
781 T_EXPECT_POSIX_SUCCESS(removexattr("inside_file.txt", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), "Test Case 1: File within the directory");
782
783 /* Test Case 2: File using a symlink pointing outside */
784 T_EXPECT_POSIX_FAILURE(removexattr("symlink", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
785
786 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
787 T_EXPECT_POSIX_FAILURE(removexattr("../outside_file.txt", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
788
789 /* Test Case 4: File within a nested directory */
790 T_EXPECT_POSIX_SUCCESS(removexattr("nested/nested_file.txt", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
791
792 if (setxattr("nested/nested_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0) < 0) {
793 T_FAIL("Unable to setxattr to nested_file.txt");
794 }
795
796 /* Test Case 5: Symlink to a file in a nested directory */
797 T_EXPECT_POSIX_SUCCESS(removexattr("symlink_to_nested", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
798
799 /* Test Case 6: File using an absolute path */
800 T_EXPECT_POSIX_FAILURE(removexattr("/etc/passwd", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
801
802 /* Test Case 7: Valid symlink to parent directory */
803 T_EXPECT_POSIX_FAILURE(removexattr("parent_symlink/outside_file.txt", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
804
805 /* Test Case 8: Circular symlink within directory */
806 T_EXPECT_POSIX_FAILURE(removexattr("circular_symlink", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
807
808 /* Test Case 9: Path can not escape outside at any point of the resolution */
809 T_EXPECT_POSIX_FAILURE(removexattr("../test_dir/inside_file.txt", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
810
811 /* Test Case 10: File using a symlink pointing to absolute path */
812 T_EXPECT_POSIX_FAILURE(removexattr("symlink_absolute/test_dir/inside_file.txt", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
813
814 T_LOG("Testing the fremovexattr() syscall using XATTR_RESOLVE_BENEATH");
815
816 /* Test Case 11: Verifying that fremovexattr() fails with EINVAL */
817 T_EXPECT_POSIX_FAILURE(fremovexattr(test_fd, XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), EINVAL, "Test Case 11: Verifying that fremovexattr() fails with EINVAL");
818 }
819
820 T_DECL(resolve_beneath_clonefile,
821 "test clonefile()/clonefileat()/fclonefileat() using the CLONE_RESOLVE_BENEATH flag")
822 {
823 int fd;
824 T_SETUPBEGIN;
825
826 T_ATEND(cleanup);
827 setup("resolve_beneath_clonefile");
828
829 /* Changing current directory to the test directory */
830 T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
831
832 /* Open test file */
833 T_ASSERT_POSIX_SUCCESS((fd = open("inside_file.txt", O_RDWR, 0777)), "Opening %s", INSIDE_FILE);
834
835 T_SETUPEND;
836
837 T_LOG("Testing the clonefile() syscall using CLONE_RESOLVE_BENEATH");
838
839 /* Test Case 1: File within the directory */
840 T_EXPECT_POSIX_SUCCESS(clonefile("inside_file.txt", "inside_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 1: File within the directory");
841 unlink("inside_file_2.txt");
842
843 /* Test Case 2: File using a symlink pointing outside */
844 T_EXPECT_POSIX_FAILURE(clonefile("symlink", "inside_file_2.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
845
846 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
847 T_EXPECT_POSIX_FAILURE(clonefile("inside_file.txt", "../outside_file.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
848
849 /* Test Case 4: File within a nested directory */
850 T_EXPECT_POSIX_SUCCESS(clonefile("nested/nested_file.txt", "nested/nested_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
851 unlinkat(test_fd, "nested/nested_file_2.txt", 0);
852
853 /* Test Case 5: Symlink to a file in a nested directory */
854 T_EXPECT_POSIX_SUCCESS(clonefile("symlink_to_nested", "nested/nested_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
855 unlinkat(test_fd, "nested/nested_file_2.txt", 0);
856
857 /* Test Case 6: File using an absolute path */
858 T_EXPECT_POSIX_FAILURE(clonefile("/etc/passwd", "inside_file_2.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
859
860 T_LOG("Testing the clonefileat() syscall using CLONE_RESOLVE_BENEATH");
861
862 /* Test Case 7: File within the directory */
863 T_EXPECT_POSIX_SUCCESS(clonefileat(test_fd, "inside_file.txt", test_fd, "inside_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 7: File within the directory");
864 unlinkat(test_fd, "inside_file_2.txt", 0);
865
866 /* Test Case 8: File using a symlink pointing outside */
867 T_EXPECT_POSIX_FAILURE(clonefileat(test_fd, "symlink", test_fd, "inside_file_2.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 8: File using a symlink pointing outside");
868
869 /* Test Case 9: Attempt to open a file using ".." to navigate outside */
870 T_EXPECT_POSIX_FAILURE(clonefileat(test_fd, "inside_file.txt", test_fd, "../outside_file.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: File using \"..\" to navigate outside");
871
872 /* Test Case 10: File within a nested directory */
873 T_EXPECT_POSIX_SUCCESS(clonefileat(test_fd, "nested/nested_file.txt", test_fd, "nested/nested_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 10: File within a nested directory");
874 unlinkat(test_fd, "nested/nested_file_2.txt", 0);
875
876 /* Test Case 11: Symlink to a file in a nested directory */
877 T_EXPECT_POSIX_SUCCESS(clonefileat(test_fd, "symlink_to_nested", test_fd, "nested/nested_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 11: Symlink to a file within the same directory");
878 unlinkat(test_fd, "nested/nested_file_2.txt", 0);
879
880 /* Test Case 12: File using an absolute path */
881 T_EXPECT_POSIX_FAILURE(clonefileat(test_fd, "/etc/passwd", test_fd, "inside_file_2.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 12: File using an absolute path");
882
883 T_LOG("Testing the fclonefileat() syscall using CLONE_RESOLVE_BENEATH");
884
885 /* Test Case 13: File within the directory */
886 T_EXPECT_POSIX_SUCCESS(fclonefileat(fd, test_fd, "inside_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 13: File within the directory");
887 unlinkat(test_fd, "inside_file_2.txt", 0);
888
889 /* Test Case 14: File using a symlink pointing outside */
890 T_EXPECT_POSIX_FAILURE(fclonefileat(fd, test_fd, "symlink_absolute/test_dir/inside_file.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 14: File using a symlink pointing outside");
891
892 /* Test Case 15: Attempt to open a file using ".." to navigate outside */
893 T_EXPECT_POSIX_FAILURE(fclonefileat(fd, test_fd, "../outside_file.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 15: File using \"..\" to navigate outside");
894
895 /* Test Case 16: File within a nested directory */
896 T_EXPECT_POSIX_SUCCESS(fclonefileat(fd, test_fd, "nested/nested_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 16: File within a nested directory");
897 unlinkat(test_fd, "nested/nested_file_2.txt", 0);
898
899 /* Test Case 17: Symlink to a file in a nested directory */
900 T_EXPECT_POSIX_SUCCESS(fclonefileat(fd, test_fd, "nested/nested_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 17: Symlink to a file within the same directory");
901 unlinkat(test_fd, "nested/nested_file_2.txt", 0);
902
903 /* Test Case 18: File using an absolute path */
904 T_EXPECT_POSIX_FAILURE(fclonefileat(fd, test_fd, "/etc/inside_file_2.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 18: File using an absolute path");
905
906 T_EXPECT_POSIX_SUCCESS(close(fd), "Closing %s", INSIDE_FILE);
907 }
908
909 T_DECL(resolve_beneath_renamex_np,
910 "test renamex_np()/renameatx_np() using the RENAME_RESOLVE_BENEATH flag")
911 {
912 T_SETUPBEGIN;
913
914 T_ATEND(cleanup);
915 setup("resolve_beneath_renamex_np");
916
917 /* Changing current directory to the test directory */
918 T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
919
920 T_SETUPEND;
921
922 T_LOG("Testing the renamex_np() syscall using RENAME_RESOLVE_BENEATH");
923
924 /* Test Case 1: File within the directory */
925 T_EXPECT_POSIX_SUCCESS(renamex_np("inside_file.txt", "inside_file_2.txt", RENAME_RESOLVE_BENEATH), "Test Case 1: File within the directory");
926 if (renamex_np("inside_file_2.txt", "inside_file.txt", 0)) {
927 T_FAIL("Unable to rename inside_file_2.txt to inside_file.txt");
928 }
929
930 /* Test Case 2: File using a symlink pointing outside */
931 T_EXPECT_POSIX_FAILURE(renamex_np("symlink/.", "inside_file_2.txt", RENAME_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
932
933 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
934 T_EXPECT_POSIX_FAILURE(renamex_np("inside_file.txt", "../outside_file.txt", RENAME_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
935
936 /* Test Case 4: File within a nested directory */
937 T_EXPECT_POSIX_SUCCESS(renamex_np("nested/nested_file.txt", "nested/nested_file_2.txt", RENAME_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
938 if (renamex_np("nested/nested_file_2.txt", "nested/nested_file.txt", 0)) {
939 T_FAIL("Unable to rename nested/nested_file_2.txt to nested/nested_file.txt");
940 }
941
942 /* Test Case 5: Symlink to a file in a nested directory */
943 T_EXPECT_POSIX_SUCCESS(renamex_np("symlink_to_nested", "nested/nested_file_2.txt", RENAME_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
944 if (renamex_np("nested/nested_file_2.txt", "symlink_to_nested", 0)) {
945 T_FAIL("Unable to rename nested/nested_file_2.txt to symlink_to_nested");
946 }
947
948 /* Test Case 6: File using an absolute path */
949 T_EXPECT_POSIX_FAILURE(renamex_np("/etc/passwd", "inside_file_2.txt", RENAME_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
950
951 T_LOG("Testing the renameatx_np() syscall using RENAME_RESOLVE_BENEATH");
952
953 /* Test Case 7: File within the directory */
954 T_EXPECT_POSIX_SUCCESS(renameatx_np(test_fd, "inside_file.txt", test_fd, "inside_file_2.txt", RENAME_RESOLVE_BENEATH), "Test Case 7: File within the directory");
955 if (renamex_np("inside_file_2.txt", "inside_file.txt", 0)) {
956 T_FAIL("Unable to rename inside_file_2.txt to inside_file.txt");
957 }
958
959 /* Test Case 8: File using a symlink pointing outside */
960 T_EXPECT_POSIX_FAILURE(renameatx_np(test_fd, "symlink/.", test_fd, "inside_file_2.txt", RENAME_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 8: File using a symlink pointing outside");
961
962 /* Test Case 9: Attempt to open a file using ".." to navigate outside */
963 T_EXPECT_POSIX_FAILURE(renameatx_np(test_fd, "inside_file.txt", test_fd, "../outside_file.txt", RENAME_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: File using \"..\" to navigate outside");
964
965 /* Test Case 10: File within a nested directory */
966 T_EXPECT_POSIX_SUCCESS(renameatx_np(test_fd, "nested/nested_file.txt", test_fd, "nested/nested_file_2.txt", RENAME_RESOLVE_BENEATH), "Test Case 10: File within a nested directory");
967 if (renamex_np("nested/nested_file_2.txt", "nested/nested_file.txt", 0)) {
968 T_FAIL("Unable to rename nested/nested_file_2.txt to nested/nested_file.txt");
969 }
970
971 /* Test Case 11: Symlink to a file in a nested directory */
972 T_EXPECT_POSIX_SUCCESS(renameatx_np(test_fd, "symlink_to_nested", test_fd, "nested/nested_file_2.txt", RENAME_RESOLVE_BENEATH), "Test Case 11: Symlink to a file within the same directory");
973 if (renamex_np("nested/nested_file_2.txt", "symlink_to_nested", 0)) {
974 T_FAIL("Unable to rename nested/nested_file_2.txt to symlink_to_nested");
975 }
976
977 /* Test Case 12: File using an absolute path */
978 T_EXPECT_POSIX_FAILURE(renameatx_np(test_fd, "/etc/passwd", test_fd, "inside_file_2.txt", RENAME_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 12: File using an absolute path");
979 }
980
981 T_DECL(resolve_beneath_getattrlist,
982 "test getattrlist()/fgetattrlist()/getattrlistat() using the FSOPT_RESOLVE_BENEATH flag")
983 {
984 int fd;
985
986 struct myattrbuf {
987 uint32_t length;
988 attribute_set_t returned_attrs;
989 vol_attributes_attr_t vol_attributes;
990 attrreference_t fstypename_ref;
991 uint32_t fssubtype;
992 char fstypename[MFSTYPENAMELEN];
993 } attrbuf;
994
995 struct attrlist attrs = {
996 .bitmapcount = ATTR_BIT_MAP_COUNT,
997 .commonattr = ATTR_CMN_RETURNED_ATTRS,
998 /*
999 * Request ATTR_VOL_ATTRIBUTES to ensure that
1000 * ATTR_VOL_FSTYPENAME and ATTR_VOL_FSSUBTYPE
1001 * are packed into the buffer *after*.
1002 */
1003 .volattr = ATTR_VOL_INFO | ATTR_VOL_ATTRIBUTES |
1004 ATTR_VOL_FSTYPENAME | ATTR_VOL_FSSUBTYPE,
1005 };
1006
1007 T_SETUPBEGIN;
1008
1009 T_ATEND(cleanup);
1010 setup("resolve_beneath_getattrlist");
1011
1012 /* Changing current directory to the test directory */
1013 T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
1014
1015 /* Open test file */
1016 T_ASSERT_POSIX_SUCCESS((fd = open("inside_file.txt", O_RDWR, 0777)), "Opening %s", INSIDE_FILE);
1017
1018 T_SETUPEND;
1019
1020 T_LOG("Testing the getattrlist() syscall using FSOPT_RESOLVE_BENEATH");
1021
1022 /* Test Case 1: File within the directory */
1023 T_EXPECT_POSIX_SUCCESS(getattrlist("inside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
1024
1025 /* Test Case 2: File using a symlink pointing outside */
1026 T_EXPECT_POSIX_FAILURE(getattrlist("symlink", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
1027
1028 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
1029 T_EXPECT_POSIX_FAILURE(getattrlist("../outside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
1030
1031 /* Test Case 4: File within a nested directory */
1032 T_EXPECT_POSIX_SUCCESS(getattrlist("nested/nested_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
1033
1034 /* Test Case 5: Symlink to a file in a nested directory */
1035 T_EXPECT_POSIX_SUCCESS(getattrlist("symlink_to_nested", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
1036
1037 /* Test Case 6: File using an absolute path */
1038 T_EXPECT_POSIX_FAILURE(getattrlist("/etc/passwd", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
1039
1040 /* Test Case 7: Valid symlink to parent directory */
1041 T_EXPECT_POSIX_FAILURE(getattrlist("parent_symlink/outside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
1042
1043 /* Test Case 8: Circular symlink within directory */
1044 T_EXPECT_POSIX_FAILURE(getattrlist("circular_symlink", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
1045
1046 /* Test Case 9: Path can not escape outside at any point of the resolution */
1047 T_EXPECT_POSIX_FAILURE(getattrlist("../test_dir/inside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
1048
1049 /* Test Case 10: File using a symlink pointing to absolute path */
1050 T_EXPECT_POSIX_FAILURE(getattrlist("symlink_absolute/test_dir/inside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
1051
1052 T_LOG("Testing the fgetattrlist() syscall using FSOPT_RESOLVE_BENEATH");
1053
1054 /* Test Case 11: fgetattrlist() syscall using FSOPT_RESOLVE_BENEATH */
1055 T_EXPECT_POSIX_SUCCESS(fgetattrlist(fd, &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 11: fgetattrlist() syscall using FSOPT_RESOLVE_BENEATH");
1056
1057 T_LOG("Testing the getattrlistat() syscall using FSOPT_RESOLVE_BENEATH");
1058
1059 /* Test Case 12: File within the directory */
1060 T_EXPECT_POSIX_SUCCESS(getattrlistat(test_fd, "inside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 12: File within the directory");
1061
1062 /* Test Case 13: File using a symlink pointing outside */
1063 T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "symlink", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 13: File using a symlink pointing outside");
1064
1065 /* Test Case 14: Attempt to open a file using ".." to navigate outside */
1066 T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "../outside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 14: File using \"..\" to navigate outside");
1067
1068 /* Test Case 15: File within a nested directory */
1069 T_EXPECT_POSIX_SUCCESS(getattrlistat(test_fd, "nested/nested_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 15: File within a nested directory");
1070
1071 /* Test Case 16: Symlink to a file in a nested directory */
1072 T_EXPECT_POSIX_SUCCESS(getattrlistat(test_fd, "symlink_to_nested", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 16: Symlink to a file within the same directory");
1073
1074 /* Test Case 17: File using an absolute path */
1075 T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "/etc/passwd", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 17: File using an absolute path");
1076
1077 /* Test Case 18: Valid symlink to parent directory */
1078 T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "parent_symlink/outside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 18: Valid symlink to parent directory");
1079
1080 /* Test Case 19: Circular symlink within directory */
1081 T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "circular_symlink", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ELOOP, "Test Case 19: Circular symlink within directory");
1082
1083 /* Test Case 20: Path can not escape outside at any point of the resolution */
1084 T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "../test_dir/inside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 20: Path can not escape outside at any point of the resolution");
1085
1086 /* Test Case 21: File using a symlink pointing to absolute path */
1087 T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "symlink_absolute/test_dir/inside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 21: File using a symlink pointing to absolute path");
1088
1089 T_EXPECT_POSIX_SUCCESS(close(fd), "Closing %s", INSIDE_FILE);
1090 }
1091
1092 T_DECL(resolve_beneath_setattrlist,
1093 "test setattrlist()/fsetattrlist()/setattrlistat() using the FSOPT_RESOLVE_BENEATH flag")
1094 {
1095 int fd;
1096 int flags;
1097 struct attrlist attrlist;
1098
1099 T_SETUPBEGIN;
1100
1101 flags = 0;
1102 memset(&attrlist, 0, sizeof(attrlist));
1103 attrlist.bitmapcount = ATTR_BIT_MAP_COUNT;
1104 attrlist.commonattr = ATTR_CMN_FLAGS;
1105
1106 T_ATEND(cleanup);
1107 setup("resolve_beneath_setattrlist");
1108
1109 /* Changing current directory to the test directory */
1110 T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
1111
1112 /* Open test file */
1113 T_ASSERT_POSIX_SUCCESS((fd = open("inside_file.txt", O_RDWR, 0777)), "Opening %s", INSIDE_FILE);
1114
1115 T_SETUPEND;
1116
1117 T_LOG("Testing the setattrlist() syscall using FSOPT_RESOLVE_BENEATH");
1118
1119 /* Test Case 1: File within the directory */
1120 T_EXPECT_POSIX_SUCCESS(setattrlist("inside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
1121
1122 /* Test Case 2: File using a symlink pointing outside */
1123 T_EXPECT_POSIX_FAILURE(setattrlist("symlink", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
1124
1125 /* Test Case 3: Attempt to open a file using ".." to navigate outside */
1126 T_EXPECT_POSIX_FAILURE(setattrlist("../outside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
1127
1128 /* Test Case 4: File within a nested directory */
1129 T_EXPECT_POSIX_SUCCESS(setattrlist("nested/nested_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
1130
1131 /* Test Case 5: Symlink to a file in a nested directory */
1132 T_EXPECT_POSIX_SUCCESS(setattrlist("symlink_to_nested", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
1133
1134 /* Test Case 6: File using an absolute path */
1135 T_EXPECT_POSIX_FAILURE(setattrlist("/etc/passwd", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
1136
1137 /* Test Case 7: Valid symlink to parent directory */
1138 T_EXPECT_POSIX_FAILURE(setattrlist("parent_symlink/outside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
1139
1140 /* Test Case 8: Circular symlink within directory */
1141 T_EXPECT_POSIX_FAILURE(setattrlist("circular_symlink", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
1142
1143 /* Test Case 9: Path can not escape outside at any point of the resolution */
1144 T_EXPECT_POSIX_FAILURE(setattrlist("../test_dir/inside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
1145
1146 /* Test Case 10: File using a symlink pointing to absolute path */
1147 T_EXPECT_POSIX_FAILURE(setattrlist("symlink_absolute/test_dir/inside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
1148
1149 T_LOG("Testing the fsetattrlist() syscall using FSOPT_RESOLVE_BENEATH");
1150
1151 /* Test Case 11: fsetattrlist() syscall using FSOPT_RESOLVE_BENEATH */
1152 T_EXPECT_POSIX_SUCCESS(fsetattrlist(fd, &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 11: fsetattrlist() syscall using FSOPT_RESOLVE_BENEATH");
1153
1154 T_LOG("Testing the setattrlistat() syscall using FSOPT_RESOLVE_BENEATH");
1155
1156 /* Test Case 12: File within the directory */
1157 T_EXPECT_POSIX_SUCCESS(setattrlistat(test_fd, "inside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 12: File within the directory");
1158
1159 /* Test Case 13: File using a symlink pointing outside */
1160 T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "symlink", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 13: File using a symlink pointing outside");
1161
1162 /* Test Case 14: Attempt to open a file using ".." to navigate outside */
1163 T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "../outside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 14: File using \"..\" to navigate outside");
1164
1165 /* Test Case 15: File within a nested directory */
1166 T_EXPECT_POSIX_SUCCESS(setattrlistat(test_fd, "nested/nested_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 15: File within a nested directory");
1167
1168 /* Test Case 16: Symlink to a file in a nested directory */
1169 T_EXPECT_POSIX_SUCCESS(setattrlistat(test_fd, "symlink_to_nested", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 16: Symlink to a file within the same directory");
1170
1171 /* Test Case 17: File using an absolute path */
1172 T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "/etc/passwd", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 17: File using an absolute path");
1173
1174 /* Test Case 18: Valid symlink to parent directory */
1175 T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "parent_symlink/outside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 18: Valid symlink to parent directory");
1176
1177 /* Test Case 19: Circular symlink within directory */
1178 T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "circular_symlink", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ELOOP, "Test Case 19: Circular symlink within directory");
1179
1180 /* Test Case 20: Path can not escape outside at any point of the resolution */
1181 T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "../test_dir/inside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 20: Path can not escape outside at any point of the resolution");
1182
1183 /* Test Case 21: File using a symlink pointing to absolute path */
1184 T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "symlink_absolute/test_dir/inside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 21: File using a symlink pointing to absolute path");
1185
1186 T_EXPECT_POSIX_SUCCESS(close(fd), "Closing %s", INSIDE_FILE);
1187 }
1188