diff options
| author | erdgeist <> | 2013-03-02 02:26:17 +0000 | 
|---|---|---|
| committer | erdgeist <> | 2013-03-02 02:26:17 +0000 | 
| commit | 87dc06e5e85a98eea2d5ebcca81c856ff2a2cbb4 (patch) | |
| tree | b4411a4e1564e628cbc35abad72b4ca7995ebc3e | |
| parent | 78615157edb1b25a8d64ad59b8649713cd39b42c (diff) | |
Keep a list of our probe's jids and kill them when the daemon exits
| -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: | 
