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 -lsandbox -o sandbox_fstat sandbox_fstat.c -g -Weverything */
30
31 #include <sys/paths.h>
32 #include <sys/xattr.h>
33 #include <sandbox/libsandbox.h>
34 #include <TargetConditionals.h>
35
36 #include <darwintest.h>
37 #include <darwintest/utils.h>
38
39 #define RUN_TEST TARGET_OS_OSX
40
41 static char template[MAXPATHLEN];
42 static char *testdir = NULL;
43 static char file[PATH_MAX], file_rsrcfork[PATH_MAX];
44 static sandbox_params_t params = NULL;
45 static sandbox_profile_t profile = NULL;
46
47 T_GLOBAL_META(
48 T_META_NAMESPACE("xnu.vfs"),
49 T_META_RADAR_COMPONENT_NAME("xnu"),
50 T_META_RADAR_COMPONENT_VERSION("vfs"),
51 T_META_ASROOT(false),
52 T_META_ENABLED(RUN_TEST),
53 T_META_CHECK_LEAKS(false));
54
55 static void
cleanup(void)56 cleanup(void)
57 {
58 if (profile) {
59 sandbox_free_profile(profile);
60 }
61 if (params) {
62 sandbox_free_params(params);
63 }
64 if (file[0] != '\0') {
65 unlink(file);
66 }
67 if (testdir) {
68 rmdir(testdir);
69 }
70 }
71
72 static void
create_profile_string(char * buff,size_t size)73 create_profile_string(char *buff, size_t size)
74 {
75 snprintf(buff, size, "(version 1) \n\
76 (allow default) \n\
77 (import \"system.sb\") \n\
78 (deny file-read-metadata (path \"%s\")) \n",
79 file);
80 }
81 static void
do_test(int expected_error)82 do_test(int expected_error)
83 {
84 int fd;
85 struct stat sb;
86
87 /* Test stat() */
88 if (expected_error) {
89 T_EXPECT_POSIX_FAILURE(stat(file, &sb), expected_error, "Calling stat() should FAIL with '%s'", strerror(expected_error));
90 } else {
91 T_EXPECT_POSIX_SUCCESS(stat(file, &sb), "Calling stat() for the file should PASS");
92 }
93
94 /* Test fstat() while the file is open with the O_CREAT | O_WRONLY flags */
95 T_EXPECT_POSIX_SUCCESS(fd = open(file, O_CREAT | O_WRONLY, 0666), "Opening with the O_CREAT | O_WRONLY flags");
96 if (fd != -1) {
97 if (expected_error) {
98 T_EXPECT_POSIX_FAILURE(fstat(fd, &sb), expected_error, "Calling fstat() should FAIL with '%s'", strerror(expected_error));
99 } else {
100 T_EXPECT_POSIX_SUCCESS(fstat(fd, &sb), "Calling fstat() for the test file should PASS");
101 }
102 close(fd);
103 }
104
105 T_EXPECT_POSIX_SUCCESS(fd = open(file_rsrcfork, O_CREAT | O_WRONLY, 0666), "Opening rsrcfork with the O_CREAT | O_WRONLY flags");
106 if (fd != -1) {
107 T_EXPECT_POSIX_SUCCESS(fstat(fd, &sb), "Calling fstat() for the rsrcfork should PASS");
108 close(fd);
109 }
110 }
111
112 T_DECL(sandbox_fstat,
113 "Prevent the information disclosure on files opened with O_WRONLY while sandbox profile denies 'file-read-metadata'")
114 {
115 #if (!RUN_TEST)
116 T_SKIP("Not macOS");
117 #endif
118
119 int fd;
120 char *sberror = NULL;
121 char profile_string[1000];
122 char testdir_path[MAXPATHLEN];
123
124 file[0] = '\0';
125
126 T_ATEND(cleanup);
127 T_SETUPBEGIN;
128
129 /* Create test root dir */
130 snprintf(template, sizeof(template), "%s/sandbox_fstat-XXXXXX", dt_tmpdir());
131 T_ASSERT_POSIX_NOTNULL((testdir = mkdtemp(template)), "Creating test root dir");
132 T_ASSERT_POSIX_SUCCESS((fd = open(testdir, O_SEARCH, 0777)), "Opening test root directory '%s'", testdir);
133 T_ASSERT_POSIX_SUCCESS(fcntl(fd, F_GETPATH, testdir_path), "Calling fcntl() to get the path");
134 T_ASSERT_POSIX_SUCCESS(close(fd), "Closing %s", testdir_path);
135
136 /* Setup file names */
137 snprintf(file, sizeof(file), "%s/%s", testdir_path, "file");
138 snprintf(file_rsrcfork, sizeof(file_rsrcfork), "%s/%s", file, _PATH_RSRCFORKSPEC);
139
140 /* Create the test file */
141 T_ASSERT_POSIX_SUCCESS((fd = open(file, O_CREAT | O_RDWR, 0777)), "Creating '%s'", file);
142 T_ASSERT_POSIX_SUCCESS(close(fd), "Closing '%s'", file);
143
144 /* Create sandbox variables */
145 T_ASSERT_POSIX_NOTNULL(params = sandbox_create_params(), "Creating Sandbox params object");
146 create_profile_string(profile_string, sizeof(profile_string));
147 T_ASSERT_POSIX_NOTNULL(profile = sandbox_compile_string(profile_string, params, &sberror), "Creating Sandbox profile object");
148
149 T_SETUPEND;
150
151 /* Test stat()/fstat() */
152 do_test(0);
153
154 /* Apply sandbox profile */
155 T_ASSERT_POSIX_SUCCESS(sandbox_apply(profile), "Applying Sandbox profile");
156
157 /* Test stat()/fstat() */
158 do_test(EPERM);
159 }
160