]> git.saurik.com Git - apple/libc.git/blob - tests/subsystem_test.c
Libc-1439.100.3.tar.gz
[apple/libc.git] / tests / subsystem_test.c
1 /*
2 * Copyright (c) 2019 Apple 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 #include <fcntl.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <spawn.h>
33 #include <spawn_private.h>
34 #include <sys/wait.h>
35 #include <unistd.h>
36 #include "subsystem_test.h"
37
38 #include <darwintest.h>
39 #include <darwintest_utils.h>
40
41 #define RANDOM_STRING_LEN 33
42
43 #define HELPER_PATH "./subsystem_test_helper"
44
45 /* Create the given file. Doesn't create directories. */
46 static bool
47 _create_file(char * const filepath)
48 {
49 bool success = false;
50 int fd = open(filepath, O_CREAT | O_EXCL, 0666);
51
52 if (fd >= 0) {
53 close(fd);
54 success = true;
55 }
56
57 return success;
58 }
59
60 /* Fills the given buffer with a random alphanumeric string. */
61 static void
62 _generate_random_string(char * buf, size_t buf_len)
63 {
64
65 static char _alphanumeric[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
66 size_t cur_byte = 0;
67
68 if (buf_len == 0) {
69 return;
70 }
71
72 for (cur_byte = 0; ((buf_len - cur_byte) > 1); cur_byte++) {
73 buf[cur_byte] = _alphanumeric[rand() % (sizeof(_alphanumeric) - 1)];
74 }
75
76 buf[cur_byte] = 0;
77
78 return;
79 }
80
81 /* Compares the contents of the given file with the buffer. */
82 static int
83 _check_file_contents(char * const filepath, char * const buf, size_t buf_len)
84 {
85 int result = 1;
86 int fd = -1;
87 char file_buf[buf_len];
88
89 fd = open(filepath, O_RDONLY);
90
91 if (fd >= 0) {
92 read(fd, file_buf, buf_len);
93 close(fd);
94
95 result = memcmp(buf, file_buf, buf_len);
96 }
97
98 return result;
99 }
100
101 /* Spawn with the given args and attributes, and waits for the child. */
102 static int
103 _spawn_and_wait(char ** args, posix_spawnattr_t *attr)
104 {
105 int pid;
106 int status;
107
108 if (posix_spawn(&pid, args[0], NULL, attr, args, NULL)) {
109 return -1;
110 }
111 if (waitpid(pid, &status, 0) < 0) {
112 return -1;
113 }
114
115 if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)) {
116 return 0;
117 }
118
119 return -1;
120 }
121
122 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
123
124 T_DECL(subsystem,
125 "Test the subsystem-related functions",
126 T_META_CHECK_LEAKS(false))
127 {
128 int result = 0;
129 int pid = 0;
130 posix_spawnattr_t attr = NULL;
131
132 char file_name[RANDOM_STRING_LEN];
133 char overflow_file_name[PATH_MAX - RANDOM_STRING_LEN];
134 char subsystem_name[RANDOM_STRING_LEN];
135
136 char file_path[PATH_MAX];
137 char subsystem_path[PATH_MAX];
138 char subsystem_tmp_path[PATH_MAX];
139 char subsystem_file_path[PATH_MAX];
140 char overflow_file_path[PATH_MAX];
141 char overflow_subsystem_file_path[PATH_MAX];
142
143 char * args[] = { HELPER_PATH, HELPER_BEHAVIOR_NOT_SET, overflow_file_path, "", NULL};
144
145 /* Seed rand() from /dev/random, and generate our random file names. */
146 sranddev();
147 _generate_random_string(file_name, sizeof(file_name));
148 _generate_random_string(overflow_file_name, sizeof(overflow_file_name));
149 _generate_random_string(subsystem_name, sizeof(subsystem_name));
150
151 /* Generate pathnames. */
152 sprintf(file_path, "/tmp/%s", file_name);
153 sprintf(overflow_file_path, "/tmp/%s", overflow_file_name);
154 sprintf(subsystem_path, "/tmp/%s", subsystem_name);
155 sprintf(subsystem_tmp_path, "%s/tmp", subsystem_path);
156 sprintf(subsystem_file_path, "%s/%s", subsystem_path, file_path);
157
158 /*
159 * Initial setup for the test; we'll need our subsystem
160 * directory and a /tmp/ for it.
161 */
162 T_QUIET; T_ASSERT_POSIX_SUCCESS(mkdir(subsystem_path, 0777), "Create subsystem directory");
163 T_QUIET; T_ASSERT_POSIX_SUCCESS(mkdir(subsystem_tmp_path, 0777), "Create subsystem /tmp/ directory");
164 T_QUIET; T_ASSERT_POSIX_SUCCESS(posix_spawnattr_init(&attr), "posix_spawnattr_init");
165
166 /* open and stat with no subsystem. */
167 args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
168 T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), -1, "open_with_subsystem with no subsystem");
169
170 args[1] = HELPER_BEHAVIOR_STAT_NONE;
171 T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with no subsystem");
172
173 T_QUIET; T_ASSERT_POSIX_SUCCESS(posix_spawnattr_set_subsystem_root_path_np(&attr, subsystem_path), "Set subsystem root path");
174
175 /*
176 * Test behavior when there is no main file and the subsystem
177 * file path is longer than PATH_MAX.
178 */
179 args[1] = HELPER_BEHAVIOR_OPEN_OVERFLOW;
180
181 T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "open_with_subsystem with overflow");
182
183 args[1] = HELPER_BEHAVIOR_STAT_OVERFLOW;
184
185 T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with overflow");
186
187 /* O_CREAT is strictly disallowed; test this. */
188 args[1] = HELPER_BEHAVIOR_OPEN_O_CREAT;
189 args[2] = file_path;
190
191 T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "open_with_subsystem with O_CREAT");
192
193 /*
194 * Test valid use of open_with_subsystem and
195 * stat_with_subsystem. We've got 4 cases to
196 * test: neither file exists, the subsystem
197 * file exists, both files exist, and the
198 * main fail exists.
199 */
200 /* Neither file exists. */
201 args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
202
203 T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), -1, "open_with_subsystem with no file");
204
205 args[1] = HELPER_BEHAVIOR_STAT_NONE;
206
207 T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with no file");
208
209 /* Subsystem file exists. */
210 T_QUIET; T_ASSERT_TRUE(_create_file(subsystem_file_path), "Create subsystem file");
211
212 args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
213 args[3] = "with subsystem file";
214
215 result = _spawn_and_wait(args, &attr);
216
217 if (!result) {
218 result = _check_file_contents(subsystem_file_path, args[3], strlen(args[3]));
219 }
220
221 T_ASSERT_EQ_INT(result, 0, "open_with_subsystem with subsystem file");
222
223 args[1] = HELPER_BEHAVIOR_STAT_NOT_MAIN;
224
225 T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with subsystem file");
226
227 /* Both files exist. */
228 T_QUIET; T_ASSERT_TRUE(_create_file(file_path), "Create main file");
229
230 args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
231 args[3] = "with both files";
232
233 result = _spawn_and_wait(args, &attr);
234
235 if (!result) {
236 result = _check_file_contents(file_path, args[3], strlen(args[3]));
237 }
238
239 T_ASSERT_EQ_INT(result, 0, "open_with_subsystem with both files");
240
241 args[1] = HELPER_BEHAVIOR_STAT_MAIN;
242
243 T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with both files");
244
245 /* Main file exists. */
246 T_QUIET; T_EXPECT_POSIX_SUCCESS(unlink(subsystem_file_path), "Delete subsystem file");
247
248 args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
249 args[3] = "with main file";
250
251 result = _spawn_and_wait(args, &attr);
252
253 if (!result) {
254 result = _check_file_contents(file_path, args[3], strlen(args[3]));
255 }
256
257 T_ASSERT_EQ_INT(result, 0, "open_with_subsystem with main file");
258
259 args[1] = HELPER_BEHAVIOR_STAT_MAIN;
260
261 T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with main file");
262
263 /* We're done; clean everything up. */
264 T_QUIET; T_EXPECT_POSIX_SUCCESS(unlink(file_path), "Delete main file");
265 T_QUIET; T_EXPECT_POSIX_SUCCESS(rmdir(subsystem_tmp_path), "Remove subsystem /tmp/ directory");
266 T_QUIET; T_EXPECT_POSIX_SUCCESS(rmdir(subsystem_path), "Remove subsystem directory");
267 T_QUIET; T_ASSERT_POSIX_SUCCESS(posix_spawnattr_destroy(&attr), "posix_spawnattr_destroy");
268 }