7 #include <sys/guarded.h>
10 #include <sys/types.h>
11 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include "guarded_test_common.h"
16 #include <sys/syscall.h>
18 #if !defined(SYS_guarded_kqueue_np)
19 #define guarded_kqueue_np(gp, gf) syscall(443, gp, gf)
22 #if !defined(SYS_change_fdguard_np)
23 #define change_fdguard_np(fd, gp, gf, ngp, nfg, flp) \
24 syscall(444, fd, gp, gf, ngp, nfg, flp)
27 #define SERVER_NAME "/tmp/fdserver"
30 struct cmsghdrcmsghdr
;
31 u_char msg_control
[0];
32 } cmsghdr_msg_control_t
;
34 /* Test case for closing a guarded fd */
35 void close_guarded_fd(int);
36 /* Test case for duping a guarded fd */
37 void dup_guarded_fd(int);
38 /* Test case for removing flag from guarded fd */
39 void remove_flag_guarded_fd(int);
40 /* Test case for closing guarded fd with bad guard */
41 void badguard_close_guarded_fd(int, guardid_t
);
42 /* Test case for guarded closing an unguarded fd */
43 void guard_close_unguarded_fd(guardid_t
);
44 /* Test case for guarded closing a guarded fd correctly */
45 void guard_close_guarded_fd(int, guardid_t
);
46 /* Test case for creating a file port from a guarded fd */
47 void fileport_makeport_guarded_fd(int);
48 /* Test case for sending guarded fd over socket */
49 void sendmsg_guarded_fd(int);
50 /* Test case for removing the guard from a guarded fd */
51 void remove_guard(int, guardid_t
, u_int
, int);
52 /* Test case for adding a guard to a tcp socket */
53 void add_guard_to_socket(guardid_t
);
54 /* Test case for a guarded kqueue */
55 void create_and_close_guarded_kqueue(guardid_t
);
58 void *client_recv_fd(void *);
59 int receive_fd_using_sockfd(int *, int);
60 int send_fd_using_sockfd(int, int);
61 int setup_server(const char *);
63 const guardid_t guard
= 0x123456789abcdefull
;
66 static void usage(void)
68 printf("usage: %s [test number]\n", pname
);
69 printf("test 0: Test case for closing a guarded fd\n");
70 printf("test 1: Test case for duping a guarded fd\n");
71 printf("test 2: Test case for removing FD_CLOEXEC flag from a guarded fd\n");
72 printf("test 3: Test case for closing a guarded fd with a bad guard\n");
73 printf("test 4: Test case for closing an unguarded fd using a guarded close\n");
74 printf("test 5: Test case for closing a guarded fd with the correct guard\n");
75 printf("test 6: Test case for creating a file port from a guarded fd\n");
76 printf("test 7: Test case for sending a guarded fd over a socket\n");
77 printf("test 8: Test case for removing the guard from a guarded fd\n");
78 printf("test 9: Test case for adding a guard to a tcp socket\n");
79 printf("test 10: Test case for a guarded kqueue\n");
82 int main(int argc
, char *argv
[])
91 printf("Test Program invoked with option [%s]\n", argv
[1]);
92 option
= atoi(argv
[1]);
98 GUARD_CLOSE
| GUARD_DUP
| GUARD_SOCKET_IPC
| GUARD_FILEPORT
,
99 O_CREAT
| O_CLOEXEC
| O_RDWR
,
103 perror("guarded_open_np");
110 close_guarded_fd(fd
);
116 remove_flag_guarded_fd(fd
);
119 badguard_close_guarded_fd(fd
, guard
);
122 guard_close_unguarded_fd(guard
);
125 guard_close_guarded_fd(fd
, guard
);
128 fileport_makeport_guarded_fd(fd
);
131 sendmsg_guarded_fd(fd
);
134 remove_guard(fd
, guard
, GUARD_CLOSE
| GUARD_DUP
|
135 GUARD_SOCKET_IPC
| GUARD_FILEPORT
, FD_CLOEXEC
);
138 add_guard_to_socket(guard
);
141 create_and_close_guarded_kqueue(guard
);
151 void close_guarded_fd(int fd
)
154 printf("Performing close on a guarded fd...\n");
156 /* Brute force way of ensuring that the child process
157 * uses the TEST_FD which is checked by the parent
159 while(fd
!= TEST_FD
&& fd
<= TEST_FD
) {
160 fd
= guarded_open_np(
163 GUARD_CLOSE
| GUARD_DUP
| GUARD_SOCKET_IPC
| GUARD_FILEPORT
,
164 O_CREAT
| O_CLOEXEC
| O_RDWR
,
168 perror("guarded_open_np");
173 ret_val
= close(TEST_FD
);
174 fprintf(stderr
, "close() returned (%d) on a guarded fd?!\n", ret_val
);
178 void dup_guarded_fd(int fd
)
181 printf("Performing dup on a guarded fd...\n");
183 fprintf(stderr
, "dup() returned (%d) on a guarded fd?!\n", ret_val
);
187 void remove_flag_guarded_fd(int fd
)
190 printf("Removing FD_CLOEXEC from a guarded fd...\n");
191 value
= fcntl(fd
, F_GETFD
);
193 fprintf(stderr
, "fcntl:F_GETFD failed with %s!\n", strerror(errno
));
196 ret_val
= fcntl(fd
, F_SETFD
, value
& ~FD_CLOEXEC
);
197 fprintf(stderr
, "fcntl:F_SETFD returned (%d) on a guarded fd?!\n", ret_val
);
201 void badguard_close_guarded_fd(int fd
, guardid_t guard
)
204 printf("Closing guarded fd with a bad guard...\n");
205 guardid_t badguard
= guard
<< 1;
206 ret_val
= guarded_close_np(fd
, &badguard
);
211 perror("guarded_close_np");
214 perror("guarded_close_np");
219 "Close with bad guard returned (%d) on a guarded fd?!\n", ret_val
);
223 void guard_close_unguarded_fd(guardid_t guard
)
225 printf("Closing Unguarded fd with guarded_close_np...\n");
228 if ((newfd
= dup(fileno(stderr
))) == -1) {
229 fprintf(stderr
, "Failed to dup stderr!\n");
233 ret_val
= guarded_close_np(newfd
, &guard
);
236 perror("guarded_close_np");
240 fprintf(stderr
, "Closing unguarded fd with guarded_fd succeeded with return value (%d)?!\n", ret_val
);
245 void guard_close_guarded_fd(int fd
, guardid_t guard
)
247 printf("Closing a guarded fd with correct guard...\n");
248 if (-1 == guarded_close_np(fd
, &guard
)) {
249 fprintf(stderr
, "Closing guarded fd with correct guard failed?!\n");
256 void fileport_makeport_guarded_fd(int fd
)
258 mach_port_name_t fdname
= MACH_PORT_NULL
;
260 printf("Creating a file port from a guarded fd...\n");
261 ret_val
= fileport_makeport(fd
, &fdname
);
262 fprintf(stderr
, "Creating a file port from guarded fd returned (%d)?!\n", ret_val
);
266 void sendmsg_guarded_fd(int fd
)
271 struct sockaddr_un client_unix_addr
;
272 pthread_t client_thread
;
275 /* Setup fd server */
276 if ((sockfd
= setup_server(SERVER_NAME
)) < 0) {
280 if(-1 == listen(sockfd
, 5)) {
285 /* Create client thread */
286 if ((err
= pthread_create(&client_thread
, NULL
, client_recv_fd
, 0)) != 0) {
287 fprintf(stderr
, "pthread_create server_thread: %s\n", strerror(err
));
291 pthread_detach(client_thread
);
294 len
= sizeof (client_unix_addr
);
295 csockfd
= accept(sockfd
,
296 (struct sockaddr
*)&client_unix_addr
, &len
);
302 printf("Sending guarded fd on a socket...\n");
303 ret_val
= send_fd_using_sockfd(fd
, csockfd
);
306 fprintf(stderr
, "sendmsg failed with return value (%d)!\n", ret_val
);
309 fprintf(stderr
, "Sending guarded fd on socket succeeded with return value (%d)?!\n", ret_val
);
317 remove_guard(int fd
, guardid_t guard
, u_int guardflags
, int fdflags
)
319 printf("Remove the guard from a guarded fd, then dup(2) it ...\n");
321 int ret_val
= change_fdguard_np(fd
, &guard
, guardflags
, NULL
, 0, &fdflags
);
324 perror("change_fdguard_np");
328 printf("Dup-ing the unguarded fd ...\n");
331 * Now that the GUARD_DUP has been removed, we should be able
332 * to dup the descriptor with no exception generation.
344 add_guard_to_socket(guardid_t guard
)
346 printf("Add a close guard to an unguarded socket fd, then close it ...\n");
348 int s
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
355 int ret_val
= change_fdguard_np(s
, NULL
, 0, &guard
, GUARD_CLOSE
| GUARD_DUP
, NULL
);
358 perror("change_fdguard_np");
363 * Now we've added a GUARD_CLOSE successfully, let's try and do a close
368 * This is an error, because we should've received a fatal EXC_GUARD
374 create_and_close_guarded_kqueue(guardid_t guard
)
376 printf("Create a guarded kqueue, then guarded_close_np() it ...\n");
378 int kq
= guarded_kqueue_np(&guard
, GUARD_CLOSE
| GUARD_DUP
);
380 int ret_val
= guarded_close_np(kq
, &guard
);
382 perror("guarded_close_np");
386 printf("Create a guarded kqueue, then close() it ...\n");
388 kq
= guarded_kqueue_np(&guard
, GUARD_CLOSE
| GUARD_DUP
);
392 * This is always an error, because we should've received a fatal EXC_GUARD
401 int setup_server(const char *name
)
404 struct sockaddr_un server_unix_addr
;
406 if ((sockfd
= socket(AF_LOCAL
, SOCK_STREAM
, 0)) < 0) {
412 bzero(&server_unix_addr
, sizeof (server_unix_addr
));
413 server_unix_addr
.sun_family
= AF_LOCAL
;
414 (void) strcpy(server_unix_addr
.sun_path
, name
);
415 len
= strlen(name
) + 1;
416 len
+= sizeof (server_unix_addr
.sun_family
);
418 if (bind(sockfd
, (struct sockaddr
*)&server_unix_addr
, len
) < 0) {
419 (void) close(sockfd
);
425 int send_fd_using_sockfd(int fd
, int sockfd
)
428 struct iovec iovec
[1];
430 struct cmsghdr
*cmsghdrp
;
431 cmsghdr_msg_control_t
*cmsghdr_msg_control
;
433 cmsghdr_msg_control
= malloc(CMSG_SPACE(sizeof (int)));
435 iovec
[0].iov_base
= "";
436 iovec
[0].iov_len
= 1;
442 msg
.msg_control
= cmsghdr_msg_control
->msg_control
;
443 msg
.msg_controllen
= CMSG_SPACE(sizeof (int));
446 cmsghdrp
= CMSG_FIRSTHDR(&msg
);
447 cmsghdrp
->cmsg_len
= CMSG_LEN(sizeof (int));
448 cmsghdrp
->cmsg_level
= SOL_SOCKET
;
449 cmsghdrp
->cmsg_type
= SCM_RIGHTS
;
451 *((int *)CMSG_DATA(cmsghdrp
)) = fd
;
453 if ((ret
= sendmsg(sockfd
, &msg
, 0)) < 0) {
461 int receive_fd_using_sockfd(int *fd
, int sockfd
)
466 struct iovec iovec
[1];
468 struct cmsghdr
*cmsghdrp
;
469 cmsghdr_msg_control_t
*cmsghdr_msg_control
;
471 cmsghdr_msg_control
= malloc(CMSG_SPACE(sizeof (int)));
473 iovec
[0].iov_base
= &c
;
474 iovec
[0].iov_len
= 1;
480 msg
.msg_control
= cmsghdr_msg_control
->msg_control
;
481 msg
.msg_controllen
= CMSG_SPACE(sizeof (int));
484 if ((ret
= recvmsg(sockfd
, &msg
, 0)) < 0) {
489 cmsghdrp
= CMSG_FIRSTHDR(&msg
);
490 if (cmsghdrp
== NULL
) {
495 if (cmsghdrp
->cmsg_len
!= CMSG_LEN(sizeof (int)))
497 if (cmsghdrp
->cmsg_level
!= SOL_SOCKET
)
499 if (cmsghdrp
->cmsg_type
!= SCM_RIGHTS
)
504 *fd
= *((int *)CMSG_DATA(cmsghdrp
));
508 void *client_recv_fd(void *arg
)
511 int fd
= -1, sockfd
, len
, ret
;
512 struct sockaddr_un server_unix_addr
;
514 bzero(&server_unix_addr
, sizeof (server_unix_addr
));
515 strcpy(server_unix_addr
.sun_path
, SERVER_NAME
);
516 server_unix_addr
.sun_family
= AF_LOCAL
;
517 len
= strlen(SERVER_NAME
) + 1;
518 len
+= sizeof (server_unix_addr
.sun_family
);
520 if ((sockfd
= socket(AF_LOCAL
, SOCK_STREAM
, 0)) < 0) {
525 if (connect(sockfd
, (struct sockaddr
*)&server_unix_addr
, len
) < 0) {
530 ret
= receive_fd_using_sockfd(&fd
, sockfd
);