]> git.saurik.com Git - apple/launchd.git/blob - launchd/testing/missed-fds.c
launchd-258.25.tar.gz
[apple/launchd.git] / launchd / testing / missed-fds.c
1 /*
2 * <rdar://problem/4389914> 8G1153: Cannot SSH into machine despite Remote Login being checked
3 */
4
5 #include <sys/types.h>
6 #include <sys/time.h>
7 #include <sys/event.h>
8 #include <sys/socket.h>
9 #include <netinet/in.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <stdbool.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <assert.h>
18
19 static void do_parent(int thefd);
20 static void do_child(int thefd);
21
22 int main(void)
23 {
24 int sp[2];
25 pid_t p;
26
27 assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) != -1);
28
29 assert((p = fork()) != -1);
30
31 if (p == 0) {
32 assert(close(sp[0]) != -1);
33 do_child(sp[1]);
34 } else {
35 assert(close(sp[1]) != -1);
36 do_parent(sp[0]);
37 }
38
39 exit(EXIT_SUCCESS);
40 }
41
42 static int
43 alloc_random_fd(void)
44 {
45 struct sockaddr_in ina;
46 int fd;
47
48 memset(&ina, 0, sizeof(ina));
49 ina.sin_family = AF_INET;
50 assert((fd = socket(PF_INET, SOCK_STREAM, 0)) != -1);
51 assert(bind(fd, (struct sockaddr *)&ina, sizeof(ina)) != -1);
52 assert(listen(fd, SOMAXCONN) != -1);
53
54 return fd;
55 }
56
57 static int total_fds_sent = 0;
58
59 void
60 send_fds(int thefd)
61 {
62 struct cmsghdr *cm = NULL;
63 struct msghdr mh;
64 struct iovec iov;
65 size_t sentctrllen = 0;
66 int fdcnt = (rand() % 223) + 1; /* 223 is prime */
67 int r, i, fds[fdcnt];
68
69 memset(&mh, 0, sizeof(mh));
70
71 iov.iov_base = &fdcnt;
72 iov.iov_len = sizeof(fdcnt);
73 mh.msg_iov = &iov;
74 mh.msg_iovlen = 1;
75
76 for (i = 0; i < fdcnt; i++) {
77 fds[i] = alloc_random_fd();
78 }
79
80 sentctrllen = mh.msg_controllen = CMSG_SPACE(fdcnt * sizeof(int));
81
82 mh.msg_control = cm = alloca(mh.msg_controllen);
83
84 memset(cm, 0, mh.msg_controllen);
85
86 cm->cmsg_len = CMSG_LEN(fdcnt * sizeof(int));
87 cm->cmsg_level = SOL_SOCKET;
88 cm->cmsg_type = SCM_RIGHTS;
89
90 memcpy(CMSG_DATA(cm), fds, fdcnt * sizeof(int));
91
92 if (sendmsg(thefd, &mh, 0) == -1) {
93 fprintf(stderr, "Child: sendmsg(): %s\n", strerror(errno));
94 fprintf(stderr, "Child: Tried to send %d fds\n", fdcnt);
95 fprintf(stderr, "Child: Total FDs sent: %d\n", total_fds_sent);
96 sleep(1);
97 exit(EXIT_FAILURE);
98 }
99 total_fds_sent += fdcnt;
100
101 assert(sentctrllen == mh.msg_controllen);
102
103 r = read(thefd, &i, sizeof(i));
104 assert(r != -1);
105 assert(r != 0);
106
107 for (i = 0; i < fdcnt; i++) {
108 assert(close(fds[i]) != -1);
109 }
110 }
111
112 void
113 do_child(int thefd)
114 {
115 for (;;) {
116 send_fds(thefd);
117 }
118 }
119
120 static int total_fds_received = 0;
121
122 static bool
123 fetch_and_check_fds(int thefd)
124 {
125 struct cmsghdr *cm = alloca(4096);
126 struct msghdr mh;
127 struct iovec iov;
128 int r, i, *fds, fdcnt = 0, sentfds;
129
130 memset(&mh, 0, sizeof(mh));
131
132 iov.iov_base = &fdcnt;
133 iov.iov_len = sizeof(fdcnt);
134 mh.msg_iov = &iov;
135 mh.msg_iovlen = 1;
136 mh.msg_control = cm;
137 mh.msg_controllen = 4096;
138
139 r = recvmsg(thefd, &mh, 0);
140 assert(r != -1);
141 assert(r != 0);
142 assert(!(mh.msg_flags & MSG_CTRUNC));
143 assert(mh.msg_controllen > 0);
144
145 fds = (int *)CMSG_DATA(cm);
146 sentfds = (mh.msg_controllen - sizeof(struct cmsghdr)) / sizeof(int);
147
148 if (sentfds != fdcnt) {
149 fprintf(stderr, "%d FDs sent, %d actually received.\n", fdcnt, sentfds);
150 return false;
151 }
152
153 total_fds_received += fdcnt;
154
155 for (i = 0; i < fdcnt; i++) {
156 assert(close(fds[i]) != -1);
157 }
158
159 r = write(thefd, &fdcnt, sizeof(fdcnt));
160 assert(r != -1);
161 assert(r != 0);
162
163 return true;
164 }
165
166 void
167 do_parent(int thefd)
168 {
169 struct kevent kev;
170 int kq, iter = 0;
171
172 EV_SET(&kev, thefd, EVFILT_READ, EV_ADD, 0, 0, NULL);
173
174 assert((kq = kqueue()) != -1);
175 assert(kevent(kq, &kev, 1, NULL, 0, NULL) != -1);
176
177 for (iter = 0; ; iter++) {
178 assert(kevent(kq, NULL, 0, &kev, 1, NULL) == 1);
179 assert(kev.filter == EVFILT_READ);
180 if (!fetch_and_check_fds(thefd))
181 break;
182 }
183
184 fprintf(stderr, "After %d iterations and %d FDs received, bug 4389914 still exists!\n", iter, total_fds_received);
185 exit(EXIT_FAILURE);
186 }