1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <assert.h> 6#include <stdbool.h> 7#include <stdio.h> 8#include <stdlib.h> 9 10#include <zircon/process.h> 11#include <zircon/rights.h> 12#include <zircon/syscalls.h> 13#include <zircon/syscalls/policy.h> 14 15#include <mini-process/mini-process.h> 16#include <unittest/unittest.h> 17 18static const char process_name[] = "job-test-p"; 19 20extern zx_handle_t root_job; 21 22static bool basic_test(void) { 23 BEGIN_TEST; 24 25 // Never close the launchpad job. 26 zx_handle_t job_parent = zx_job_default(); 27 ASSERT_NE(job_parent, ZX_HANDLE_INVALID, ""); 28 29 // If the parent job is valid, one should be able to create a child job 30 // and a child job of the child job. 31 zx_handle_t job_child, job_grandchild; 32 ASSERT_EQ(zx_job_create(job_parent, 0u, &job_child), ZX_OK, ""); 33 ASSERT_EQ(zx_job_create(job_child, 0u, &job_grandchild), ZX_OK, ""); 34 35 ASSERT_EQ(zx_handle_close(job_child), ZX_OK, ""); 36 ASSERT_EQ(zx_handle_close(job_grandchild), ZX_OK, ""); 37 38 // If the parent job is not valid it should fail. 39 zx_handle_t job_fail; 40 ASSERT_EQ(zx_job_create(ZX_HANDLE_INVALID, 0u, &job_fail), ZX_ERR_BAD_HANDLE, ""); 41 42 END_TEST; 43} 44 45static bool create_test(void) { 46 BEGIN_TEST; 47 48 zx_handle_t job_parent = zx_job_default(); 49 ASSERT_NE(job_parent, ZX_HANDLE_INVALID, ""); 50 51 zx_handle_t job_child; 52 ASSERT_EQ(zx_job_create(job_parent, 0u, &job_child), ZX_OK, ""); 53 54 // Make sure we can create process object with both the parent job and a child job. 55 zx_handle_t process1, vmar1; 56 ASSERT_EQ(zx_process_create( 57 job_parent, process_name, sizeof(process_name), 0u, &process1, &vmar1), ZX_OK, ""); 58 59 zx_handle_t process2, vmar2; 60 ASSERT_EQ(zx_process_create( 61 job_child, process_name, sizeof(process_name), 0u, &process2, &vmar2), ZX_OK, ""); 62 63 ASSERT_EQ(zx_handle_close(job_child), ZX_OK, ""); 64 ASSERT_EQ(zx_handle_close(process1), ZX_OK, ""); 65 ASSERT_EQ(zx_handle_close(process2), ZX_OK, ""); 66 ASSERT_EQ(zx_handle_close(vmar1), ZX_OK, ""); 67 ASSERT_EQ(zx_handle_close(vmar2), ZX_OK, ""); 68 69 END_TEST; 70} 71 72static bool create_missing_rights_test(void) { 73 BEGIN_TEST; 74 75 zx_rights_t rights = ZX_DEFAULT_JOB_RIGHTS & ~ZX_RIGHT_WRITE & ~ZX_RIGHT_MANAGE_JOB; 76 zx_handle_t job_parent; 77 zx_status_t status = zx_handle_duplicate(zx_job_default(), rights, &job_parent); 78 ASSERT_EQ(status, ZX_OK, ""); 79 80 zx_handle_t job_child; 81 ASSERT_EQ(zx_job_create(job_parent, 0u, &job_child), ZX_ERR_ACCESS_DENIED, ""); 82 83 zx_handle_close(job_parent); 84 85 END_TEST; 86} 87 88static bool policy_basic_test(void) { 89 BEGIN_TEST; 90 91 zx_handle_t job_parent = zx_job_default(); 92 ASSERT_NE(job_parent, ZX_HANDLE_INVALID, ""); 93 94 zx_handle_t job_child; 95 ASSERT_EQ(zx_job_create(job_parent, 0u, &job_child), ZX_OK, ""); 96 97 zx_policy_basic_t policy[] = { 98 { ZX_POL_BAD_HANDLE, ZX_POL_ACTION_KILL }, 99 { ZX_POL_NEW_CHANNEL, ZX_POL_ACTION_ALLOW | ZX_POL_ACTION_EXCEPTION }, 100 { ZX_POL_NEW_FIFO, ZX_POL_ACTION_DENY }, 101 }; 102 103 ASSERT_EQ(zx_job_set_policy(job_child, ZX_JOB_POL_RELATIVE, 104 ZX_JOB_POL_BASIC, policy, countof(policy)), ZX_OK, ""); 105 106 ASSERT_EQ(zx_handle_close(job_child), ZX_OK, ""); 107 END_TEST; 108} 109 110static bool kill_test(void) { 111 BEGIN_TEST; 112 113 zx_handle_t job_parent = zx_job_default(); 114 ASSERT_NE(job_parent, ZX_HANDLE_INVALID, ""); 115 116 zx_handle_t job_child; 117 ASSERT_EQ(zx_job_create(job_parent, 0u, &job_child), ZX_OK, ""); 118 119 zx_handle_t event; 120 ASSERT_EQ(zx_event_create(0u, &event), ZX_OK, ""); 121 122 zx_handle_t process, thread; 123 ASSERT_EQ(start_mini_process(job_child, event, &process, &thread), ZX_OK, ""); 124 125 ASSERT_EQ(zx_task_kill(job_child), ZX_OK, ""); 126 127 zx_signals_t signals; 128 ASSERT_EQ(zx_object_wait_one( 129 process, ZX_TASK_TERMINATED, ZX_TIME_INFINITE, &signals), ZX_OK, ""); 130 ASSERT_EQ(signals, ZX_TASK_TERMINATED, ""); 131 132 ASSERT_EQ(zx_object_wait_one( 133 job_child, ZX_JOB_NO_PROCESSES, ZX_TIME_INFINITE, &signals), ZX_OK, ""); 134 ASSERT_EQ(signals, ZX_JOB_NO_PROCESSES | ZX_JOB_NO_JOBS, ""); 135 136 // Process should be in the dead state here. 137 138 zx_handle_t job_grandchild; 139 ASSERT_EQ(zx_job_create(job_child, 0u, &job_grandchild), ZX_ERR_BAD_STATE, ""); 140 141 ASSERT_EQ(zx_handle_close(thread), ZX_OK, ""); 142 ASSERT_EQ(zx_handle_close(process), ZX_OK, ""); 143 ASSERT_EQ(start_mini_process(job_child, event, &process, &thread), ZX_ERR_BAD_STATE, ""); 144 145 END_TEST; 146} 147 148static bool wait_test(void) { 149 BEGIN_TEST; 150 151 zx_handle_t job_parent = zx_job_default(); 152 ASSERT_NE(job_parent, ZX_HANDLE_INVALID, ""); 153 154 zx_handle_t job_child; 155 ASSERT_EQ(zx_job_create(job_parent, 0u, &job_child), ZX_OK, ""); 156 157 zx_handle_t event; 158 ASSERT_EQ(zx_event_create(0u, &event), ZX_OK, ""); 159 160 zx_handle_t process, thread; 161 ASSERT_EQ(start_mini_process(job_child, event, &process, &thread), ZX_OK, ""); 162 163 zx_signals_t signals; 164 ASSERT_EQ(zx_object_wait_one( 165 job_child, ZX_JOB_NO_JOBS, ZX_TIME_INFINITE, &signals), ZX_OK, ""); 166 ASSERT_EQ(signals, ZX_JOB_NO_JOBS, ""); 167 168 zx_nanosleep(zx_deadline_after(ZX_MSEC(5))); 169 ASSERT_EQ(zx_task_kill(process), ZX_OK, ""); 170 171 ASSERT_EQ(zx_object_wait_one( 172 job_child, ZX_JOB_NO_PROCESSES, ZX_TIME_INFINITE, &signals), ZX_OK, ""); 173 ASSERT_EQ(signals, ZX_JOB_NO_PROCESSES | ZX_JOB_NO_JOBS, ""); 174 175 ASSERT_EQ(zx_handle_close(thread), ZX_OK, ""); 176 ASSERT_EQ(zx_handle_close(process), ZX_OK, ""); 177 ASSERT_EQ(zx_handle_close(job_child), ZX_OK, ""); 178 179 END_TEST; 180} 181 182static bool info_task_stats_fails(void) { 183 BEGIN_TEST; 184 zx_info_task_stats_t info; 185 ASSERT_NE(zx_object_get_info(zx_job_default(), ZX_INFO_TASK_STATS, 186 &info, sizeof(info), NULL, NULL), 187 ZX_OK, 188 "Just added job support to info_task_status?"); 189 // If so, replace this with a real test; see example in process.cpp. 190 END_TEST; 191} 192 193// Show that there is a max job height. 194static bool max_height_smoke(void) { 195 BEGIN_TEST; 196 197 // Get our parent job. 198 zx_handle_t parent_job = zx_job_default(); 199 200 // Stack of handles that we need to close. 201 static const int kNumJobs = 128; 202 zx_handle_t *handles = calloc(kNumJobs, sizeof(*handles)); 203 ASSERT_NONNULL(handles, ""); 204 zx_handle_t *htop = handles; 205 206 // Eat up our max height. 207 while (true) { 208 zx_handle_t child_job; 209 zx_status_t s = zx_job_create(parent_job, 0u, &child_job); 210 if (s != ZX_OK) { 211 break; 212 } 213 // We should hit the max before running out of entries; 214 // this is the core check of this test. 215 ASSERT_LT(htop - handles, kNumJobs, 216 "Should have seen the max job height"); 217 *htop++ = child_job; 218 parent_job = child_job; 219 } 220 221 // We've hit the bottom. Creating a child under this job should fail. 222 zx_handle_t child_job; 223 EXPECT_EQ(zx_job_create(parent_job, 0u, &child_job), ZX_ERR_OUT_OF_RANGE, ""); 224 225 // Creating a process should succeed, though. 226 zx_handle_t child_proc; 227 zx_handle_t vmar; 228 ASSERT_EQ(zx_process_create( 229 parent_job, "test", sizeof("test"), 0u, &child_proc, &vmar), 230 ZX_OK, ""); 231 zx_handle_close(vmar); 232 zx_handle_close(child_proc); 233 234 // Clean up. 235 while (htop > handles) { 236 EXPECT_EQ(zx_handle_close(*--htop), ZX_OK, ""); 237 } 238 free(handles); 239 240 END_TEST; 241} 242 243BEGIN_TEST_CASE(job_tests) 244RUN_TEST(basic_test) 245RUN_TEST(create_missing_rights_test) 246RUN_TEST(policy_basic_test) 247RUN_TEST(create_test) 248RUN_TEST(kill_test) 249RUN_TEST(wait_test) 250RUN_TEST(info_task_stats_fails) 251RUN_TEST(max_height_smoke) 252END_TEST_CASE(job_tests) 253