1 #include <darwintest.h>
2 #include <servers/bootstrap.h>
4 #include <mach/message.h>
6 #include <sys/sysctl.h>
9 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
12 mach_msg_header_t header
;
14 mach_msg_guarded_port_descriptor_t guarded_port_descriptor1
;
15 mach_msg_guarded_port_descriptor_t guarded_port_descriptor2
;
16 mach_msg_trailer_t trailer
; // subtract this when sending
17 } ipc_complex_message
;
19 static ipc_complex_message icm_request
= {};
26 const char *server_port_name
;
27 mach_port_t server_port
;
28 mach_port_t reply_port
;
29 mach_port_t voucher_port
;
34 mach_port_t sp_voucher_port
;
39 void parse_args(struct args
*args
);
40 void* create_buffer(int *buffer_size
);
41 void client(struct args
*args
);
42 void server_setup(struct args
* args
);
43 void server(struct args
*args
);
46 parse_args(struct args
*args
)
50 args
->server_port_name
= "TEST";
51 args
->server_port
= MACH_PORT_NULL
;
52 args
->reply_port
= MACH_PORT_NULL
;
53 args
->voucher_port
= MACH_PORT_NULL
;
55 args
->request_msg_size
= sizeof(ipc_complex_message
);
56 args
->request_msg
= &icm_request
;
57 args
->client_pid
= getpid();
60 /* Create a mach IPC listener which will respond to the client's message */
62 server_setup(struct args
* args
)
67 ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
,
69 T_ASSERT_MACH_SUCCESS(ret
, "server: mach_port_allocate()");
71 ret
= mach_port_insert_right(mach_task_self(), args
->server_port
, args
->server_port
,
72 MACH_MSG_TYPE_MAKE_SEND
);
73 T_ASSERT_MACH_SUCCESS(ret
, "server: mach_port_insert_right()");
75 ret
= task_get_bootstrap_port(mach_task_self(), &bsport
);
76 T_ASSERT_MACH_SUCCESS(ret
, "server: task_get_bootstrap_port()");
78 ret
= bootstrap_register(bsport
, args
->server_port_name
, args
->server_port
);
79 T_ASSERT_MACH_SUCCESS(ret
, "server: bootstrap_register()");
81 T_LOG("server: waiting for IPC messages from client on port '%s'.\n",
82 args
->server_port_name
);
85 /* Server process loop
87 * Listens for message.
91 server(struct args
*args
)
93 mach_msg_header_t
*request
;
94 mach_msg_option_t rcvoption
;
97 request
= (mach_msg_header_t
*)args
->request_msg
;
99 rcvoption
= MACH_RCV_MSG
| MACH_RCV_INTERRUPT
| MACH_RCV_GUARDED_DESC
;
101 T_LOG("server: Awaiting message\n");
102 ret
= mach_msg(request
,
105 sizeof(ipc_complex_message
),
107 MACH_MSG_TIMEOUT_NONE
,
110 T_ASSERT_MACH_SUCCESS(ret
, "server: mach_msg receive");
112 ipc_complex_message
*request_complexmsg
= (ipc_complex_message
*)request
;
113 T_ASSERT_NE(request_complexmsg
->guarded_port_descriptor1
.name
, 0, "server: Should not receive mach_port_null; name = %x", request_complexmsg
->guarded_port_descriptor1
.name
);
114 T_ASSERT_EQ(request_complexmsg
->guarded_port_descriptor1
.type
, MACH_MSG_GUARDED_PORT_DESCRIPTOR
, "server: Received a guarded port descriptor");
115 T_ASSERT_EQ(request_complexmsg
->guarded_port_descriptor1
.disposition
, MACH_MSG_TYPE_PORT_RECEIVE
, "server: Received a receive right");
116 T_ASSERT_EQ(request_complexmsg
->guarded_port_descriptor1
.context
, (unsigned long)request
, "server: Received a port with correct context = %p", request
);
117 T_LOG("Guard flags = %d", request_complexmsg
->guarded_port_descriptor1
.flags
);
119 T_ASSERT_NE(request_complexmsg
->guarded_port_descriptor2
.name
, 0, "server: Should not receive mach_port_null; name = %x", request_complexmsg
->guarded_port_descriptor2
.name
);
120 T_ASSERT_EQ(request_complexmsg
->guarded_port_descriptor2
.type
, MACH_MSG_GUARDED_PORT_DESCRIPTOR
, "server: Received a guarded port descriptor");
121 T_ASSERT_EQ(request_complexmsg
->guarded_port_descriptor2
.disposition
, MACH_MSG_TYPE_PORT_RECEIVE
, "server: Received a receive right");
122 T_ASSERT_EQ(request_complexmsg
->guarded_port_descriptor2
.context
, (unsigned long)request
, "server: Received a port with correct context = %p", request
);
124 mach_port_status_t status
;
125 mach_msg_type_number_t status_size
= MACH_PORT_RECEIVE_STATUS_COUNT
;
127 kern_return_t kr
= mach_port_get_attributes(mach_task_self(), request_complexmsg
->guarded_port_descriptor1
.name
,
128 MACH_PORT_RECEIVE_STATUS
, (mach_port_info_t
)&status
, &status_size
);
129 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "mach_port_get_attributes for descriptor 1");
130 T_LOG("Status flags %d", status
.mps_flags
);
131 T_ASSERT_NE(0, (status
.mps_flags
& MACH_PORT_STATUS_FLAG_GUARD_IMMOVABLE_RECEIVE
), "Imm rcv bit is set for descriptor1");
133 kr
= mach_port_get_attributes(mach_task_self(), request_complexmsg
->guarded_port_descriptor2
.name
,
134 MACH_PORT_RECEIVE_STATUS
, (mach_port_info_t
)&status
, &status_size
);
135 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "mach_port_get_attributes for descriptor 2");
136 T_LOG("Status flags %d", status
.mps_flags
);
137 T_ASSERT_NE(0, (status
.mps_flags
& MACH_PORT_STATUS_FLAG_GUARD_IMMOVABLE_RECEIVE
), "Imm rcv bit is set for descriptor2");
139 mach_msg_destroy(request
);
143 client(struct args
*args
)
145 //Find the bootstrap port
147 mach_port_t guarded_port
;
148 mach_port_t unguarded_port
;
150 kern_return_t ret
= task_get_bootstrap_port(mach_task_self(), &bsport
);
151 T_ASSERT_MACH_SUCCESS(ret
, "client: task_get_bootstrap_port()");
153 //Look up the service port
154 ret
= bootstrap_look_up(bsport
, (char *)args
->server_port_name
,
156 T_ASSERT_MACH_SUCCESS(ret
, "client: bootstrap_look_up()");
158 //Create the unguarded port
159 ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
,
161 T_ASSERT_MACH_SUCCESS(ret
, "client: mach_port_allocate() reply port");
163 mach_port_options_t opts
= {
164 .flags
= MPO_CONTEXT_AS_GUARD
167 ret
= mach_port_construct(mach_task_self(), &opts
, 0x10, &guarded_port
);
168 T_QUIET
; T_ASSERT_MACH_SUCCESS(ret
, "mach_port_construct");
170 //Construct the message
171 mach_msg_header_t
*request
= (mach_msg_header_t
*)args
->request_msg
;
172 request
->msgh_bits
= MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND
, MACH_MSG_TYPE_MAKE_SEND_ONCE
,
173 0, 0) | MACH_MSGH_BITS_COMPLEX
;
174 request
->msgh_size
= (mach_msg_size_t
)args
->request_msg_size
;
175 request
->msgh_remote_port
= args
->server_port
;
176 request
->msgh_local_port
= args
->reply_port
;
177 request
->msgh_id
= 1;
179 ipc_complex_message
*complexmsg
= (ipc_complex_message
*)request
;
180 complexmsg
->body
.msgh_descriptor_count
= 2;
181 complexmsg
->guarded_port_descriptor1
.name
= guarded_port
;
182 complexmsg
->guarded_port_descriptor1
.disposition
= MACH_MSG_TYPE_MOVE_RECEIVE
;
183 complexmsg
->guarded_port_descriptor1
.flags
= MACH_MSG_GUARD_FLAGS_IMMOVABLE_RECEIVE
;
184 complexmsg
->guarded_port_descriptor1
.context
= 0x10;
185 complexmsg
->guarded_port_descriptor1
.type
= MACH_MSG_GUARDED_PORT_DESCRIPTOR
;
187 complexmsg
->guarded_port_descriptor2
.name
= unguarded_port
;
188 complexmsg
->guarded_port_descriptor2
.disposition
= MACH_MSG_TYPE_MOVE_RECEIVE
;
189 complexmsg
->guarded_port_descriptor2
.flags
= MACH_MSG_GUARD_FLAGS_IMMOVABLE_RECEIVE
| MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND
;
190 complexmsg
->guarded_port_descriptor2
.context
= 0;
191 complexmsg
->guarded_port_descriptor2
.type
= MACH_MSG_GUARDED_PORT_DESCRIPTOR
;
193 mach_msg_option_t option
= MACH_SEND_MSG
;
195 //Listen for the reply on the reply port
196 T_LOG("client: Sending request\n");
197 ret
= mach_msg(request
,
199 (mach_msg_size_t
)args
->request_msg_size
,
202 MACH_MSG_TIMEOUT_NONE
,
204 T_ASSERT_MACH_SUCCESS(ret
, "client: mach_msg_overwrite()");
207 T_DECL(mo_immovable_receive
, "Send a message containing a guard port descriptor for an immovable receive right")
209 struct args args
= {};
211 args
.request_msg_size
-= sizeof(mach_msg_trailer_t
);
212 args
.reply_msg_size
-= sizeof(mach_msg_trailer_t
);
217 T_LOG("Server is up");
224 T_LOG("Preparing client to send a request");
226 T_ASSERT_POSIX_SUCCESS(waitpid(pid
, NULL
, 0), "waitpid()");