10 #include <sys/ptrace.h>
23 int check_tainted(void)
29 buffer
[10] = 0; //make sure that we can fit the whole int.
31 fd
= open("/proc/sys/kernel/tainted", O_RDONLY
);
34 ret
= read(fd
, buffer
, 10);
40 /* We should never fail, but if we do, assume untainted. */
47 static void oom_score_adj(int adj
)
51 fp
= fopen("/proc/self/oom_score_adj", "w");
55 fprintf(fp
, "%d", adj
);
59 static void fork_children(void)
62 static char childname
[17];
64 /* Generate children*/
66 while (shm
->running_childs
< shm
->max_children
) {
70 if (shm
->spawn_no_more
== TRUE
)
73 /* a new child means a new seed, or the new child
74 * will do the same syscalls as the one in the pidslot it's replacing.
75 * (special case startup, or we reseed unnecessarily)
77 if (shm
->ready
== TRUE
)
80 /* Find a space for it in the pid map */
81 pidslot
= find_pid_slot(EMPTY_PIDSLOT
);
82 if (pidslot
== PIDSLOT_NOT_FOUND
) {
83 outputerr("## Pid map was full!\n");
88 if (logging
== TRUE
) {
89 fd
= fileno(shm
->logfiles
[pidslot
]);
90 if (ftruncate(fd
, 0) == 0)
91 lseek(fd
, 0, SEEK_SET
);
98 shm
->pids
[pidslot
] = pid
;
103 mask_signals_child();
105 memset(childname
, 0, sizeof(childname
));
106 sprintf(childname
, "trinity-child%d", pidslot
);
107 prctl(PR_SET_NAME
, (unsigned long) &childname
);
111 /* Wait for parent to set our pidslot */
112 while (shm
->pids
[pidslot
] != getpid()) {
113 /* Make sure parent is actually alive to wait for us. */
114 ret
= pid_alive(shm
->mainpid
);
116 shm
->exit_reason
= EXIT_SHM_CORRUPTION
;
117 outputerr(BUGTXT
"parent (%d) went away!\n", shm
->mainpid
);
122 /* Wait for all the children to start up. */
123 while (shm
->ready
== FALSE
)
128 ret
= child_process(pidslot
);
130 output(1, "child exiting.\n");
134 shm
->running_childs
++;
135 debugf("Created child %d in pidslot %d [total:%d/%d]\n",
136 shm
->pids
[pidslot
], pidslot
,
137 shm
->running_childs
, shm
->max_children
);
139 if (shm
->exit_reason
!= STILL_RUNNING
)
145 debugf("created enough children\n");
148 void reap_child(pid_t childpid
)
152 while (shm
->reaper_lock
== LOCKED
);
154 shm
->reaper_lock
= LOCKED
;
156 if (childpid
== shm
->last_reaped
) {
157 debugf("already reaped %d!\n", childpid
);
161 i
= find_pid_slot(childpid
);
162 if (i
== PIDSLOT_NOT_FOUND
)
165 debugf("Removing pid %d from pidmap.\n", childpid
);
166 shm
->pids
[i
] = EMPTY_PIDSLOT
;
167 shm
->running_childs
--;
168 shm
->tv
[i
].tv_sec
= 0;
169 shm
->last_reaped
= childpid
;
172 shm
->reaper_lock
= UNLOCKED
;
175 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
) {
190 debugf("All children exited!\n");
191 for_each_pidslot(i
) {
192 if (shm
->pids
[i
] != EMPTY_PIDSLOT
) {
193 if (pid_alive(shm
->pids
[i
]) == -1) {
194 debugf("Removing %d from pidmap\n", shm
->pids
[i
]);
195 shm
->pids
[i
] = EMPTY_PIDSLOT
;
196 shm
->running_childs
--;
198 debugf("%d looks still alive! ignoring.\n", shm
->pids
[i
]);
204 output(0, "error! (%s)\n", strerror(errno
));
208 debugf("Something happened to pid %d\n", childpid
);
210 if (WIFEXITED(childstatus
)) {
212 slot
= find_pid_slot(childpid
);
213 if (slot
== PIDSLOT_NOT_FOUND
) {
214 /* If we reaped it, it wouldn't show up, so check that. */
215 if (shm
->last_reaped
!= childpid
) {
216 outputerr("## Couldn't find pid slot for %d\n", childpid
);
217 shm
->exit_reason
= EXIT_LOST_PID_SLOT
;
221 debugf("Child %d exited after %ld syscalls.\n", childpid
, shm
->child_syscall_count
[slot
]);
222 reap_child(childpid
);
226 } else if (WIFSIGNALED(childstatus
)) {
228 switch (WTERMSIG(childstatus
)) {
230 debugf("got a alarm signal from pid %d\n", childpid
);
237 debugf("got a signal from pid %d (%s)\n", childpid
, strsignal(WTERMSIG(childstatus
)));
238 reap_child(childpid
);
241 debugf("** Child got an unhandled signal (%d)\n", WTERMSIG(childstatus
));
246 } else if (WIFSTOPPED(childstatus
)) {
248 switch (WSTOPSIG(childstatus
)) {
250 debugf("got an alarm signal from pid %d\n", childpid
);
253 debugf("Sending PTRACE_DETACH (and then KILL)\n");
254 ptrace(PTRACE_DETACH
, childpid
, NULL
, NULL
);
255 kill(childpid
, SIGKILL
);
256 reap_child(childpid
);
263 debugf("Child %d was stopped by %s\n", childpid
, strsignal(WTERMSIG(childstatus
)));
264 reap_child(childpid
);
267 debugf("Child %d was stopped by unhandled signal (%s).\n", childpid
, strsignal(WSTOPSIG(childstatus
)));
272 } else if (WIFCONTINUED(childstatus
)) {
275 output(0, "erk, wtf\n");
280 static void handle_children(void)
286 if (shm
->running_childs
== 0)
289 /* First, we wait for *any* child to wake us up. */
290 pid
= waitpid(-1, &childstatus
, WUNTRACED
| WCONTINUED
);
292 /* We were awoken, handle it. */
293 handle_child(pid
, childstatus
);
295 /* While we're awake, let's see if the other children need attention.
296 * We do this instead of just waitpid(-1) again so that there's no way
297 * for any one child to starve the others of attention.
299 for_each_pidslot(i
) {
303 if (pid
== EMPTY_PIDSLOT
)
306 if (pid_is_valid(pid
) == FALSE
)
309 pid
= waitpid(pid
, &childstatus
, WUNTRACED
| WCONTINUED
| WNOHANG
);
311 handle_child(pid
, childstatus
);
315 static const char *reasons
[] = {
317 "No more syscalls enabled.",
318 "Reached maximum syscall count.",
319 "No file descriptors open.",
320 "Lost track of a pid slot.",
321 "shm corruption - Found a pid out of range.",
323 "kernel became tainted.",
324 "SHM was corrupted!",
325 "Child reparenting problem",
326 "No files in file list.",
327 "Main process disappeared.",
331 static const char * decode_exit(unsigned int reason
)
333 return reasons
[reason
];
336 static void main_loop(void)
338 while (shm
->exit_reason
== STILL_RUNNING
) {
340 if (shm
->spawn_no_more
== FALSE
) {
341 if (shm
->running_childs
< shm
->max_children
)
344 /* Periodic regenation of fd's etc. */
345 if (shm
->regenerate
>= REGENERATION_POINT
)
348 if (shm
->need_reseed
== TRUE
)
357 void do_main_loop(void)
359 const char taskname
[13]="trinity-main";
363 /* do an extra fork so that the watchdog and the children don't share a common parent */
367 setup_main_signals();
369 shm
->mainpid
= getpid();
370 output(0, "Main thread is alive.\n");
371 prctl(PR_SET_NAME
, (unsigned long) &taskname
);
375 if (no_files
== FALSE
) {
376 if (files_in_index
== 0) {
377 shm
->exit_reason
= EXIT_NO_FILES
;
384 /* Wait until all children have exited. */
385 while (pidmap_empty() == FALSE
)
388 outputerr("Bailing main loop. Exit reason: %s\n", decode_exit(shm
->exit_reason
));
392 /* wait for main loop process to exit. */
393 pid
= waitpid(pid
, &childstatus
, 0);