Loading...
--- xnu/xnu-12377.121.6/tests/sysctl_procargs_no_read.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (c) 2026 Apple Inc. All rights reserved.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. The rights granted to you under the License
- * may not be used to create, or enable the creation or redistribution of,
- * unlawful or unlicensed copies of an Apple operating system, or to
- * circumvent, violate, or enable the circumvention or violation of, any
- * terms of an Apple operating system software license agreement.
- *
- * Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
- */
-#include <darwintest.h>
-#include <sys/param.h>
-#include <sys/sysctl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <mach-o/dyld.h>
-#include <spawn.h>
-#include <string.h>
-#include <stdbool.h>
-
-T_GLOBAL_META(
- T_META_NAMESPACE("xnu.sysctl"),
- T_META_RADAR_COMPONENT_NAME("xnu"),
- T_META_RADAR_COMPONENT_VERSION("sysctl"),
- T_META_CHECK_LEAKS(false),
- T_META_RUN_CONCURRENTLY(true),
- T_META_REQUIRES_PLATFORM_BINARY(true));
-
-static int
-read_procargs(pid_t pid, char *buf, size_t buf_size, size_t *out_size)
-{
- int mib[3];
- size_t size = buf_size;
- int ret;
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROCARGS2;
- mib[2] = pid;
-
- ret = sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &size, NULL, 0);
- if (out_size) {
- *out_size = size;
- }
- return ret;
-}
-
-static int
-read_procargs1(pid_t pid, char *buf, size_t buf_size, size_t *out_size)
-{
- int mib[3] = { CTL_KERN, KERN_PROCARGS, pid };
- size_t size = buf_size;
- int ret = sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &size, NULL, 0);
- if (out_size) {
- *out_size = size;
- }
- return ret;
-}
-
-T_HELPER_DECL(sleeper, "Helper that sleeps")
-{
- raise(SIGSTOP);
-}
-
-T_HELPER_DECL(execer, "Helper that execs non-entitled binary")
-{
- execv("/bin/sleep", (char *[]){"/bin/sleep", "1000", NULL});
-}
-
-static void
-verify_hidden_procargs(pid_t child_pid, char *exec_path_out)
-{
- char buf[sizeof(int) + MAXPATHLEN + 1 + MAXPATHLEN + 1];
- size_t out_size;
- int ret = read_procargs(child_pid, buf, sizeof(buf), &out_size);
- T_ASSERT_POSIX_SUCCESS(ret, "read_procargs()");
-
- T_ASSERT_GT_ULONG(out_size, sizeof(int) + 1, "read_procargs should return enough data");
-
- int child_argc;
- memcpy(&child_argc, buf, sizeof(int));
- char *exec_name = buf + sizeof(int);
- char *argv_0 = exec_name + strlen(exec_name) + 2; /* + 1 for null terminator, + 1 for padding */
-
- T_LOG("read procargs: argc = %d, exec name = %s, argv[0] = %s\n", child_argc, exec_name, argv_0);
-
- T_ASSERT_EQ(child_argc, 1, "argc should be 1 (synthesized)");
- T_ASSERT_EQ_STR(exec_name, argv_0, "exec_name should equal argv[0] in synthesized procargs");
-
- if (exec_path_out) {
- strlcpy(exec_path_out, exec_name, MAXPATHLEN);
- }
-}
-
-static void
-verify_visible_procargs(pid_t child_pid)
-{
- char buf[1024];
- size_t out_size;
- int ret = read_procargs(child_pid, buf, sizeof(buf), &out_size);
- T_ASSERT_POSIX_SUCCESS(ret, "read_procargs()");
-
- T_ASSERT_GT_ULONG(out_size, sizeof(int) + 1, "read_procargs should return enough data");
-
- int child_argc;
- memcpy(&child_argc, buf, sizeof(int));
-
- /* With real args, argc should be > 1 */
- T_ASSERT_GT(child_argc, 1, "argc should be > 1 (real args visible)");
-}
-
-static pid_t
-spawn_helper(const char *helper_name)
-{
- char path[PATH_MAX];
- uint32_t path_size = sizeof(path);
- T_QUIET;
- T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath");
-
- char *args[] = { path, "-n", (char *)helper_name, NULL };
- pid_t pid;
- int ret = posix_spawn(&pid, path, NULL, NULL, args, NULL);
- T_ASSERT_POSIX_ZERO(ret, "posix_spawn %s", helper_name);
- return pid;
-}
-
-
-/*
- * Make sure that we handle strange buffer sizes the same way
- * as the unentitled logic, for compatibility purposes.
- */
-static void
-assert_procargs_buf_sizes(pid_t pid, const char *label)
-{
- size_t argslen = 0;
- T_ASSERT_POSIX_SUCCESS(read_procargs(pid, NULL, 0, &argslen),
- "%s: size query succeeds", label);
- T_ASSERT_GT_ULONG(argslen, (size_t)0, "%s: argslen is non-zero", label);
-
- char *buf = malloc(argslen * 2);
- T_ASSERT_NOTNULL(buf, "malloc");
-
- size_t small = argslen / 2;
- size_t big = argslen * 2;
-
- /* buflen < argslen: should succeed and report buflen bytes written */
- size_t out_size = small;
- T_ASSERT_POSIX_SUCCESS(read_procargs(pid, buf, small, &out_size),
- "%s: small buf succeeds", label);
- T_ASSERT_EQ_ULONG(out_size, small, "%s: small buf returns buflen bytes", label);
-
- /* buflen == argslen: should succeed and report argslen bytes written */
- out_size = argslen;
- T_ASSERT_POSIX_SUCCESS(read_procargs(pid, buf, argslen, &out_size),
- "%s: exact buf succeeds", label);
- T_ASSERT_EQ_ULONG(out_size, argslen, "%s: exact buf returns argslen bytes", label);
-
- /* buflen > argslen: should succeed and report argslen bytes written */
- out_size = big;
- T_ASSERT_POSIX_SUCCESS(read_procargs(pid, buf, argslen * 2, &out_size),
- "%s: big buf succeeds", label);
- T_ASSERT_EQ_ULONG(out_size, argslen, "%s: big buf returns argslen bytes", label);
-
- free(buf);
-}
-
-T_DECL(procargs_no_read_spawn, "Spawning binary entitled with no-read-procargs hides the procargs")
-{
- pid_t child_pid = spawn_helper("sleeper");
-
- char exec_path[MAXPATHLEN];
- verify_hidden_procargs(child_pid, exec_path);
-
- /* Make sure the new and old logic agree on the edge cases */
- assert_procargs_buf_sizes(child_pid, "child (synthetic path)");
- assert_procargs_buf_sizes(getpid(), "ourselves (data from stack)");
-
- /* Check KERN_PROCARGS (argc_yes=0) also succeeds and starts with the exec path */
-#if TARGET_OS_OSX
- char buf[sizeof(int) + MAXPATHLEN + 1 + MAXPATHLEN + 1];
- size_t out_size;
- T_ASSERT_POSIX_SUCCESS(read_procargs1(child_pid, buf, sizeof(buf), &out_size), "KERN_PROCARGS succeeds");
- T_ASSERT_EQ_STR(buf, exec_path, "KERN_PROCARGS starts with exec path");
-#endif
-
- kill(child_pid, SIGKILL);
-}
-
-T_DECL(procargs_no_read_fork, "Forking from binary entitled with no-read-procargs hides the procargs")
-{
- pid_t child_pid = fork();
- if (child_pid == 0) {
- raise(SIGSTOP);
- exit(0);
- } else {
- T_ASSERT_POSIX_SUCCESS(child_pid, "fork");
- verify_hidden_procargs(child_pid, NULL);
- kill(child_pid, SIGKILL);
- }
-}
-
-T_DECL(procargs_no_read_spawn_unentitled, "Spawning from entitled to unentitled binary shows the procargs")
-{
- char *args[] = {"/bin/sleep", "1000", NULL};
- pid_t child_pid;
- int ret = posix_spawn(&child_pid, "/bin/sleep", NULL, NULL, args, NULL);
- T_ASSERT_POSIX_ZERO(ret, "posix_spawn /bin/sleep");
- verify_visible_procargs(child_pid);
- kill(child_pid, SIGKILL);
-}
-
-T_DECL(procargs_no_read_exec_unentitled, "Execing from entitled to unentitled binary shows the procargs")
-{
- pid_t child_pid = spawn_helper("execer");
-
- char buf[1024];
- while (1) {
- usleep(10000);
- if (read_procargs(child_pid, buf, sizeof(buf), NULL) != 0) {
- break;
- }
- char *exec_name = buf + sizeof(int);
- if (strcmp(exec_name, "/bin/sleep") == 0) {
- break;
- }
- }
-
- verify_visible_procargs(child_pid);
- kill(child_pid, SIGKILL);
-}