Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /* -*- coding: utf-8 -*-
  2. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  3. // See https://llvm.org/LICENSE.txt for license information.
  4. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  5. */
  6.  
  7. /**
  8.  * This file implements a shared library. This library can be pre-loaded by
  9.  * the dynamic linker of the Operating System (OS). It implements a few function
  10.  * related to process creation. By pre-load this library the executed process
  11.  * uses these functions instead of those from the standard library.
  12.  *
  13.  * The idea here is to inject a logic before call the real methods. The logic is
  14.  * to dump the call into a file. To call the real method this library is doing
  15.  * the job of the dynamic linker.
  16.  *
  17.  * The only input for the log writing is about the destination directory.
  18.  * This is passed as environment variable.
  19.  */
  20.  
  21. // NOLINTNEXTLINE
  22. #include "config.h"
  23.  
  24. #include <dlfcn.h>
  25. #include <pthread.h>
  26. #include <stdarg.h>
  27. #include <stddef.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <unistd.h>
  32.  
  33. #if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
  34. #include <spawn.h>
  35. #endif
  36.  
  37. #if defined HAVE_NSGETENVIRON
  38. #include <crt_externs.h>
  39. #else
  40. extern char **environ;
  41. #endif
  42.  
  43. #define ENV_OUTPUT "INTERCEPT_BUILD_TARGET_DIR"
  44. #ifdef APPLE
  45. #define ENV_FLAT "DYLD_FORCE_FLAT_NAMESPACE"
  46. #define ENV_PRELOAD "DYLD_INSERT_LIBRARIES"
  47. #define ENV_SIZE 3
  48. #else
  49. #define ENV_PRELOAD "LD_PRELOAD"
  50. #define ENV_SIZE 2
  51. #endif
  52.  
  53. #define DLSYM(TYPE_, VAR_, SYMBOL_)                                            \
  54.   union {                                                                      \
  55.     void *from;                                                                \
  56.     TYPE_ to;                                                                  \
  57.   } cast;                                                                      \
  58.   if (0 == (cast.from = dlsym(RTLD_NEXT, SYMBOL_))) {                          \
  59.     perror("bear: dlsym");                                                     \
  60.     exit(EXIT_FAILURE);                                                        \
  61.   }                                                                            \
  62.   TYPE_ const VAR_ = cast.to;
  63.  
  64. typedef char const *bear_env_t[ENV_SIZE];
  65.  
  66. static int bear_capture_env_t(bear_env_t *env);
  67. static int bear_reset_env_t(bear_env_t *env);
  68. static void bear_release_env_t(bear_env_t *env);
  69. static char const **bear_update_environment(char *const envp[],
  70.                                             bear_env_t *env);
  71. static char const **bear_update_environ(char const **in, char const *key,
  72.                                         char const *value);
  73. static char **bear_get_environment();
  74. static void bear_report_call(char const *fun, char const *const argv[]);
  75. static char const **bear_strings_build(char const *arg, va_list *ap);
  76. static char const **bear_strings_copy(char const **const in);
  77. static char const **bear_strings_append(char const **in, char const *e);
  78. static size_t bear_strings_length(char const *const *in);
  79. static void bear_strings_release(char const **);
  80.  
  81. static bear_env_t env_names = {ENV_OUTPUT, ENV_PRELOAD
  82. #ifdef ENV_FLAT
  83.                                ,
  84.                                ENV_FLAT
  85. #endif
  86. };
  87.  
  88. static bear_env_t initial_env = {0, 0
  89. #ifdef ENV_FLAT
  90.                                  ,
  91.                                  0
  92. #endif
  93. };
  94.  
  95. static int initialized = 0;
  96. static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  97.  
  98. static void on_load(void) __attribute__((constructor));
  99. static void on_unload(void) __attribute__((destructor));
  100.  
  101. #ifdef HAVE_EXECVE
  102. static int call_execve(const char *path, char *const argv[],
  103.                        char *const envp[]);
  104. #endif
  105. #ifdef HAVE_EXECVP
  106. static int call_execvp(const char *file, char *const argv[]);
  107. #endif
  108. #ifdef HAVE_EXECVPE
  109. static int call_execvpe(const char *file, char *const argv[],
  110.                         char *const envp[]);
  111. #endif
  112. #ifdef HAVE_EXECVP2
  113. static int call_execvP(const char *file, const char *search_path,
  114.                        char *const argv[]);
  115. #endif
  116. #ifdef HAVE_EXECT
  117. static int call_exect(const char *path, char *const argv[], char *const envp[]);
  118. #endif
  119. #ifdef HAVE_POSIX_SPAWN
  120. static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
  121.                             const posix_spawn_file_actions_t *file_actions,
  122.                             const posix_spawnattr_t *restrict attrp,
  123.                             char *const argv[restrict],
  124.                             char *const envp[restrict]);
  125. #endif
  126. #ifdef HAVE_POSIX_SPAWNP
  127. static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
  128.                              const posix_spawn_file_actions_t *file_actions,
  129.                              const posix_spawnattr_t *restrict attrp,
  130.                              char *const argv[restrict],
  131.                              char *const envp[restrict]);
  132. #endif
  133.  
  134. /* Initialization method to Captures the relevant environment variables.
  135.  */
  136.  
  137. static void on_load(void) {
  138.   pthread_mutex_lock(&mutex);
  139.   if (!initialized)
  140.     initialized = bear_capture_env_t(&initial_env);
  141.   pthread_mutex_unlock(&mutex);
  142. }
  143.  
  144. static void on_unload(void) {
  145.   pthread_mutex_lock(&mutex);
  146.   bear_release_env_t(&initial_env);
  147.   initialized = 0;
  148.   pthread_mutex_unlock(&mutex);
  149. }
  150.  
  151. /* These are the methods we are try to hijack.
  152.  */
  153.  
  154. #ifdef HAVE_EXECVE
  155. int execve(const char *path, char *const argv[], char *const envp[]) {
  156.   bear_report_call(__func__, (char const *const *)argv);
  157.   return call_execve(path, argv, envp);
  158. }
  159. #endif
  160.  
  161. #ifdef HAVE_EXECV
  162. #ifndef HAVE_EXECVE
  163. #error can not implement execv without execve
  164. #endif
  165. int execv(const char *path, char *const argv[]) {
  166.   bear_report_call(__func__, (char const *const *)argv);
  167.   char *const *envp = bear_get_environment();
  168.   return call_execve(path, argv, envp);
  169. }
  170. #endif
  171.  
  172. #ifdef HAVE_EXECVPE
  173. int execvpe(const char *file, char *const argv[], char *const envp[]) {
  174.   bear_report_call(__func__, (char const *const *)argv);
  175.   return call_execvpe(file, argv, envp);
  176. }
  177. #endif
  178.  
  179. #ifdef HAVE_EXECVP
  180. int execvp(const char *file, char *const argv[]) {
  181.   bear_report_call(__func__, (char const *const *)argv);
  182.   return call_execvp(file, argv);
  183. }
  184. #endif
  185.  
  186. #ifdef HAVE_EXECVP2
  187. int execvP(const char *file, const char *search_path, char *const argv[]) {
  188.   bear_report_call(__func__, (char const *const *)argv);
  189.   return call_execvP(file, search_path, argv);
  190. }
  191. #endif
  192.  
  193. #ifdef HAVE_EXECT
  194. int exect(const char *path, char *const argv[], char *const envp[]) {
  195.   bear_report_call(__func__, (char const *const *)argv);
  196.   return call_exect(path, argv, envp);
  197. }
  198. #endif
  199.  
  200. #ifdef HAVE_EXECL
  201. #ifndef HAVE_EXECVE
  202. #error can not implement execl without execve
  203. #endif
  204. int execl(const char *path, const char *arg, ...) {
  205.   va_list args;
  206.   va_start(args, arg);
  207.   char const **argv = bear_strings_build(arg, &args);
  208.   va_end(args);
  209.  
  210.   bear_report_call(__func__, (char const *const *)argv);
  211.   char *const *envp = bear_get_environment();
  212.   int const result = call_execve(path, (char *const *)argv, envp);
  213.  
  214.   bear_strings_release(argv);
  215.   return result;
  216. }
  217. #endif
  218.  
  219. #ifdef HAVE_EXECLP
  220. #ifndef HAVE_EXECVP
  221. #error can not implement execlp without execvp
  222. #endif
  223. int execlp(const char *file, const char *arg, ...) {
  224.   va_list args;
  225.   va_start(args, arg);
  226.   char const **argv = bear_strings_build(arg, &args);
  227.   va_end(args);
  228.  
  229.   bear_report_call(__func__, (char const *const *)argv);
  230.   int const result = call_execvp(file, (char *const *)argv);
  231.  
  232.   bear_strings_release(argv);
  233.   return result;
  234. }
  235. #endif
  236.  
  237. #ifdef HAVE_EXECLE
  238. #ifndef HAVE_EXECVE
  239. #error can not implement execle without execve
  240. #endif
  241. // int execle(const char *path, const char *arg, ..., char * const envp[]);
  242. int execle(const char *path, const char *arg, ...) {
  243.   va_list args;
  244.   va_start(args, arg);
  245.   char const **argv = bear_strings_build(arg, &args);
  246.   char const **envp = va_arg(args, char const **);
  247.   va_end(args);
  248.  
  249.   bear_report_call(__func__, (char const *const *)argv);
  250.   int const result =
  251.       call_execve(path, (char *const *)argv, (char *const *)envp);
  252.  
  253.   bear_strings_release(argv);
  254.   return result;
  255. }
  256. #endif
  257.  
  258. #ifdef HAVE_POSIX_SPAWN
  259. int posix_spawn(pid_t *restrict pid, const char *restrict path,
  260.                 const posix_spawn_file_actions_t *file_actions,
  261.                 const posix_spawnattr_t *restrict attrp,
  262.                 char *const argv[restrict], char *const envp[restrict]) {
  263.   bear_report_call(__func__, (char const *const *)argv);
  264.   return call_posix_spawn(pid, path, file_actions, attrp, argv, envp);
  265. }
  266. #endif
  267.  
  268. #ifdef HAVE_POSIX_SPAWNP
  269. int posix_spawnp(pid_t *restrict pid, const char *restrict file,
  270.                  const posix_spawn_file_actions_t *file_actions,
  271.                  const posix_spawnattr_t *restrict attrp,
  272.                  char *const argv[restrict], char *const envp[restrict]) {
  273.   bear_report_call(__func__, (char const *const *)argv);
  274.   return call_posix_spawnp(pid, file, file_actions, attrp, argv, envp);
  275. }
  276. #endif
  277.  
  278. /* These are the methods which forward the call to the standard implementation.
  279.  */
  280.  
  281. #ifdef HAVE_EXECVE
  282. static int call_execve(const char *path, char *const argv[],
  283.                        char *const envp[]) {
  284.   typedef int (*func)(const char *, char *const *, char *const *);
  285.  
  286.   DLSYM(func, fp, "execve");
  287.  
  288.   char const **const menvp = bear_update_environment(envp, &initial_env);
  289.   int const result = (*fp)(path, argv, (char *const *)menvp);
  290.   bear_strings_release(menvp);
  291.   return result;
  292. }
  293. #endif
  294.  
  295. #ifdef HAVE_EXECVPE
  296. static int call_execvpe(const char *file, char *const argv[],
  297.                         char *const envp[]) {
  298.   typedef int (*func)(const char *, char *const *, char *const *);
  299.  
  300.   DLSYM(func, fp, "execvpe");
  301.  
  302.   char const **const menvp = bear_update_environment(envp, &initial_env);
  303.   int const result = (*fp)(file, argv, (char *const *)menvp);
  304.   bear_strings_release(menvp);
  305.   return result;
  306. }
  307. #endif
  308.  
  309. #ifdef HAVE_EXECVP
  310. static int call_execvp(const char *file, char *const argv[]) {
  311.   typedef int (*func)(const char *file, char *const argv[]);
  312.  
  313.   DLSYM(func, fp, "execvp");
  314.  
  315.   bear_env_t current_env;
  316.   bear_capture_env_t(&current_env);
  317.   bear_reset_env_t(&initial_env);
  318.   int const result = (*fp)(file, argv);
  319.   bear_reset_env_t(&current_env);
  320.   bear_release_env_t(&current_env);
  321.  
  322.   return result;
  323. }
  324. #endif
  325.  
  326. #ifdef HAVE_EXECVP2
  327. static int call_execvP(const char *file, const char *search_path,
  328.                        char *const argv[]) {
  329.   typedef int (*func)(const char *, const char *, char *const *);
  330.  
  331.   DLSYM(func, fp, "execvP");
  332.  
  333.   bear_env_t current_env;
  334.   bear_capture_env_t(&current_env);
  335.   bear_reset_env_t(&initial_env);
  336.   int const result = (*fp)(file, search_path, argv);
  337.   bear_reset_env_t(&current_env);
  338.   bear_release_env_t(&current_env);
  339.  
  340.   return result;
  341. }
  342. #endif
  343.  
  344. #ifdef HAVE_EXECT
  345. static int call_exect(const char *path, char *const argv[],
  346.                       char *const envp[]) {
  347.   typedef int (*func)(const char *, char *const *, char *const *);
  348.  
  349.   DLSYM(func, fp, "exect");
  350.  
  351.   char const **const menvp = bear_update_environment(envp, &initial_env);
  352.   int const result = (*fp)(path, argv, (char *const *)menvp);
  353.   bear_strings_release(menvp);
  354.   return result;
  355. }
  356. #endif
  357.  
  358. #ifdef HAVE_POSIX_SPAWN
  359. static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
  360.                             const posix_spawn_file_actions_t *file_actions,
  361.                             const posix_spawnattr_t *restrict attrp,
  362.                             char *const argv[restrict],
  363.                             char *const envp[restrict]) {
  364.   typedef int (*func)(pid_t *restrict, const char *restrict,
  365.                       const posix_spawn_file_actions_t *,
  366.                       const posix_spawnattr_t *restrict, char *const *restrict,
  367.                       char *const *restrict);
  368.  
  369.   DLSYM(func, fp, "posix_spawn");
  370.  
  371.   char const **const menvp = bear_update_environment(envp, &initial_env);
  372.   int const result =
  373.       (*fp)(pid, path, file_actions, attrp, argv, (char *const *restrict)menvp);
  374.   bear_strings_release(menvp);
  375.   return result;
  376. }
  377. #endif
  378.  
  379. #ifdef HAVE_POSIX_SPAWNP
  380. static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
  381.                              const posix_spawn_file_actions_t *file_actions,
  382.                              const posix_spawnattr_t *restrict attrp,
  383.                              char *const argv[restrict],
  384.                              char *const envp[restrict]) {
  385.   typedef int (*func)(pid_t *restrict, const char *restrict,
  386.                       const posix_spawn_file_actions_t *,
  387.                       const posix_spawnattr_t *restrict, char *const *restrict,
  388.                       char *const *restrict);
  389.  
  390.   DLSYM(func, fp, "posix_spawnp");
  391.  
  392.   char const **const menvp = bear_update_environment(envp, &initial_env);
  393.   int const result =
  394.       (*fp)(pid, file, file_actions, attrp, argv, (char *const *restrict)menvp);
  395.   bear_strings_release(menvp);
  396.   return result;
  397. }
  398. #endif
  399.  
  400. /* this method is to write log about the process creation. */
  401.  
  402. static void bear_report_call(char const *fun, char const *const argv[]) {
  403.   static int const GS = 0x1d;
  404.   static int const RS = 0x1e;
  405.   static int const US = 0x1f;
  406.  
  407.   if (!initialized)
  408.     return;
  409.  
  410.   pthread_mutex_lock(&mutex);
  411.   const char *cwd = getcwd(NULL, 0);
  412.   if (0 == cwd) {
  413.     perror("bear: getcwd");
  414.     pthread_mutex_unlock(&mutex);
  415.     exit(EXIT_FAILURE);
  416.   }
  417.   char const *const out_dir = initial_env[0];
  418.   size_t const path_max_length = strlen(out_dir) + 32;
  419.   char filename[path_max_length];
  420.   if (-1 ==
  421.       snprintf(filename, path_max_length, "%s/%d.cmd", out_dir, getpid())) {
  422.     perror("bear: snprintf");
  423.     pthread_mutex_unlock(&mutex);
  424.     exit(EXIT_FAILURE);
  425.   }
  426.   FILE *fd = fopen(filename, "a+");
  427.   if (0 == fd) {
  428.     perror("bear: fopen");
  429.     pthread_mutex_unlock(&mutex);
  430.     exit(EXIT_FAILURE);
  431.   }
  432.   fprintf(fd, "%d%c", getpid(), RS);
  433.   fprintf(fd, "%d%c", getppid(), RS);
  434.   fprintf(fd, "%s%c", fun, RS);
  435.   fprintf(fd, "%s%c", cwd, RS);
  436.   size_t const argc = bear_strings_length(argv);
  437.   for (size_t it = 0; it < argc; ++it) {
  438.     fprintf(fd, "%s%c", argv[it], US);
  439.   }
  440.   fprintf(fd, "%c", GS);
  441.   if (fclose(fd)) {
  442.     perror("bear: fclose");
  443.     pthread_mutex_unlock(&mutex);
  444.     exit(EXIT_FAILURE);
  445.   }
  446.   free((void *)cwd);
  447.   pthread_mutex_unlock(&mutex);
  448. }
  449.  
  450. /* update environment assure that children processes will copy the desired
  451.  * behaviour */
  452.  
  453. static int bear_capture_env_t(bear_env_t *env) {
  454.   int status = 1;
  455.   for (size_t it = 0; it < ENV_SIZE; ++it) {
  456.     char const *const env_value = getenv(env_names[it]);
  457.     char const *const env_copy = (env_value) ? strdup(env_value) : env_value;
  458.     (*env)[it] = env_copy;
  459.     status &= (env_copy) ? 1 : 0;
  460.   }
  461.   return status;
  462. }
  463.  
  464. static int bear_reset_env_t(bear_env_t *env) {
  465.   int status = 1;
  466.   for (size_t it = 0; it < ENV_SIZE; ++it) {
  467.     if ((*env)[it]) {
  468.       setenv(env_names[it], (*env)[it], 1);
  469.     } else {
  470.       unsetenv(env_names[it]);
  471.     }
  472.   }
  473.   return status;
  474. }
  475.  
  476. static void bear_release_env_t(bear_env_t *env) {
  477.   for (size_t it = 0; it < ENV_SIZE; ++it) {
  478.     free((void *)(*env)[it]);
  479.     (*env)[it] = 0;
  480.   }
  481. }
  482.  
  483. static char const **bear_update_environment(char *const envp[],
  484.                                             bear_env_t *env) {
  485.   char const **result = bear_strings_copy((char const **)envp);
  486.   for (size_t it = 0; it < ENV_SIZE && (*env)[it]; ++it)
  487.     result = bear_update_environ(result, env_names[it], (*env)[it]);
  488.   return result;
  489. }
  490.  
  491. static char const **bear_update_environ(char const *envs[], char const *key,
  492.                                         char const *const value) {
  493.   // find the key if it's there
  494.   size_t const key_length = strlen(key);
  495.   char const **it = envs;
  496.   for (; (it) && (*it); ++it) {
  497.     if ((0 == strncmp(*it, key, key_length)) && (strlen(*it) > key_length) &&
  498.         ('=' == (*it)[key_length]))
  499.       break;
  500.   }
  501.   // allocate a environment entry
  502.   size_t const value_length = strlen(value);
  503.   size_t const env_length = key_length + value_length + 2;
  504.   char *env = malloc(env_length);
  505.   if (0 == env) {
  506.     perror("bear: malloc [in env_update]");
  507.     exit(EXIT_FAILURE);
  508.   }
  509.   if (-1 == snprintf(env, env_length, "%s=%s", key, value)) {
  510.     perror("bear: snprintf");
  511.     exit(EXIT_FAILURE);
  512.   }
  513.   // replace or append the environment entry
  514.   if (it && *it) {
  515.     free((void *)*it);
  516.     *it = env;
  517.     return envs;
  518.   }
  519.   return bear_strings_append(envs, env);
  520. }
  521.  
  522. static char **bear_get_environment() {
  523. #if defined HAVE_NSGETENVIRON
  524.   return *_NSGetEnviron();
  525. #else
  526.   return environ;
  527. #endif
  528. }
  529.  
  530. /* util methods to deal with string arrays. environment and process arguments
  531.  * are both represented as string arrays. */
  532.  
  533. static char const **bear_strings_build(char const *const arg, va_list *args) {
  534.   char const **result = 0;
  535.   size_t size = 0;
  536.   for (char const *it = arg; it; it = va_arg(*args, char const *)) {
  537.     result = realloc(result, (size + 1) * sizeof(char const *));
  538.     if (0 == result) {
  539.       perror("bear: realloc");
  540.       exit(EXIT_FAILURE);
  541.     }
  542.     char const *copy = strdup(it);
  543.     if (0 == copy) {
  544.       perror("bear: strdup");
  545.       exit(EXIT_FAILURE);
  546.     }
  547.     result[size++] = copy;
  548.   }
  549.   result = realloc(result, (size + 1) * sizeof(char const *));
  550.   if (0 == result) {
  551.     perror("bear: realloc");
  552.     exit(EXIT_FAILURE);
  553.   }
  554.   result[size++] = 0;
  555.  
  556.   return result;
  557. }
  558.  
  559. static char const **bear_strings_copy(char const **const in) {
  560.   size_t const size = bear_strings_length(in);
  561.  
  562.   char const **const result = malloc((size + 1) * sizeof(char const *));
  563.   if (0 == result) {
  564.     perror("bear: malloc");
  565.     exit(EXIT_FAILURE);
  566.   }
  567.  
  568.   char const **out_it = result;
  569.   for (char const *const *in_it = in; (in_it) && (*in_it); ++in_it, ++out_it) {
  570.     *out_it = strdup(*in_it);
  571.     if (0 == *out_it) {
  572.       perror("bear: strdup");
  573.       exit(EXIT_FAILURE);
  574.     }
  575.   }
  576.   *out_it = 0;
  577.   return result;
  578. }
  579.  
  580. static char const **bear_strings_append(char const **const in,
  581.                                         char const *const e) {
  582.   size_t size = bear_strings_length(in);
  583.   char const **result = realloc(in, (size + 2) * sizeof(char const *));
  584.   if (0 == result) {
  585.     perror("bear: realloc");
  586.     exit(EXIT_FAILURE);
  587.   }
  588.   result[size++] = e;
  589.   result[size++] = 0;
  590.   return result;
  591. }
  592.  
  593. static size_t bear_strings_length(char const *const *const in) {
  594.   size_t result = 0;
  595.   for (char const *const *it = in; (it) && (*it); ++it)
  596.     ++result;
  597.   return result;
  598. }
  599.  
  600. static void bear_strings_release(char const **in) {
  601.   for (char const *const *it = in; (it) && (*it); ++it) {
  602.     free((void *)*it);
  603.   }
  604.   free((void *)in);
  605. }
  606.