1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <mach/mach.h> 4 #include <mach/mach_port.h> 5 #include <sys/code_signing.h> 6 #include <sys/sysctl.h> 7 #include <darwintest.h> 8 9 T_GLOBAL_META( 10 T_META_NAMESPACE("xnu.ipc"), 11 T_META_RUN_CONCURRENTLY(TRUE), 12 T_META_RADAR_COMPONENT_NAME("xnu"), 13 T_META_RADAR_COMPONENT_VERSION("IPC"), 14 T_META_TAG_VM_PREFERRED); 15 16 #define countof(x) (sizeof(x) / sizeof(x[0])) 17 18 static void 19 expect_sigkill( 20 void (^fn)(void), 21 const char *description) 22 { 23 pid_t pid = fork(); 24 T_QUIET; T_ASSERT_POSIX_SUCCESS(pid, "fork"); 25 26 if (pid == 0) { 27 fn(); 28 T_ASSERT_FAIL("%s: did not receive SIGKILL", description); 29 } else { 30 int status = 0; 31 T_QUIET; T_ASSERT_POSIX_SUCCESS(waitpid(pid, &status, 0), "waitpid"); 32 T_EXPECT_EQ(WTERMSIG(status), SIGKILL, 33 "%s exited with %d, expect SIGKILL", description, WTERMSIG(status)); 34 } 35 } 36 37 T_DECL(mach_port_construct_at_most_one, 38 "mach_port_construct at most one flag policy") 39 { 40 /* verify our at most one flag rule is enforced */ 41 const uint32_t at_most_one_flags[] = { 42 MPO_REPLY_PORT, 43 MPO_CONNECTION_PORT, 44 MPO_SERVICE_PORT, 45 MPO_PROVISIONAL_REPLY_PORT, 46 MPO_EXCEPTION_PORT, 47 MPO_CONNECTION_PORT_WITH_PORT_ARRAY 48 }; 49 50 51 for (uint32_t i = 0; i < countof(at_most_one_flags) - 1; ++i) { 52 for (uint32_t j = i + 1; j < countof(at_most_one_flags); ++j) { 53 mach_port_t port; 54 55 mach_port_options_t opts = { 56 .flags = at_most_one_flags[i] | at_most_one_flags[j] 57 }; 58 59 kern_return_t kr = mach_port_construct(mach_task_self(), &opts, 0x0, &port); 60 T_ASSERT_MACH_ERROR(kr, 61 KERN_INVALID_ARGUMENT, "mach_port_construct failed for at most one flags"); 62 } 63 } 64 } 65 66 T_DECL(mach_port_construct_invalid_arguments_and_values, 67 "mach_port_construct invalid arguments and values") 68 { 69 kern_return_t kr; 70 mach_port_t port; 71 72 mach_port_options_t conn_opts = { 73 .flags = MPO_CONNECTION_PORT, 74 .service_port_name = 0x0 75 }; 76 77 kr = mach_port_construct(mach_task_self(), &conn_opts, 0x0, &port); 78 T_ASSERT_MACH_ERROR(kr, 79 KERN_INVALID_ARGUMENT, 80 "MPO_CONNECTION_PORT failed on service_port_name"); 81 82 conn_opts.service_port_name = MPO_ANONYMOUS_SERVICE; 83 84 kr = mach_port_construct(mach_task_self(), &conn_opts, 0x0, &port); 85 T_ASSERT_MACH_SUCCESS(kr, "MPO_CONNECTION_PORT succeeds with anonymous service name"); 86 kr = mach_port_destruct(mach_task_self(), port, 0, 0); 87 T_ASSERT_MACH_SUCCESS(kr, "destroy anonymous service name"); 88 89 mach_port_options_t qlimit_opts = { 90 .flags = MPO_QLIMIT, 91 .mpl.mpl_qlimit = MACH_PORT_QLIMIT_MAX + 1 92 }; 93 94 kr = mach_port_construct(mach_task_self(), &qlimit_opts, 0x0, &port); 95 T_ASSERT_MACH_ERROR(kr, 96 KERN_INVALID_VALUE, 97 "MPO_QLIMIT failed on invalid value"); 98 99 /* Enumerate on all unknown MPO flags */ 100 mach_port_options_t unknown_flags_opts; 101 for (uint32_t i = 0; i < sizeof(unknown_flags_opts.flags) * CHAR_BIT; ++i) { 102 unknown_flags_opts.flags = MPO_UNUSED_BITS & (1 << i); 103 104 if (unknown_flags_opts.flags != 0) { 105 kr = mach_port_construct(mach_task_self(), &unknown_flags_opts, 0x0, &port); 106 T_ASSERT_MACH_ERROR(kr, 107 KERN_INVALID_ARGUMENT, 108 "Unknown MPO flags 0x%x failed with KERN_INVALID_ARGUMENT", 109 unknown_flags_opts.flags); 110 } 111 } 112 } 113 114 T_DECL(mach_port_construct_fatal_failure, 115 "mach_port_construct kern defined fatal failures", 116 T_META_IGNORECRASHES(".*mach_port_construct_errors.*"), 117 T_META_ENABLED(!TARGET_OS_OSX && !TARGET_OS_BRIDGE)) 118 { 119 expect_sigkill(^{ 120 mach_port_t port; 121 mach_port_options_t opts = { 122 .flags = MPO_CONNECTION_PORT_WITH_PORT_ARRAY 123 }; 124 (void)mach_port_construct(mach_task_self(), &opts, 0x0, &port); 125 }, "passing MPO_CONNECTION_PORT_WITH_PORT_ARRAY without entitlement"); 126 } 127 128 T_DECL(mach_port_construct_kern_denied, 129 "mach_port_construct kern defined failures", 130 T_META_TAG_VM_PREFERRED, 131 T_META_ENABLED(!TARGET_OS_OSX && !TARGET_OS_BRIDGE)) 132 { 133 kern_return_t kr; 134 mach_port_t port; 135 mach_port_options_t opts; 136 137 /* 138 * should fail because only TASK_GRAPHICS_SERVER is allowed to 139 * use MPO_TG_BLOCK_TRACKING. 140 */ 141 opts.flags = MPO_TG_BLOCK_TRACKING; 142 143 kr = mach_port_construct(mach_task_self(), &opts, 0x0, &port); 144 T_ASSERT_MACH_ERROR(kr, 145 KERN_DENIED, "MPO_TG_BLOCK_TRACKING failed with KERN_DENIED"); 146 } 147