diff options
-rw-r--r-- | jaildaemon.c | 82 |
1 files changed, 74 insertions, 8 deletions
diff --git a/jaildaemon.c b/jaildaemon.c index 506ca98..3ae8612 100644 --- a/jaildaemon.c +++ b/jaildaemon.c | |||
@@ -16,11 +16,17 @@ | |||
16 | #define IPC_PACKETSIZE 4096 | 16 | #define IPC_PACKETSIZE 4096 |
17 | #define MAGIC_EXIT_CODE 42 | 17 | #define MAGIC_EXIT_CODE 42 |
18 | enum { IAM_DAEMON, IAM_CLIENT, IAM_FORKSLAVE }; | 18 | enum { IAM_DAEMON, IAM_CLIENT, IAM_FORKSLAVE }; |
19 | static int g_uds; | 19 | static int g_uds; |
20 | static int g_whoami = IAM_CLIENT; | 20 | static int g_whoami = IAM_CLIENT; |
21 | static int g_fork_slave_fd; | 21 | static int g_fork_slave_fd; |
22 | static char g_ipc_packet[IPC_PACKETSIZE]; | 22 | static char g_ipc_packet[IPC_PACKETSIZE]; |
23 | static int * const g_ipc_packet_int = (int*)g_ipc_packet; | 23 | static int * const g_ipc_packet_int = (int*)g_ipc_packet; |
24 | |||
25 | /* For house keeping a list of all processes we attach to jails (probes), with | ||
26 | an initial vector size of 128. The vector never shrinks. */ | ||
27 | #define PROBES_VECTOR_SIZE 128 | ||
28 | static pid_t * g_probes; | ||
29 | static size_t g_probes_size; | ||
24 | 30 | ||
25 | typedef struct { | 31 | typedef struct { |
26 | int m_jid; | 32 | int m_jid; |
@@ -31,6 +37,8 @@ typedef struct { | |||
31 | 37 | ||
32 | /* Forward declarations */ | 38 | /* Forward declarations */ |
33 | static void signal_handler( int signal ); | 39 | static void signal_handler( int signal ); |
40 | static void term_handler( int signal ); | ||
41 | static void kill_all_probes( void ); | ||
34 | static int check_for_jail( int jid ); | 42 | static int check_for_jail( int jid ); |
35 | static int copy_daemontask( daemon_task ** out, daemon_task * const in ); | 43 | static int copy_daemontask( daemon_task ** out, daemon_task * const in ); |
36 | static int add_task_to_kqueue( int kq, daemon_task * task_in ); | 44 | static int add_task_to_kqueue( int kq, daemon_task * task_in ); |
@@ -49,6 +57,11 @@ static void signal_handler( int signal ) { | |||
49 | _exit( MAGIC_EXIT_CODE ); | 57 | _exit( MAGIC_EXIT_CODE ); |
50 | } | 58 | } |
51 | 59 | ||
60 | static void term_handler( int signal ) { | ||
61 | if( signal == SIGTERM ) | ||
62 | exit(0); | ||
63 | } | ||
64 | |||
52 | /* Report error through the appropriate notification channel. | 65 | /* Report error through the appropriate notification channel. |
53 | Currently this just writes to stderr, which hopefully still is there. */ | 66 | Currently this just writes to stderr, which hopefully still is there. */ |
54 | static void exerr( char * message ) { | 67 | static void exerr( char * message ) { |
@@ -266,10 +279,23 @@ static void fork_and_execve( int kq, daemon_task * t_in ) { | |||
266 | } | 279 | } |
267 | } | 280 | } |
268 | 281 | ||
282 | static void kill_all_probes( void ) { | ||
283 | size_t i; | ||
284 | syslog( LOG_ERR, "KILLING PROBES" ); | ||
285 | if( g_probes ) | ||
286 | for( i = 0; i < g_probes_size; ++i ) | ||
287 | if( g_probes[i] ) | ||
288 | kill( g_probes[i], SIGTERM ); | ||
289 | g_probes_size = 0; | ||
290 | free( g_probes ); | ||
291 | g_probes = 0; | ||
292 | } | ||
293 | |||
269 | static int add_task_to_kqueue( int kq, daemon_task * t_in ) { | 294 | static int add_task_to_kqueue( int kq, daemon_task * t_in ) { |
270 | struct kevent ke; | 295 | struct kevent ke; |
271 | daemon_task * t; | 296 | daemon_task * t; |
272 | pid_t pid; | 297 | pid_t pid; |
298 | size_t i; | ||
273 | 299 | ||
274 | if( check_for_jail( t_in->m_jid ) ) { | 300 | if( check_for_jail( t_in->m_jid ) ) { |
275 | syslog( LOG_ERR, "Invalid jail id: %d", t_in->m_jid ); | 301 | syslog( LOG_ERR, "Invalid jail id: %d", t_in->m_jid ); |
@@ -297,6 +323,27 @@ static int add_task_to_kqueue( int kq, daemon_task * t_in ) { | |||
297 | /* Expect reply from fork slave */ | 323 | /* Expect reply from fork slave */ |
298 | pid = *(pid_t*)g_ipc_packet; | 324 | pid = *(pid_t*)g_ipc_packet; |
299 | 325 | ||
326 | /* Account for new pid */ | ||
327 | for( i = 0; i < g_probes_size; ++i ) | ||
328 | if( !g_probes[i] ) | ||
329 | g_probes[i] = pid; | ||
330 | |||
331 | /* No space for pid entry => make room */ | ||
332 | if( i == g_probes_size ) { | ||
333 | size_t bytes = sizeof(pid_t) * g_probes_size; | ||
334 | pid_t *probes = realloc( g_probes, 4 * bytes ); | ||
335 | /* If we can not allocate memory, just ignore. Worst case is a defunct | ||
336 | probe process in the jail once the daemon dies. Probably the probe | ||
337 | will be killed anyway when the kevent below fails, too. */ | ||
338 | if( probes ) { | ||
339 | /* Erase new memory */ | ||
340 | memset( probes + g_probes_size, 0, 3 * bytes ); | ||
341 | probes[g_probes_size] = pid; | ||
342 | g_probes_size *= 4; | ||
343 | g_probes = probes; | ||
344 | } | ||
345 | } | ||
346 | |||
300 | /* Associate pid with command line to execute and add to our kqueue */ | 347 | /* Associate pid with command line to execute and add to our kqueue */ |
301 | memset( &ke, 0, sizeof ke ); | 348 | memset( &ke, 0, sizeof ke ); |
302 | EV_SET( &ke, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, t ); | 349 | EV_SET( &ke, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, t ); |
@@ -320,7 +367,7 @@ int main( int argc, char **argv ) { | |||
320 | int o_force_daemon = 0; | 367 | int o_force_daemon = 0; |
321 | int o_daemonize = 0, o_jid = -1, o_respawn = 0; | 368 | int o_daemonize = 0, o_jid = -1, o_respawn = 0; |
322 | char *o_command = NULL, *o_pidfile = NULL, *o_proctitle = NULL; | 369 | char *o_command = NULL, *o_pidfile = NULL, *o_proctitle = NULL; |
323 | char *o_uds_path = "/var/run/jaildaemon"; | 370 | char *o_uds_path = "/var/run/jaildaemon.pipe"; |
324 | struct kevent ke; | 371 | struct kevent ke; |
325 | struct sockaddr_un addr; | 372 | struct sockaddr_un addr; |
326 | struct sigaction sa; | 373 | struct sigaction sa; |
@@ -447,11 +494,16 @@ int main( int argc, char **argv ) { | |||
447 | /* We do not care for the spawned process -- it is checked for in our | 494 | /* We do not care for the spawned process -- it is checked for in our |
448 | kqueue filter. So just ignore SIGCHLD */ | 495 | kqueue filter. So just ignore SIGCHLD */ |
449 | memset( &sa, 0, sizeof( sa ) ); | 496 | memset( &sa, 0, sizeof( sa ) ); |
450 | sigemptyset(&sa.sa_mask); | ||
451 | sa.sa_flags = SA_NOCLDWAIT; | 497 | sa.sa_flags = SA_NOCLDWAIT; |
452 | if( sigaction(SIGCHLD, &sa, NULL) == -1 ) | 498 | if( sigaction(SIGCHLD, &sa, NULL) == -1 ) |
453 | exerr( "when trying to enable auto reap" ); | 499 | exerr( "when trying to enable auto reap" ); |
454 | 500 | ||
501 | /* When dying gracefully, this signal handler sends TERM signals to all | ||
502 | probes */ | ||
503 | sa.sa_handler = term_handler; | ||
504 | if( sigaction(SIGTERM, &sa, NULL) == -1 ) | ||
505 | exerr( "when trying to install TERM handler" ); | ||
506 | |||
455 | /* Create our kqueue */ | 507 | /* Create our kqueue */ |
456 | if( ( kq = kqueue( ) ) == -1 ) | 508 | if( ( kq = kqueue( ) ) == -1 ) |
457 | exerr( "when create kqueue" ); | 509 | exerr( "when create kqueue" ); |
@@ -466,10 +518,18 @@ int main( int argc, char **argv ) { | |||
466 | kevent( kq, &ke, 1, NULL, 0, NULL ); | 518 | kevent( kq, &ke, 1, NULL, 0, NULL ); |
467 | 519 | ||
468 | /* We want to be notified if the fork slave died. This is a good time to | 520 | /* We want to be notified if the fork slave died. This is a good time to |
469 | die, too*/ | 521 | die, too */ |
470 | EV_SET( &ke, g_fork_slave_fd, EVFILT_READ, EV_ADD, 0, 0, 0); | 522 | EV_SET( &ke, g_fork_slave_fd, EVFILT_READ, EV_ADD, 0, 0, 0); |
471 | kevent( kq, &ke, 1, NULL, 0, NULL ); | 523 | kevent( kq, &ke, 1, NULL, 0, NULL ); |
472 | 524 | ||
525 | /* Prepare probe pids list, initally 128 processes long, vector grows by | ||
526 | factor 4, when exhausted */ | ||
527 | g_probes = malloc( sizeof(pid_t) * PROBES_VECTOR_SIZE ); | ||
528 | g_probes_size = PROBES_VECTOR_SIZE; | ||
529 | if( !g_probes ) | ||
530 | exerr( "allocating memory." ); | ||
531 | memset( g_probes, 0, sizeof(pid_t) * PROBES_VECTOR_SIZE ); | ||
532 | atexit( kill_all_probes ); | ||
473 | 533 | ||
474 | /* If daemon was started with some initial script, fire it now | 534 | /* If daemon was started with some initial script, fire it now |
475 | -- this leaks some information in the command line to all jails and | 535 | -- this leaks some information in the command line to all jails and |
@@ -502,6 +562,7 @@ int main( int argc, char **argv ) { | |||
502 | switch( ke.filter ) { | 562 | switch( ke.filter ) { |
503 | case EVFILT_PROC: | 563 | case EVFILT_PROC: |
504 | if( ke.fflags & NOTE_EXIT ) { | 564 | if( ke.fflags & NOTE_EXIT ) { |
565 | size_t i; | ||
505 | daemon_task * task = (daemon_task *)ke.udata; | 566 | daemon_task * task = (daemon_task *)ke.udata; |
506 | if( !task ) | 567 | if( !task ) |
507 | continue; | 568 | continue; |
@@ -525,6 +586,11 @@ int main( int argc, char **argv ) { | |||
525 | EV_SET( &ke, ke.ident, EVFILT_PROC, EV_DELETE, NOTE_EXIT, | 586 | EV_SET( &ke, ke.ident, EVFILT_PROC, EV_DELETE, NOTE_EXIT, |
526 | 0, NULL ); | 587 | 0, NULL ); |
527 | kevent( kq, &ke, 1, NULL, 0, NULL ); | 588 | kevent( kq, &ke, 1, NULL, 0, NULL ); |
589 | |||
590 | /* Remove pid from our probes list */ | ||
591 | for( i = 0; i < g_probes_size; ++i ) | ||
592 | if( g_probes[i] == (pid_t)ke.ident ) | ||
593 | g_probes[i] = 0; | ||
528 | } | 594 | } |
529 | break; | 595 | break; |
530 | case EVFILT_READ: | 596 | case EVFILT_READ: |