1 #include <darwintest.h>
2 #include <servers/bootstrap.h>
4 #include <mach/message.h>
6 #include <sys/sysctl.h>
8 #include <darwintest_multiprocess.h>
11 #include <spawn_private.h>
12 #include <libproc_internal.h>
15 #include <IOKit/IOKitLib.h>
17 #define TASK_EXC_GUARD_MP_DELIVER 0x10
20 extern char **environ
;
23 catch_mach_exception_raise_state(mach_port_t exception_port
,
24 exception_type_t exception
,
25 const mach_exception_data_t code
,
26 mach_msg_type_number_t code_count
,
28 const thread_state_t old_state
,
29 mach_msg_type_number_t old_state_count
,
30 thread_state_t new_state
,
31 mach_msg_type_number_t
* new_state_count
)
33 #pragma unused(exception_port, exception, code, code_count, flavor, old_state, old_state_count, new_state, new_state_count)
34 T_FAIL("Unsupported catch_mach_exception_raise_state");
35 return KERN_NOT_SUPPORTED
;
39 catch_mach_exception_raise_state_identity(mach_port_t exception_port
,
42 exception_type_t exception
,
43 mach_exception_data_t code
,
44 mach_msg_type_number_t code_count
,
46 thread_state_t old_state
,
47 mach_msg_type_number_t old_state_count
,
48 thread_state_t new_state
,
49 mach_msg_type_number_t
* new_state_count
)
51 #pragma unused(exception_port, thread, task, exception, code, code_count, flavor, old_state, old_state_count, new_state, new_state_count)
52 T_FAIL("Unsupported catch_mach_exception_raise_state_identity");
53 return KERN_NOT_SUPPORTED
;
57 catch_mach_exception_raise(mach_port_t exception_port
,
60 exception_type_t exception
,
61 mach_exception_data_t code
,
62 mach_msg_type_number_t code_count
)
64 #pragma unused(exception_port, task, thread, code_count)
65 T_ASSERT_EQ(exception
, EXC_GUARD
, "exception type");
66 T_LOG("Exception raised with exception code : %llx\n", *code
);
72 mach_msg_header_t header
;
74 mach_msg_port_descriptor_t port_descriptor
;
75 mach_msg_trailer_t trailer
; // subtract this when sending
76 } ipc_complex_message
;
79 char *server_port_name
;
80 mach_port_t server_port
;
83 void parse_args(struct args
*args
);
84 void server_setup(struct args
* args
);
85 void* exception_server_thread(void *arg
);
86 mach_port_t
create_exception_port(void);
88 #define TEST_TIMEOUT 10
91 parse_args(struct args
*args
)
93 args
->server_port_name
= "TEST_IMMOVABLE_SEND";
94 args
->server_port
= MACH_PORT_NULL
;
97 /* Create a mach IPC listener which will respond to the client's message */
99 server_setup(struct args
*args
)
104 ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
,
106 T_ASSERT_MACH_SUCCESS(ret
, "server: mach_port_allocate()");
108 ret
= mach_port_insert_right(mach_task_self(), args
->server_port
, args
->server_port
,
109 MACH_MSG_TYPE_MAKE_SEND
);
110 T_ASSERT_MACH_SUCCESS(ret
, "server: mach_port_insert_right()");
112 ret
= task_get_bootstrap_port(mach_task_self(), &bsport
);
113 T_ASSERT_MACH_SUCCESS(ret
, "server: task_get_bootstrap_port()");
115 ret
= bootstrap_register(bsport
, args
->server_port_name
, args
->server_port
);
116 T_ASSERT_MACH_SUCCESS(ret
, "server: bootstrap_register()");
118 T_LOG("server: waiting for IPC messages from client on port '%s'.\n",
119 args
->server_port_name
);
123 create_exception_port()
126 mach_port_t exc_port
= MACH_PORT_NULL
;
127 mach_port_t task
= mach_task_self();
129 kret
= mach_port_allocate(task
, MACH_PORT_RIGHT_RECEIVE
, &exc_port
);
130 T_EXPECT_MACH_SUCCESS(kret
, "mach_port_allocate exc_port");
132 kret
= mach_port_insert_right(task
, exc_port
, exc_port
, MACH_MSG_TYPE_MAKE_SEND
);
133 T_EXPECT_MACH_SUCCESS(kret
, "mach_port_insert_right exc_port");
139 exception_server_thread(void *arg
)
142 mach_port_t exc_port
= *(mach_port_t
*)arg
;
143 T_EXPECT_NE(exc_port
, MACH_PORT_NULL
, "exception port is not null");
145 /* Handle exceptions on exc_port */
146 kr
= mach_msg_server(mach_exc_server
, 4096, exc_port
, 0);
147 T_EXPECT_MACH_SUCCESS(kr
, "mach_msg_server");
152 T_DECL(catch_exception
, "Send guard port descriptor to another process", T_META_IGNORECRASHES(".*immovable_send_client.*"))
154 uint32_t task_exc_guard
= 0;
155 size_t te_size
= sizeof(&task_exc_guard
);
157 mach_msg_type_number_t maskCount
= 1;
158 exception_mask_t mask
;
159 exception_handler_t handler
;
160 exception_behavior_t behavior
;
161 thread_state_flavor_t flavor
;
162 mach_port_t task
= mach_task_self();
163 struct args
* server_args
= (struct args
*)malloc(sizeof(struct args
));
164 posix_spawnattr_t attrs
;
165 char *test_prog_name
= "./immovable_send_client";
166 char *child_args
[MAX_ARGV
];
168 T_LOG("Check if task_exc_guard exception has been enabled\n");
169 sysctlbyname("kern.task_exc_guard_default", &task_exc_guard
, &te_size
, NULL
, 0);
170 //TODO: check if sysctlbyname is successful
172 /* Create the bootstrap port */
173 parse_args(server_args
);
174 server_setup(server_args
);
176 /* Create the exception port for the server */
177 mach_port_t exc_port
= create_exception_port();
178 T_EXPECT_NOTNULL(exc_port
, "Create a new exception port");
180 pthread_t s_exc_thread
;
182 /* Create exception serving thread */
183 int ret
= pthread_create(&s_exc_thread
, NULL
, exception_server_thread
, &exc_port
);
184 T_EXPECT_POSIX_SUCCESS(ret
, "pthread_create exception_server_thread");
186 /* Get current exception ports */
187 kr
= task_get_exception_ports(task
, EXC_MASK_GUARD
, &mask
,
188 &maskCount
, &handler
, &behavior
, &flavor
);
189 T_EXPECT_MACH_SUCCESS(kr
, "task_get_exception_ports");
191 /* Initialize posix_spawn attributes */
192 posix_spawnattr_init(&attrs
);
194 int err
= posix_spawnattr_setexceptionports_np(&attrs
, EXC_MASK_GUARD
, exc_port
,
195 (exception_behavior_t
) (EXCEPTION_DEFAULT
| MACH_EXCEPTION_CODES
), 0);
196 T_EXPECT_POSIX_SUCCESS(err
, "posix_spawnattr_setflags");
198 child_args
[0] = test_prog_name
;
199 child_args
[1] = NULL
;
201 err
= posix_spawn(NULL
, child_args
[0], NULL
, &attrs
, &child_args
[0], environ
);
202 T_EXPECT_POSIX_SUCCESS(err
, "posix_spawn immovable_send_client");
205 /* Wait for child and check for exception */
206 if (-1 == wait4(-1, &child_status
, 0, NULL
)) {
207 T_FAIL("wait4: child mia");
210 if (WIFEXITED(child_status
) && WEXITSTATUS(child_status
)) {
211 T_LOG("Child exited with status = %x", child_status
);