1// Copyright 2017 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 <stdio.h> 7#include <threads.h> 8 9#include <lib/zx/channel.h> 10#include <lib/zx/event.h> 11#include <lib/zx/handle.h> 12#include <lib/zx/job.h> 13#include <lib/zx/port.h> 14#include <lib/zx/process.h> 15#include <lib/zx/thread.h> 16#include <lib/zx/vmar.h> 17 18#include <fbl/algorithm.h> 19#include <fbl/type_support.h> 20 21#include <zircon/process.h> 22#include <zircon/syscalls/debug.h> 23#include <zircon/syscalls/exception.h> 24#include <zircon/syscalls/policy.h> 25#include <zircon/syscalls/port.h> 26 27#include <mini-process/mini-process.h> 28 29#include <unistd.h> 30#include <unittest/unittest.h> 31 32static const unsigned kExceptionPortKey = 42u; 33 34// Basic job operation is tested by core-tests. 35static zx::job make_job() { 36 zx::job job; 37 if (zx::job::create(*zx::job::default_job(), 0u, &job) != ZX_OK) 38 return zx::job(); 39 return job; 40} 41 42static zx::process make_test_process(const zx::job& job, zx::thread* out_thread, 43 zx_handle_t* ctrl) { 44 zx::vmar vmar; 45 zx::process proc; 46 zx_status_t status = zx::process::create(job, "poltst", 6u, 0u, &proc, &vmar); 47 if (status != ZX_OK) 48 return zx::process(); 49 50 zx::thread thread; 51 status = zx::thread::create(proc, "poltst", 6u, 0, &thread); 52 if (status != ZX_OK) 53 return zx::process(); 54 if (out_thread) { 55 status = thread.duplicate(ZX_RIGHT_SAME_RIGHTS, out_thread); 56 if (status != ZX_OK) 57 return zx::process(); 58 } 59 60 zx::event event; 61 status = zx::event::create(0u, &event); 62 if (status != ZX_OK) 63 return zx::process(); 64 65 auto thr = thread.release(); 66 status = start_mini_process_etc(proc.get(), thr, vmar.get(), event.release(), ctrl); 67 if (status != ZX_OK) 68 return zx::process(); 69 70 return proc; 71} 72 73static bool abs_then_rel() { 74 BEGIN_TEST; 75 76 zx_policy_basic_t policy[] = { 77 { ZX_POL_BAD_HANDLE, ZX_POL_ACTION_KILL } }; 78 79 auto job = make_job(); 80 EXPECT_EQ(job.set_policy( 81 ZX_JOB_POL_ABSOLUTE, ZX_JOB_POL_BASIC, policy, static_cast<uint32_t>(fbl::count_of(policy))), ZX_OK); 82 83 // A contradictory policy should fail. 84 policy[0].policy = ZX_POL_ACTION_EXCEPTION | ZX_POL_ACTION_DENY; 85 EXPECT_EQ(job.set_policy( 86 ZX_JOB_POL_ABSOLUTE, ZX_JOB_POL_BASIC, policy, static_cast<uint32_t>(fbl::count_of(policy))), ZX_ERR_ALREADY_EXISTS); 87 88 // The same again will succeed. 89 policy[0].policy = ZX_POL_ACTION_KILL; 90 EXPECT_EQ(job.set_policy( 91 ZX_JOB_POL_ABSOLUTE, ZX_JOB_POL_BASIC, policy, static_cast<uint32_t>(fbl::count_of(policy))), ZX_OK); 92 93 // A contradictory relative policy will succeed, but is a no-op 94 policy[0].policy = ZX_POL_ACTION_ALLOW; 95 EXPECT_EQ(job.set_policy( 96 ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, policy, static_cast<uint32_t>(fbl::count_of(policy))), ZX_OK); 97 98 zx_policy_basic_t more[] = { 99 { ZX_POL_NEW_CHANNEL, ZX_POL_ACTION_ALLOW | ZX_POL_ACTION_EXCEPTION }, 100 { ZX_POL_NEW_FIFO, ZX_POL_ACTION_DENY } }; 101 102 // An additional absolute policy that doesn't contradict existing 103 // policy can be added. 104 EXPECT_EQ(job.set_policy( 105 ZX_JOB_POL_ABSOLUTE, ZX_JOB_POL_BASIC, more, static_cast<uint32_t>(fbl::count_of(more))), ZX_OK); 106 107 END_TEST; 108} 109 110static bool invalid_calls(uint32_t options) { 111 auto job = make_job(); 112 113 EXPECT_EQ(job.set_policy(options, ZX_JOB_POL_BASIC, nullptr, 0u), ZX_ERR_INVALID_ARGS); 114 115 EXPECT_EQ(job.set_policy(options, ZX_JOB_POL_BASIC, nullptr, 5u), ZX_ERR_INVALID_ARGS); 116 117 zx_policy_basic_t policy1[] = { 118 { ZX_POL_BAD_HANDLE, ZX_POL_ACTION_KILL }, 119 }; 120 121 EXPECT_EQ(job.set_policy(options, ZX_JOB_POL_BASIC, policy1, 0u), ZX_ERR_INVALID_ARGS); 122 123 zx_policy_basic_t policy2[] = { 124 { 100001u, ZX_POL_ACTION_KILL }, 125 }; 126 127 EXPECT_EQ(job.set_policy( 128 options, ZX_JOB_POL_BASIC, policy2, static_cast<uint32_t>(fbl::count_of(policy2))), ZX_ERR_INVALID_ARGS); 129 130 zx_policy_basic_t policy3[] = { 131 { ZX_POL_BAD_HANDLE, 100001u }, 132 }; 133 134 EXPECT_EQ(job.set_policy( 135 options, ZX_JOB_POL_BASIC, policy3, static_cast<uint32_t>(fbl::count_of(policy2))), ZX_ERR_NOT_SUPPORTED); 136 137 // The job will still accept a valid combination: 138 zx_policy_basic_t policy4[] = { 139 { ZX_POL_BAD_HANDLE, ZX_POL_ACTION_KILL } }; 140 141 EXPECT_EQ(job.set_policy( 142 options, ZX_JOB_POL_BASIC, policy4, static_cast<uint32_t>(fbl::count_of(policy4))), ZX_OK); 143 144 return true; 145} 146 147static bool invalid_calls_abs() { 148 BEGIN_TEST; 149 150 invalid_calls(ZX_JOB_POL_ABSOLUTE); 151 152 END_TEST; 153} 154 155static bool invalid_calls_rel() { 156 BEGIN_TEST; 157 158 invalid_calls(ZX_JOB_POL_RELATIVE); 159 160 END_TEST; 161} 162 163// Test that executing the given mini-process.h command (|minip_cmd|) 164// produces the given result (|expect|) when the given policy is in force. 165static bool test_invoking_policy( 166 zx_policy_basic_t* pol, uint32_t pol_count, uint32_t minip_cmd, zx_status_t expect) { 167 auto job = make_job(); 168 ASSERT_EQ(job.set_policy(ZX_JOB_POL_ABSOLUTE, ZX_JOB_POL_BASIC, pol, pol_count), ZX_OK); 169 170 zx_handle_t ctrl; 171 auto proc = make_test_process(job, nullptr, &ctrl); 172 ASSERT_TRUE(proc.is_valid()); 173 ASSERT_NE(ctrl, ZX_HANDLE_INVALID); 174 175 zx_handle_t obj; 176 EXPECT_EQ(mini_process_cmd(ctrl, minip_cmd, &obj), expect); 177 EXPECT_EQ(mini_process_cmd(ctrl, MINIP_CMD_EXIT_NORMAL, nullptr), ZX_ERR_PEER_CLOSED); 178 179 zx_handle_close(ctrl); 180 return true; 181} 182 183static bool enforce_deny_event() { 184 BEGIN_TEST; 185 186 zx_policy_basic_t policy[] = { { ZX_POL_NEW_EVENT, ZX_POL_ACTION_DENY } }; 187 test_invoking_policy(policy, static_cast<uint32_t>(fbl::count_of(policy)), MINIP_CMD_CREATE_EVENT, 188 ZX_ERR_ACCESS_DENIED); 189 190 END_TEST; 191} 192 193static bool enforce_deny_channel() { 194 BEGIN_TEST; 195 196 zx_policy_basic_t policy[] = { { ZX_POL_NEW_CHANNEL, ZX_POL_ACTION_DENY } }; 197 test_invoking_policy(policy, static_cast<uint32_t>(fbl::count_of(policy)), MINIP_CMD_CREATE_CHANNEL, 198 ZX_ERR_ACCESS_DENIED); 199 200 END_TEST; 201} 202 203static bool enforce_deny_any() { 204 BEGIN_TEST; 205 206 zx_policy_basic_t policy[] = { { ZX_POL_NEW_ANY, ZX_POL_ACTION_DENY } }; 207 test_invoking_policy(policy, static_cast<uint32_t>(fbl::count_of(policy)), MINIP_CMD_CREATE_EVENT, 208 ZX_ERR_ACCESS_DENIED); 209 210 END_TEST; 211} 212 213static bool enforce_allow_any() { 214 BEGIN_TEST; 215 216 zx_policy_basic_t policy[] = { { ZX_POL_NEW_ANY, ZX_POL_ACTION_ALLOW } }; 217 test_invoking_policy(policy, static_cast<uint32_t>(fbl::count_of(policy)), MINIP_CMD_CREATE_EVENT, 218 ZX_OK); 219 220 END_TEST; 221} 222 223static bool enforce_deny_but_event() { 224 BEGIN_TEST; 225 226 zx_policy_basic_t policy[] = { 227 { ZX_POL_NEW_ANY, ZX_POL_ACTION_DENY }, 228 { ZX_POL_NEW_EVENT, ZX_POL_ACTION_ALLOW } 229 }; 230 test_invoking_policy(policy, static_cast<uint32_t>(fbl::count_of(policy)), MINIP_CMD_CREATE_EVENT, 231 ZX_OK); 232 test_invoking_policy(policy, static_cast<uint32_t>(fbl::count_of(policy)), MINIP_CMD_CREATE_CHANNEL, 233 ZX_ERR_ACCESS_DENIED); 234 235 END_TEST; 236} 237 238static bool get_koid(zx_handle_t handle, zx_koid_t* koid) { 239 zx_info_handle_basic_t info; 240 ASSERT_EQ(zx_object_get_info( 241 handle, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), 242 nullptr, nullptr), ZX_OK); 243 *koid = info.koid; 244 return true; 245} 246 247#if defined(__x86_64__) 248 249static uint64_t get_syscall_result(zx_thread_state_general_regs_t* regs) { 250 return regs->rax; 251} 252 253#elif defined(__aarch64__) 254 255static uint64_t get_syscall_result(zx_thread_state_general_regs_t* regs) { 256 return regs->r[0]; 257} 258 259#else 260# error Unsupported architecture 261#endif 262 263// Like test_invoking_policy(), this tests that executing the given 264// mini-process.h command produces the given result when the given policy 265// is in force. In addition, it tests that a debug port exception gets 266// generated. 267static bool test_invoking_policy_with_exception( 268 zx_policy_basic_t* policy, uint32_t policy_count, uint32_t minip_cmd, 269 zx_status_t expected_syscall_result) { 270 auto job = make_job(); 271 ASSERT_EQ(job.set_policy(ZX_JOB_POL_ABSOLUTE, ZX_JOB_POL_BASIC, policy, 272 policy_count), ZX_OK); 273 274 zx_handle_t ctrl; 275 zx::thread thread; 276 auto proc = make_test_process(job, &thread, &ctrl); 277 ASSERT_TRUE(proc.is_valid()); 278 ASSERT_NE(ctrl, ZX_HANDLE_INVALID); 279 280 zx_handle_t exc_port; 281 ASSERT_EQ(zx_port_create(0, &exc_port), ZX_OK); 282 ASSERT_EQ(zx_task_bind_exception_port( 283 proc.get(), exc_port, kExceptionPortKey, 284 ZX_EXCEPTION_PORT_DEBUGGER), 285 ZX_OK); 286 287 EXPECT_EQ(mini_process_cmd_send(ctrl, minip_cmd), ZX_OK); 288 289 // Check that the subprocess did not return a reply yet (indicating 290 // that it was suspended). 291 EXPECT_EQ(zx_object_wait_one(ctrl, ZX_CHANNEL_READABLE, 292 zx_deadline_after(ZX_MSEC(1)), nullptr), 293 ZX_ERR_TIMED_OUT); 294 295 // Check that we receive an exception message. 296 zx_port_packet_t packet; 297 ASSERT_EQ(zx_port_wait(exc_port, ZX_TIME_INFINITE, &packet), ZX_OK); 298 299 // Check the exception message contents. 300 ASSERT_EQ(packet.key, kExceptionPortKey); 301 ASSERT_EQ(packet.type, (uint32_t)ZX_EXCP_POLICY_ERROR); 302 303 zx_koid_t pid; 304 zx_koid_t tid; 305 ASSERT_TRUE(get_koid(proc.get(), &pid)); 306 ASSERT_TRUE(get_koid(thread.get(), &tid)); 307 ASSERT_EQ(packet.exception.pid, pid); 308 ASSERT_EQ(packet.exception.tid, tid); 309 310 // Check that we can read the thread's register state. 311 zx_thread_state_general_regs_t regs; 312 ASSERT_EQ(zx_thread_read_state(thread.get(), ZX_THREAD_STATE_GENERAL_REGS, ®s, sizeof(regs)), 313 ZX_OK); 314 ASSERT_EQ(get_syscall_result(®s), (uint64_t)expected_syscall_result); 315 // TODO(mseaborn): Check the values of other registers. We could check 316 // that rip/pc is within the VDSO, which will require figuring out 317 // where the VDSO is mapped. We could check that unwinding the stack 318 // using crashlogger gives a correct backtrace. 319 320 // Resume the thread. 321 ASSERT_EQ(zx_task_resume(thread.get(), ZX_RESUME_EXCEPTION), ZX_OK); 322 // Check that the read-ready state of the channel changed compared with 323 // the earlier check. 324 EXPECT_EQ(zx_object_wait_one(ctrl, ZX_CHANNEL_READABLE, ZX_TIME_INFINITE, 325 nullptr), 326 ZX_OK); 327 328 // Check that we receive a reply message from the resumed thread. 329 zx_handle_t obj; 330 EXPECT_EQ(mini_process_cmd_read_reply(ctrl, &obj), 331 expected_syscall_result); 332 if (expected_syscall_result == ZX_OK) 333 EXPECT_EQ(zx_handle_close(obj), ZX_OK); 334 335 // Clean up: Tell the subprocess to exit. 336 EXPECT_EQ(mini_process_cmd(ctrl, MINIP_CMD_EXIT_NORMAL, nullptr), 337 ZX_ERR_PEER_CLOSED); 338 339 zx_handle_close(ctrl); 340 341 return true; 342} 343 344static bool test_exception_on_new_event_and_deny() { 345 BEGIN_TEST; 346 347 zx_policy_basic_t policy[] = { 348 { ZX_POL_NEW_EVENT, ZX_POL_ACTION_DENY | ZX_POL_ACTION_EXCEPTION }, 349 }; 350 test_invoking_policy_with_exception( 351 policy, static_cast<uint32_t>(fbl::count_of(policy)), MINIP_CMD_CREATE_EVENT, ZX_ERR_ACCESS_DENIED); 352 353 END_TEST; 354} 355 356static bool test_exception_on_new_event_but_allow() { 357 BEGIN_TEST; 358 359 zx_policy_basic_t policy[] = { 360 { ZX_POL_NEW_EVENT, ZX_POL_ACTION_ALLOW | ZX_POL_ACTION_EXCEPTION }, 361 }; 362 test_invoking_policy_with_exception( 363 policy, static_cast<uint32_t>(fbl::count_of(policy)), MINIP_CMD_CREATE_EVENT, ZX_OK); 364 365 END_TEST; 366} 367 368// Test ZX_POL_BAD_HANDLE when syscalls are allowed to continue. 369static bool test_error_on_bad_handle() { 370 BEGIN_TEST; 371 372 // The ALLOW and DENY actions should be equivalent for ZX_POL_BAD_HANDLE. 373 uint32_t actions[] = { ZX_POL_ACTION_ALLOW, ZX_POL_ACTION_DENY }; 374 for (uint32_t action : actions) { 375 unittest_printf_critical("Testing action=%d\n", action); 376 zx_policy_basic_t policy[] = { 377 { ZX_POL_BAD_HANDLE, action }, 378 }; 379 test_invoking_policy( 380 policy, static_cast<uint32_t>(fbl::count_of(policy)), MINIP_CMD_USE_BAD_HANDLE_CLOSED, 381 ZX_ERR_BAD_HANDLE); 382 test_invoking_policy( 383 policy, static_cast<uint32_t>(fbl::count_of(policy)), MINIP_CMD_USE_BAD_HANDLE_TRANSFERRED, 384 ZX_ERR_BAD_HANDLE); 385 } 386 387 END_TEST; 388} 389 390// Test ZX_POL_BAD_HANDLE with ZX_POL_ACTION_EXCEPTION. 391static bool test_exception_on_bad_handle() { 392 BEGIN_TEST; 393 394 // The ALLOW and DENY actions should be equivalent for ZX_POL_BAD_HANDLE. 395 uint32_t actions[] = { ZX_POL_ACTION_ALLOW, ZX_POL_ACTION_DENY }; 396 for (uint32_t action : actions) { 397 unittest_printf_critical("Testing action=%d\n", action); 398 zx_policy_basic_t policy[] = { 399 { ZX_POL_BAD_HANDLE, action | ZX_POL_ACTION_EXCEPTION }, 400 }; 401 test_invoking_policy_with_exception( 402 policy, static_cast<uint32_t>(fbl::count_of(policy)), MINIP_CMD_USE_BAD_HANDLE_CLOSED, 403 ZX_ERR_BAD_HANDLE); 404 test_invoking_policy_with_exception( 405 policy, static_cast<uint32_t>(fbl::count_of(policy)), MINIP_CMD_USE_BAD_HANDLE_TRANSFERRED, 406 ZX_ERR_BAD_HANDLE); 407 } 408 409 END_TEST; 410} 411 412// The one exception for ZX_POL_BAD_HANDLE is zx_object_info( ZX_INFO_HANDLE_VALID). 413static bool test_get_info_on_bad_handle() { 414 BEGIN_TEST; 415 416 zx_policy_basic_t policy[] = {{ 417 ZX_POL_BAD_HANDLE, ZX_POL_ACTION_DENY | ZX_POL_ACTION_EXCEPTION }}; 418 test_invoking_policy( 419 policy, static_cast<uint32_t>(fbl::count_of(policy)), MINIP_CMD_VALIDATE_CLOSED_HANDLE, 420 ZX_ERR_BAD_HANDLE); 421 422 END_TEST; 423} 424 425BEGIN_TEST_CASE(job_policy) 426RUN_TEST(invalid_calls_abs) 427RUN_TEST(invalid_calls_rel) 428RUN_TEST(abs_then_rel) 429RUN_TEST(enforce_deny_event) 430RUN_TEST(enforce_deny_channel) 431RUN_TEST(enforce_deny_any) 432RUN_TEST(enforce_allow_any) 433RUN_TEST(enforce_deny_but_event) 434RUN_TEST(test_exception_on_new_event_and_deny) 435RUN_TEST(test_exception_on_new_event_but_allow) 436RUN_TEST(test_error_on_bad_handle) 437RUN_TEST(test_exception_on_bad_handle) 438RUN_TEST(test_get_info_on_bad_handle) 439END_TEST_CASE(job_policy) 440 441int main(int argc, char** argv) { 442 bool success = unittest_run_all_tests(argc, argv); 443 return success ? 0 : -1; 444} 445