7 #include <sys/ptrace.h>
24 int check_tainted(void)
30 buffer
[10] = 0; //make sure that we can fit the whole int.
32 fd
= open("/proc/sys/kernel/tainted", O_RDONLY
);
35 ret
= read(fd
, buffer
, 10);
41 /* We should never fail, but if we do, assume untainted. */
48 static void oom_score_adj(int adj
)
52 fp
= fopen("/proc/self/oom_score_adj", "w");
56 fprintf(fp
, "%d", adj
);
60 /* Generate children*/
61 static void fork_children(void)
63 while (shm
->running_childs
< max_children
) {
67 if (shm
->spawn_no_more
== TRUE
)
70 /* a new child means a new seed, or the new child
71 * will do the same syscalls as the one in the pidslot it's replacing.
72 * (special case startup, or we reseed unnecessarily)
74 if (shm
->ready
== TRUE
)
77 /* Find a space for it in the pid map */
78 pidslot
= find_pid_slot(EMPTY_PIDSLOT
);
79 if (pidslot
== PIDSLOT_NOT_FOUND
) {
80 outputerr("## Pid map was full!\n");
85 if (logging
== TRUE
) {
88 fd
= fileno(shm
->logfiles
[pidslot
]);
89 if (ftruncate(fd
, 0) == 0)
90 lseek(fd
, 0, SEEK_SET
);
98 output(0, "couldn't create child! (%s)\n", strerror(errno
));
99 shm
->exit_reason
= EXIT_FORK_FAILURE
;
102 shm
->pids
[pidslot
] = pid
;
108 mask_signals_child();
110 memset(childname
, 0, sizeof(childname
));
111 sprintf(childname
, "trinity-c%d", pidslot
);
112 prctl(PR_SET_NAME
, (unsigned long) &childname
);
116 /* Wait for parent to set our pidslot */
117 while (shm
->pids
[pidslot
] != getpid()) {
118 /* Make sure parent is actually alive to wait for us. */
119 ret
= pid_alive(shm
->mainpid
);
121 shm
->exit_reason
= EXIT_SHM_CORRUPTION
;
122 outputerr(BUGTXT
"parent (%d) went away!\n", shm
->mainpid
);
127 /* Wait for all the children to start up. */
128 while (shm
->ready
== FALSE
)
133 ret
= child_process(pidslot
);
135 output(1, "child exiting.\n");
139 shm
->running_childs
++;
140 debugf("Created child %d in pidslot %d [total:%d/%d]\n",
141 shm
->pids
[pidslot
], pidslot
,
142 shm
->running_childs
, max_children
);
144 if (shm
->exit_reason
!= STILL_RUNNING
)
150 debugf("created enough children\n");
153 void reap_child(pid_t childpid
)
157 acquire(&shm
->reaper_lock
);
159 if (childpid
== shm
->last_reaped
) {
160 debugf("already reaped %d!\n", childpid
);
164 i
= find_pid_slot(childpid
);
165 if (i
== PIDSLOT_NOT_FOUND
)
168 debugf("Removing pid %d from pidmap.\n", childpid
);
169 shm
->pids
[i
] = EMPTY_PIDSLOT
;
170 shm
->running_childs
--;
171 shm
->tv
[i
].tv_sec
= 0;
172 shm
->last_reaped
= childpid
;
175 release(&shm
->reaper_lock
);
178 static void handle_child(pid_t childpid
, int childstatus
)
182 //debugf("Nothing changed. children:%d\n", shm->running_childs);
186 if (shm
->exit_reason
!= STILL_RUNNING
)
189 if (errno
== ECHILD
) {
193 debugf("All children exited!\n");
195 for_each_pidslot(i
) {
196 if (shm
->pids
[i
] != EMPTY_PIDSLOT
) {
197 if (pid_alive(shm
->pids
[i
]) == -1) {
198 debugf("Removing %d from pidmap\n", shm
->pids
[i
]);
199 shm
->pids
[i
] = EMPTY_PIDSLOT
;
200 shm
->running_childs
--;
202 debugf("%d looks still alive! ignoring.\n", shm
->pids
[i
]);
208 shm
->running_childs
= 0;
211 output(0, "error! (%s)\n", strerror(errno
));
215 debugf("Something happened to pid %d\n", childpid
);
217 if (WIFEXITED(childstatus
)) {
221 slot
= find_pid_slot(childpid
);
222 if (slot
== PIDSLOT_NOT_FOUND
) {
223 /* If we reaped it, it wouldn't show up, so check that. */
224 if (shm
->last_reaped
!= childpid
) {
225 outputerr("## Couldn't find pid slot for %d\n", childpid
);
226 shm
->exit_reason
= EXIT_LOST_PID_SLOT
;
230 debugf("Child %d exited after %ld syscalls.\n", childpid
, shm
->child_syscall_count
[slot
]);
231 reap_child(childpid
);
235 } else if (WIFSIGNALED(childstatus
)) {
237 switch (WTERMSIG(childstatus
)) {
239 debugf("got a alarm signal from pid %d\n", childpid
);
246 debugf("got a signal from pid %d (%s)\n", childpid
, strsignal(WTERMSIG(childstatus
)));
247 reap_child(childpid
);
250 debugf("** Child got an unhandled signal (%d)\n", WTERMSIG(childstatus
));
255 } else if (WIFSTOPPED(childstatus
)) {
257 switch (WSTOPSIG(childstatus
)) {
259 debugf("got an alarm signal from pid %d\n", childpid
);
262 debugf("Sending PTRACE_DETACH (and then KILL)\n");
263 ptrace(PTRACE_DETACH
, childpid
, NULL
, NULL
);
264 kill(childpid
, SIGKILL
);
265 reap_child(childpid
);
272 debugf("Child %d was stopped by %s\n", childpid
, strsignal(WTERMSIG(childstatus
)));
273 reap_child(childpid
);
276 debugf("Child %d was stopped by unhandled signal (%s).\n", childpid
, strsignal(WSTOPSIG(childstatus
)));
281 } else if (WIFCONTINUED(childstatus
)) {
284 output(0, "erk, wtf\n");
289 static void handle_children(void)
295 if (shm
->running_childs
== 0)
298 /* First, we wait for *any* child to wake us up. */
299 pid
= waitpid(-1, &childstatus
, WUNTRACED
| WCONTINUED
);
301 /* We were awoken, handle it. */
302 handle_child(pid
, childstatus
);
304 /* While we're awake, let's see if the other children need attention.
305 * We do this instead of just waitpid(-1) again so that there's no way
306 * for any one child to starve the others of attention.
308 for_each_pidslot(i
) {
312 if (pid
== EMPTY_PIDSLOT
)
315 if (pid_is_valid(pid
) == FALSE
)
318 pid
= waitpid(pid
, &childstatus
, WUNTRACED
| WCONTINUED
| WNOHANG
);
320 handle_child(pid
, childstatus
);
324 static const char *reasons
[NUM_EXIT_REASONS
] = {
326 "No more syscalls enabled.",
327 "Reached maximum syscall count.",
328 "No file descriptors open.",
329 "Lost track of a pid slot.",
330 "shm corruption - Found a pid out of range.",
332 "kernel became tainted.",
333 "SHM was corrupted!",
334 "Child reparenting problem",
335 "No files in file list.",
336 "Main process disappeared.",
338 "Something happened during fd init.",
342 static const char * decode_exit(unsigned int reason
)
344 return reasons
[reason
];
349 while (shm
->exit_reason
== STILL_RUNNING
) {
351 if (shm
->spawn_no_more
== FALSE
) {
352 if (shm
->running_childs
< max_children
)
355 /* Periodic regenation of fd's etc. */
356 if (shm
->regenerate
>= REGENERATION_POINT
)
359 if (shm
->need_reseed
== TRUE
)
366 /* Wait until all children have exited. */
367 while (pidmap_empty() == FALSE
)
370 outputerr("Bailing main loop. Exit reason: %s\n", decode_exit(shm
->exit_reason
));