xref: /xnu-12377.81.4/tests/vfs/sandbox_type_error.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
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