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_type_error sandbox_type_error.c -g -Weverything */
30
31 #include <sandbox/libsandbox.h>
32 #include <TargetConditionals.h>
33
34 #include <darwintest.h>
35 #include <darwintest/utils.h>
36
37 #define RUN_TEST TARGET_OS_OSX
38
39 static sandbox_params_t params = NULL;
40
41 T_GLOBAL_META(
42 T_META_NAMESPACE("xnu.vfs"),
43 T_META_RADAR_COMPONENT_NAME("xnu"),
44 T_META_RADAR_COMPONENT_VERSION("vfs"),
45 T_META_ASROOT(false),
46 T_META_ENABLED(RUN_TEST),
47 T_META_CHECK_LEAKS(false));
48
49 static void
cleanup(void)50 cleanup(void)
51 {
52 if (params) {
53 sandbox_free_params(params);
54 }
55 }
56
57 static void
create_profile_string(char * buff,size_t size,char * path)58 create_profile_string(char *buff, size_t size, char *path)
59 {
60 snprintf(buff, size, "(version 1) \n\
61 (allow default) \n\
62 (deny file-read-metadata (path \"%s\")) \n",
63 path);
64 }
65
66 static void
test_path(char * deny_path,char * stat_path,int expected_err)67 test_path(char *deny_path, char *stat_path, int expected_err)
68 {
69 struct stat sb;
70 pid_t pid, res;
71 char *sberror = NULL;
72 char profile_string[1000];
73 sandbox_profile_t profile = NULL;
74 int status, error, ret;
75
76 /* Fork */
77 pid = fork();
78 if (pid < -1) {
79 T_FAIL("Failed to fork");
80 return;
81 }
82
83 switch (pid) {
84 case 0:
85 /* Create sandbox variables */
86 create_profile_string(profile_string, sizeof(profile_string), deny_path);
87 if ((profile = sandbox_compile_string(profile_string, params, &sberror)) == NULL) {
88 T_FAIL("Creating Sandbox profile object");
89 exit(EINVAL);
90 }
91
92 error = sandbox_apply(profile);
93 if (error) {
94 T_FAIL("Applying Sandbox profile FAILED");
95 sandbox_free_profile(profile);
96 exit(EINVAL);
97 }
98
99 /* Query stat */
100 error = stat(stat_path, &sb);
101
102 /* Validate error */
103 if ((!error && !expected_err) || (error == -1 && errno == expected_err)) {
104 ret = 0;
105 } else {
106 ret = errno;
107 }
108
109 if (profile) {
110 sandbox_free_profile(profile);
111 }
112 exit(ret);
113 default:
114 do {
115 res = waitpid(pid, &status, WUNTRACED);
116 } while (res == -1 && errno == EINTR);
117
118 if (res != pid) {
119 T_FAIL("(res != pid");
120 break;
121 }
122
123 if (!WIFEXITED(status)) {
124 T_FAIL("Stat of '%s' with deny path of '%s' FAILED", stat_path, deny_path);
125 break;
126 }
127
128 if (WEXITSTATUS(status)) {
129 T_FAIL("Stat of '%s' with deny path of '%s' should FAIL with '%s', got '%s'", stat_path, deny_path, strerror(expected_err), strerror(WEXITSTATUS(status)));
130 break;
131 }
132
133 if (expected_err) {
134 T_PASS("Stat of '%s' with deny path of '%s' should FAIL with '%s'", stat_path, deny_path, strerror(expected_err));
135 } else {
136 T_PASS("Stat of '%s' with deny path of '%s' should PASS", stat_path, deny_path);
137 }
138 }
139 }
140
141 T_DECL(sandbox_type_error,
142 "Prevent the information disclosure on resource type File/Directory/Symlink")
143 {
144 #if (!RUN_TEST)
145 T_SKIP("Not macOS");
146 #endif
147
148 T_ATEND(cleanup);
149 T_SETUPBEGIN;
150
151 T_ASSERT_POSIX_NOTNULL(params = sandbox_create_params(), "Creating Sandbox params object");
152
153 T_SETUPEND;
154
155 /* Verify handling of non-existent files */
156 test_path("/.file", "/.nofollow/notexist/", ENOENT);
157
158 /* Prevent the information disclosure on the resource type for file */
159 test_path("/.file", "/.nofollow/.file/", EPERM);
160
161 /* Prevent the information disclosure on the resource type for directory */
162 test_path("/private", "/.nofollow/private/", EPERM);
163
164 /* Prevent the information disclosure on the resource type for symlink */
165 test_path("/tmp", "/.nofollow/tmp/", EPERM);
166
167 /* Prevent the information disclosure on the resource type for symlink child */
168 test_path("/tmp", "/.nofollow/tmp/notexist", EPERM);
169 }
170