55// License. See LICENSE.TXT for details.
66*/
77
8- #include "config.h"
8+ /**
9+ This file implements a shared library. This library can be pre-loaded by
10+ the dynamic linker of the Operating System (OS). It implements a few function
11+ related to process creation. By pre-load this library the executed process
12+ uses these functions instead of those from the standard library.
13+
14+ The idea here is to inject a logic before call the real methods. The logic is
15+ to dump the call into a file. To call the real method this library is doing
16+ the job of the dynamic linker.
17+
18+ The only input for the log writing is about the destination directory.
19+ This is passed as environment variable.
20+ */
921
10- #include "stringarray.h"
11- #include "environ.h"
12- #include "protocol.h"
22+ #include "config.h"
1323
1424#include <sys/types.h>
1525#include <sys/stat.h>
26+ #include <ctype.h>
27+ #include <stddef.h>
1628#include <stdarg.h>
1729#include <stdlib.h>
1830#include <stdio.h>
31+ #include <string.h>
1932#include <unistd.h>
20-
33+ #include <fcntl.h>
2134#include <dlfcn.h>
2235
2336#if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
2437#include <spawn.h>
2538#endif
2639
40+ #ifdef HAVE_NSGETENVIRON
41+ #include <crt_externs.h>
42+ #else
43+ extern char * * environ ;
44+ #endif
2745
2846#ifdef __APPLE__
2947# define EXEC_LOOP_ON_EXECVE
3048#endif
3149
32- static char const * * update_environment (char * const envp []);
3350
34- static void report_call (char const * fun , char const * const argv []);
51+ typedef struct
52+ {
53+ pid_t pid ;
54+ pid_t ppid ;
55+ char const * fun ;
56+ char const * cwd ;
57+ char const * * cmd ;
58+ } bear_message_t ;
59+
60+ static char const * * bear_update_environment (char * const envp []);
61+ static void bear_report_call (char const * fun , char const * const argv []);
62+ static void bear_write_message (int fd , bear_message_t const * e );
63+ static void bear_send_message (char const * destination , bear_message_t const * e );
64+ static char const * * bear_update_environ (char const * * in , char const * key );
65+ static char * * bear_get_environ (void );
66+ static char const * * bear_strings_build (char const * arg , va_list * ap );
67+ static char const * * bear_strings_copy (char const * * const in );
68+ static char const * * bear_strings_append (char const * * in , char const * e );
69+ static size_t bear_strings_length (char const * const * in );
70+ static void bear_strings_release (char const * * );
71+
3572
3673#ifdef EXEC_LOOP_ON_EXECVE
3774 static int already_reported = 0 ;
3875# define REPORT_CALL (ARGV_ ) \
3976 int const report_state = already_reported; \
4077 if (!already_reported) { \
41- report_call (__func__, (char const * const *)ARGV_); \
78+ bear_report_call (__func__, (char const * const *)ARGV_); \
4279 already_reported = 1; \
4380 }
4481# define REPORT_FAILED_CALL (RESULT_ ) \
4582 if (!report_state) { \
4683 already_reported = 0; \
4784 }
4885#else
49- # define REPORT_CALL (ARGV_ ) report_call (__func__, (char const * const *)ARGV_);
86+ # define REPORT_CALL (ARGV_ ) bear_report_call (__func__, (char const * const *)ARGV_);
5087# define REPORT_FAILED_CALL (RESULT_ )
5188#endif
5289
@@ -90,6 +127,9 @@ static int call_posix_spawnp(pid_t *restrict pid,
90127#endif
91128
92129
130+ /* These are the methods we are try to hijack.
131+ */
132+
93133#if defined HAVE_VFORK && defined EXEC_LOOP_ON_EXECVE
94134pid_t vfork (void )
95135{
@@ -249,14 +289,16 @@ int posix_spawnp(pid_t *restrict pid,
249289}
250290#endif
251291
292+ /* These are the methods which forward the call to the standard implementation. */
293+
252294#ifdef HAVE_EXECVE
253295static int call_execve (const char * path , char * const argv [], char * const envp [])
254296{
255297 typedef int (* func )(const char * , char * const * , char * const * );
256298
257299 DLSYM (func , fp , "execve" );
258300
259- char const * * const menvp = update_environment (envp );
301+ char const * * const menvp = bear_update_environment (envp );
260302 int const result = (* fp )(path , argv , (char * const * )menvp );
261303 bear_strings_release (menvp );
262304 return result ;
@@ -270,7 +312,7 @@ static int call_execvpe(const char * file, char * const argv[], char * const env
270312
271313 DLSYM (func , fp , "execvpe" );
272314
273- char const * * const menvp = update_environment (envp );
315+ char const * * const menvp = bear_update_environment (envp );
274316 int const result = (* fp )(file , argv , (char * const * )menvp );
275317 bear_strings_release (menvp );
276318 return result ;
@@ -341,7 +383,73 @@ static int call_posix_spawnp(pid_t *restrict pid,
341383}
342384#endif
343385
344- static char const * * update_environment (char * const envp [])
386+ /* these methods are for to write log about the process creation. */
387+
388+ static void bear_report_call (char const * fun , char const * const argv [])
389+ {
390+ char * const destination = getenv (ENV_OUTPUT );
391+ if (0 == destination )
392+ {
393+ perror ("bear: getenv" );
394+ exit (EXIT_FAILURE );
395+ }
396+ const char * cwd = getcwd (NULL , 0 );
397+ if (0 == cwd )
398+ {
399+ perror ("bear: getcwd" );
400+ exit (EXIT_FAILURE );
401+ }
402+
403+ bear_message_t const msg =
404+ {
405+ getpid (),
406+ getppid (),
407+ fun ,
408+ cwd ,
409+ (char const * * )argv
410+ };
411+ bear_send_message (destination , & msg );
412+
413+ free ((void * )cwd );
414+ }
415+
416+ static void bear_write_message (int fd , bear_message_t const * e )
417+ {
418+ static int const RS = 0x1e ;
419+ static int const US = 0x1f ;
420+ dprintf (fd , "%d%c" , e -> pid , RS );
421+ dprintf (fd , "%d%c" , e -> ppid , RS );
422+ dprintf (fd , "%s%c" , e -> fun , RS );
423+ dprintf (fd , "%s%c" , e -> cwd , RS );
424+ size_t const length = bear_strings_length (e -> cmd );
425+ for (size_t it = 0 ; it < length ; ++ it )
426+ {
427+ dprintf (fd , "%s%c" , e -> cmd [it ], US );
428+ }
429+ }
430+
431+ static void bear_send_message (char const * destination , bear_message_t const * msg )
432+ {
433+ char * filename = 0 ;
434+ if (-1 == asprintf (& filename , "%s/cmd.XXXXXX" , destination ))
435+ {
436+ perror ("bear: asprintf" );
437+ exit (EXIT_FAILURE );
438+ }
439+ int fd = mkstemp (filename );
440+ free ((void * )filename );
441+ if (-1 == fd )
442+ {
443+ perror ("bear: open" );
444+ exit (EXIT_FAILURE );
445+ }
446+ bear_write_message (fd , msg );
447+ close (fd );
448+ }
449+
450+ /* update environment assure that chilren processes will copy the desired behaviour */
451+
452+ static char const * * bear_update_environment (char * const envp [])
345453{
346454 char const * * result = bear_strings_copy ((char const * * )envp );
347455 result = bear_update_environ (result , ENV_PRELOAD );
@@ -352,30 +460,144 @@ static char const * * update_environment(char * const envp[])
352460 return result ;
353461}
354462
355- typedef void (* send_message )(char const * destination , bear_message_t const * );
463+ static char const * * bear_update_environ (char const * envs [], char const * key )
464+ {
465+ char const * const value = getenv (key );
466+ if (0 == value )
467+ {
468+ perror ("bear: getenv" );
469+ exit (EXIT_FAILURE );
470+ }
471+ // find the key if it's there
472+ size_t const key_length = strlen (key );
473+ char const * * it = envs ;
474+ for (; (it ) && (* it ); ++ it )
475+ {
476+ if ((0 == strncmp (* it , key , key_length )) &&
477+ (strlen (* it ) > key_length ) &&
478+ ('=' == (* it )[key_length ]))
479+ break ;
480+ }
481+ // check the value might already correct
482+ char const * * result = envs ;
483+ if ((0 != it ) && ((0 == * it ) || (strcmp (* it + key_length + 1 , value ))))
484+ {
485+ char * env = 0 ;
486+ if (-1 == asprintf (& env , "%s=%s" , key , value ))
487+ {
488+ perror ("bear: asprintf" );
489+ exit (EXIT_FAILURE );
490+ }
491+ if (* it )
492+ {
493+ free ((void * )* it );
494+ * it = env ;
495+ }
496+ else
497+ result = bear_strings_append (envs , env );
498+ }
499+ return result ;
500+ }
501+
502+ static char * * bear_get_environ (void )
503+ {
504+ #ifdef HAVE_NSGETENVIRON
505+ // environ is not available for shared libraries have to use _NSGetEnviron()
506+ return * _NSGetEnviron ();
507+ #else
508+ return environ ;
509+ #endif
510+ }
356511
357- static void report (send_message fp , char const * destination , char const * fun , char const * const argv [])
512+ /* util methods to deal with string arrays. environment and process arguments
513+ are both represented as string arrays. */
514+
515+ static char const * * bear_strings_build (char const * const arg , va_list * args )
358516{
359- bear_message_t const msg =
517+ char const * * result = 0 ;
518+ size_t size = 0 ;
519+ for (char const * it = arg ; it ; it = va_arg (* args , char const * ))
360520 {
361- getpid (),
362- getppid (),
363- fun ,
364- getcwd (NULL , 0 ),
365- (char const * * )argv
366- };
367- (* fp )(destination , & msg );
368- free ((void * )msg .cwd );
521+ result = realloc (result , (size + 1 ) * sizeof (char const * ));
522+ if (0 == result )
523+ {
524+ perror ("bear: realloc" );
525+ exit (EXIT_FAILURE );
526+ }
527+ char const * copy = strdup (it );
528+ if (0 == copy )
529+ {
530+ perror ("bear: strdup" );
531+ exit (EXIT_FAILURE );
532+ }
533+ result [size ++ ] = copy ;
534+ }
535+ result = realloc (result , (size + 1 ) * sizeof (char const * ));
536+ if (0 == result )
537+ {
538+ perror ("bear: realloc" );
539+ exit (EXIT_FAILURE );
540+ }
541+ result [size ++ ] = 0 ;
542+
543+ return result ;
369544}
370545
371- static void report_call ( char const * fun , char const * const argv [] )
546+ static char const * * bear_strings_copy ( char const * * const in )
372547{
373- char * const destination = getenv (ENV_OUTPUT );
374- if (0 == destination )
548+ size_t const size = bear_strings_length (in );
549+
550+ char const * * const result = malloc ((size + 1 ) * sizeof (char const * ));
551+ if (0 == result )
375552 {
376- perror ("bear: getenv " );
553+ perror ("bear: malloc " );
377554 exit (EXIT_FAILURE );
378555 }
379556
380- report (bear_send_message , destination , fun , argv );
557+ char const * * out_it = result ;
558+ for (char const * const * in_it = in ; (in_it ) && (* in_it ); ++ in_it , ++ out_it )
559+ {
560+ * out_it = strdup (* in_it );
561+ if (0 == * out_it )
562+ {
563+ perror ("bear: strdup" );
564+ exit (EXIT_FAILURE );
565+ }
566+ }
567+ * out_it = 0 ;
568+ return result ;
569+ }
570+
571+ static char const * * bear_strings_append (char const * * const in , char const * const e )
572+ {
573+ if (0 == e )
574+ return in ;
575+
576+ size_t size = bear_strings_length (in );
577+ char const * * result = realloc (in , (size + 2 ) * sizeof (char const * ));
578+ if (0 == result )
579+ {
580+ perror ("bear: realloc" );
581+ exit (EXIT_FAILURE );
582+ }
583+ result [size ++ ] = e ;
584+ result [size ++ ] = 0 ;
585+ return result ;
586+ }
587+
588+ static size_t bear_strings_length (char const * const * const in )
589+ {
590+ size_t result = 0 ;
591+ for (char const * const * it = in ; (it ) && (* it ); ++ it )
592+ ++ result ;
593+ return result ;
594+ }
595+
596+ static void bear_strings_release (char const * * in )
597+ {
598+ for (char const * const * it = in ; (it ) && (* it ); ++ it )
599+ {
600+ free ((void * )* it );
601+ }
602+ free ((void * )in );
381603}
0 commit comments