7 #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 /* Generate children*/
60 static void fork_children(void)
62 while (shm
->running_childs
< max_children
) {
66 if (shm
->spawn_no_more
== TRUE
)
69 /* a new child means a new seed, or the new child
70 * will do the same syscalls as the one in the pidslot it's replacing.
71 * (special case startup, or we reseed unnecessarily)
73 if (shm
->ready
== TRUE
)
76 /* Find a space for it in the pid map */
77 pidslot
= find_pid_slot(EMPTY_PIDSLOT
);
78 if (pidslot
== PIDSLOT_NOT_FOUND
) {
79 outputerr("## Pid map was full!\n");
84 if (logging
== TRUE
) {
87 fd
= fileno(shm
->logfiles
[pidslot
]);
88 if (ftruncate(fd
, 0) == 0)
89 lseek(fd
, 0, SEEK_SET
);
97 output(0, "couldn't create child! (%s)\n", strerror(errno
));
98 shm
->exit_reason
= EXIT_FORK_FAILURE
;
101 shm
->pids
[pidslot
] = pid
;
107 mask_signals_child();
109 memset(childname
, 0, sizeof(childname
));
110 sprintf(childname
, "trinity-c%d", pidslot
);
111 prctl(PR_SET_NAME
, (unsigned long) &childname
);
115 /* Wait for parent to set our pidslot */
116 while (shm
->pids
[pidslot
] != getpid()) {
117 /* Make sure parent is actually alive to wait for us. */
118 ret
= pid_alive(shm
->mainpid
);
120 shm
->exit_reason
= EXIT_SHM_CORRUPTION
;
121 outputerr(BUGTXT
"parent (%d) went away!\n", shm
->mainpid
);
126 /* Wait for all the children to start up. */
127 while (shm
->ready
== FALSE
)
132 ret
= child_process(pidslot
);
134 output(1, "child exiting.\n");
138 shm
->running_childs
++;
139 debugf("Created child %d in pidslot %d [total:%d/%d]\n",
140 shm
->pids
[pidslot
], pidslot
,
141 shm
->running_childs
, max_children
);
143 if (shm
->exit_reason
!= STILL_RUNNING
)
149 debugf("created enough children\n");
152 void reap_child(pid_t childpid
)
156 while (shm
->reaper_lock
== LOCKED
);
158 shm
->reaper_lock
= LOCKED
;
160 if (childpid
== shm
->last_reaped
) {
161 debugf("already reaped %d!\n", childpid
);
165 i
= find_pid_slot(childpid
);
166 if (i
== PIDSLOT_NOT_FOUND
)
169 debugf("Removing pid %d from pidmap.\n", childpid
);
170 shm
->pids
[i
] = EMPTY_PIDSLOT
;
171 shm
->running_childs
--;
172 shm
->tv
[i
].tv_sec
= 0;
173 shm
->last_reaped
= childpid
;
176 shm
->reaper_lock
= UNLOCKED
;
179 static void handle_child(pid_t childpid
, int childstatus
)
183 //debugf("Nothing changed. children:%d\n", shm->running_childs);
187 if (shm
->exit_reason
!= STILL_RUNNING
)
190 if (errno
== ECHILD
) {
194 debugf("All children exited!\n");
196 for_each_pidslot(i
) {
197 if (shm
->pids
[i
] != EMPTY_PIDSLOT
) {
198 if (pid_alive(shm
->pids
[i
]) == -1) {
199 debugf("Removing %d from pidmap\n", shm
->pids
[i
]);
200 shm
->pids
[i
] = EMPTY_PIDSLOT
;
201 shm
->running_childs
--;
203 debugf("%d looks still alive! ignoring.\n", shm
->pids
[i
]);
209 shm
->running_childs
= 0;
212 output(0, "error! (%s)\n", strerror(errno
));
216 debugf("Something happened to pid %d\n", childpid
);
218 if (WIFEXITED(childstatus
)) {
222 slot
= find_pid_slot(childpid
);
223 if (slot
== PIDSLOT_NOT_FOUND
) {
224 /* If we reaped it, it wouldn't show up, so check that. */
225 if (shm
->last_reaped
!= childpid
) {
226 outputerr("## Couldn't find pid slot for %d\n", childpid
);
227 shm
->exit_reason
= EXIT_LOST_PID_SLOT
;
231 debugf("Child %d exited after %ld syscalls.\n", childpid
, shm
->child_syscall_count
[slot
]);
232 reap_child(childpid
);
236 } else if (WIFSIGNALED(childstatus
)) {
238 switch (WTERMSIG(childstatus
)) {
240 debugf("got a alarm signal from pid %d\n", childpid
);
247 debugf("got a signal from pid %d (%s)\n", childpid
, strsignal(WTERMSIG(childstatus
)));
248 reap_child(childpid
);
251 debugf("** Child got an unhandled signal (%d)\n", WTERMSIG(childstatus
));
256 } else if (WIFSTOPPED(childstatus
)) {
258 switch (WSTOPSIG(childstatus
)) {
260 debugf("got an alarm signal from pid %d\n", childpid
);
263 debugf("Sending PTRACE_DETACH (and then KILL)\n");
264 ptrace(PTRACE_DETACH
, childpid
, NULL
, NULL
);
265 kill(childpid
, SIGKILL
);
266 reap_child(childpid
);
273 debugf("Child %d was stopped by %s\n", childpid
, strsignal(WTERMSIG(childstatus
)));
274 reap_child(childpid
);
277 debugf("Child %d was stopped by unhandled signal (%s).\n", childpid
, strsignal(WSTOPSIG(childstatus
)));
282 } else if (WIFCONTINUED(childstatus
)) {
285 output(0, "erk, wtf\n");
290 static void handle_children(void)
296 if (shm
->running_childs
== 0)
299 /* First, we wait for *any* child to wake us up. */
300 pid
= waitpid(-1, &childstatus
, WUNTRACED
| WCONTINUED
);
302 /* We were awoken, handle it. */
303 handle_child(pid
, childstatus
);
305 /* While we're awake, let's see if the other children need attention.
306 * We do this instead of just waitpid(-1) again so that there's no way
307 * for any one child to starve the others of attention.
309 for_each_pidslot(i
) {
313 if (pid
== EMPTY_PIDSLOT
)
316 if (pid_is_valid(pid
) == FALSE
)
319 pid
= waitpid(pid
, &childstatus
, WUNTRACED
| WCONTINUED
| WNOHANG
);
321 handle_child(pid
, childstatus
);
325 static const char *reasons
[NUM_EXIT_REASONS
] = {
327 "No more syscalls enabled.",
328 "Reached maximum syscall count.",
329 "No file descriptors open.",
330 "Lost track of a pid slot.",
331 "shm corruption - Found a pid out of range.",
333 "kernel became tainted.",
334 "SHM was corrupted!",
335 "Child reparenting problem",
336 "No files in file list.",
337 "Main process disappeared.",
339 "Something happened during fd init.",
343 static const char * decode_exit(unsigned int reason
)
345 return reasons
[reason
];
350 while (shm
->exit_reason
== STILL_RUNNING
) {
352 if (shm
->spawn_no_more
== FALSE
) {
353 if (shm
->running_childs
< max_children
)
356 /* Periodic regenation of fd's etc. */
357 if (shm
->regenerate
>= REGENERATION_POINT
)
360 if (shm
->need_reseed
== TRUE
)
367 /* Wait until all children have exited. */
368 while (pidmap_empty() == FALSE
)
371 outputerr("Bailing main loop. Exit reason: %s\n", decode_exit(shm
->exit_reason
));