xref: /netbsd-src/external/gpl3/binutils.old/dist/gprofng/libcollector/linetrace.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2    Contributed by Oracle.
3 
4    This file is part of GNU Binutils.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 /*
22  *	Lineage events for process fork, exec, etc.
23  */
24 
25 #include "config.h"
26 #include <string.h>
27 #include <elf.h>
28 #include <regex.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/mman.h>
32 
33 #include "descendants.h"
34 
35 /* TprintfT(<level>,...) definitions.  Adjust per module as needed */
36 #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
37 #define DBG_LTT 0 // for interposition on GLIBC functions
38 #define DBG_LT1 1 // for configuration details, warnings
39 #define DBG_LT2 2
40 #define DBG_LT3 3
41 
42 #define LT_MAXNAMELEN 1024
43 #define LT_MAXPATHLEN 1024
44 
45 int __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
46 int dbg_current_mode = FOLLOW_NONE; /* for debug only */
47 unsigned line_key = COLLECTOR_TSD_INVALID_KEY;
48 line_mode_t line_mode = LM_DORMANT;
49 int user_follow_mode = FOLLOW_ON;
50 int java_mode = 0;
51 
52 static char *user_follow_spec;
53 static char new_lineage[LT_MAXNAMELEN];
54 static char curr_lineage[LT_MAXNAMELEN];
55 static char linetrace_exp_dir_name[LT_MAXPATHLEN + 1]; // experiment directory
56 
57 /* lineage tracking for descendants of this process */
58 
59 static int fork_linenum = 0;
60 static int line_initted = 0;
61 static collector_mutex_t fork_lineage_lock = COLLECTOR_MUTEX_INITIALIZER;
62 static collector_mutex_t clone_lineage_lock = COLLECTOR_MUTEX_INITIALIZER;
63 
64 /* interposition */
65 #define CALL_REAL(x)    (*(int(*)())__real_##x)
66 #define CALL_REALC(x)   (*(char*(*)())__real_##x)
67 #define CALL_REALF(x)   (*(FILE*(*)())__real_##x)
68 #define NULL_PTR(x)     ( __real_##x == NULL )
69 
70 // For a given Linux, which lib functions have more than one GLIBC version? Do this:
71 // objdump -T `find /lib /lib64 -name "*.so*"` | grep GLIBC | grep text | grep \(
72 static void *__real_fork = NULL;
73 static void *__real_vfork = NULL;
74 static void *__real_execve = NULL;
75 static void *__real_execvp = NULL;
76 static void *__real_execv = NULL;
77 static void *__real_execle = NULL;
78 static void *__real_execlp = NULL;
79 static void *__real_execl = NULL;
80 static void *__real_clone = NULL;
81 static void *__real_grantpt = NULL;
82 static void *__real_ptsname = NULL;
83 static void *__real_popen = NULL;
84 static int clone_linenum = 0;
85 #if ARCH(Intel)
86 #if WSIZE(32)
87 static void *__real_popen_2_1 = NULL;
88 static void *__real_popen_2_0 = NULL;
89 static void *__real_posix_spawn_2_15 = NULL;
90 static void *__real_posix_spawnp_2_15 = NULL;
91 static void *__real_posix_spawn_2_2 = NULL;
92 static void *__real_posix_spawnp_2_2 = NULL;
93 #elif WSIZE(64)
94 static void *__real_posix_spawn_2_15 = NULL;
95 static void *__real_posix_spawnp_2_15 = NULL;
96 static void *__real_posix_spawn_2_2_5 = NULL;
97 static void *__real_posix_spawnp_2_2_5 = NULL;
98 #endif /* WSIZE() */
99 #endif /* ARCH(Intel) */
100 static void *__real_system = NULL;
101 static void *__real_posix_spawn = NULL;
102 static void *__real_posix_spawnp = NULL;
103 static void *__real_setuid = NULL;
104 static void *__real_seteuid = NULL;
105 static void *__real_setreuid = NULL;
106 static void *__real_setgid = NULL;
107 static void *__real_setegid = NULL;
108 static void *__real_setregid = NULL;
109 static void linetrace_dormant ();
110 static int check_follow_fork ();
111 static int check_follow_exec (const char *execfile);
112 static int check_follow_combo (const char *execfile);
113 static int path_collectable (const char *execfile);
114 static char * build_experiment_path (char *instring, size_t instring_sz, const char *lineage_str);
115 static int init_lineage_intf ();
116 
117 /* -------  "Previously dbx-visible" function prototypes ----------------- */
118 static int linetrace_follow_experiment (const char *follow_spec, const char *lineage_str, const char *execfile);
119 static char *lineage_from_expname (char *lineage_str, size_t lstr_sz, const char *expname);
120 static void linetrace_ext_fork_prologue (const char *variant, char * new_lineage, int *following_fork);
121 static void linetrace_ext_fork_epilogue (const char *variant, const pid_t ret, char * new_lineage, int *following_fork);
122 static char **linetrace_ext_exec_prologue (const char *variant,
123 					   const char* path, char *const argv[], char *const envp[], int *following_exec);
124 static void linetrace_ext_exec_epilogue (const char *variant, char *const envp[], const int ret, int *following_exec);
125 static void linetrace_ext_combo_prologue (const char *variant, const char *cmd, int *following_combo);
126 static void linetrace_ext_combo_epilogue (const char *variant, const int ret, int *following_combo);
127 
128 #ifdef DEBUG
129 static int
get_combo_flag()130 get_combo_flag ()
131 {
132   int * guard = NULL;
133   int combo_flag = ((line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0);
134   return combo_flag;
135 }
136 #endif /* DEBUG */
137 
138 /* must be called for potentially live experiment */
139 int
__collector_ext_line_init(int * precord_this_experiment,const char * progspec,const char * progname)140 __collector_ext_line_init (int *precord_this_experiment,
141 			   const char * progspec, const char * progname)
142 {
143   *precord_this_experiment = 1;
144   TprintfT (DBG_LT0, "__collector_ext_line_init(%s)\n", progspec);
145   if (NULL_PTR (fork))
146     if (init_lineage_intf ())
147       {
148 	TprintfT (DBG_LT0, "__collector_ext_line_init() ERROR: initialization failed.\n");
149 	return COL_ERROR_LINEINIT;
150       }
151   /* check the follow spec */
152   user_follow_spec = CALL_UTIL (getenv)(SP_COLLECTOR_FOLLOW_SPEC);
153   if (user_follow_spec != NULL)
154     {
155       TprintfT (DBG_LT0, "collector: %s=%s\n", SP_COLLECTOR_FOLLOW_SPEC, user_follow_spec);
156       if (!linetrace_follow_experiment (user_follow_spec, curr_lineage, progname))
157 	{
158 	  *precord_this_experiment = 0;
159 	  TprintfT (DBG_LT0, "collector: -F =<regex> does not match, will NOT be followed\n");
160 	}
161       else
162 	TprintfT (DBG_LT0, "collector: -F =<regex> matches, will be followed\n");
163       user_follow_mode = FOLLOW_ALL;
164     }
165   __collector_env_save_preloads ();
166   TprintfT (DBG_LT0, "__collector_ext_line_init(), progname=%s, followspec=%s, followthis=%d\n",
167 	    progname, user_follow_spec ? user_follow_spec : "NULL",
168 	    *precord_this_experiment);
169   line_mode = LM_TRACK_LINEAGE; /* even if we don't follow, we report the interposition */
170   line_initted = 1;
171   return COL_ERROR_NONE;
172 }
173 
174 /*
175  * int __collector_ext_line_install(args)
176  * Check args to determine which line events to follow.
177  * Create tsd key for combo flag.
178  */
179 int
__collector_ext_line_install(char * args,const char * expname)180 __collector_ext_line_install (char *args, const char * expname)
181 {
182   if (!line_initted)
183     {
184       TprintfT (DBG_LT0, "__collector_ext_line_install(%s) ERROR: init hasn't be called yet\n", args);
185       return COL_ERROR_EXPOPEN;
186     }
187   TprintfT (DBG_LT0, "__collector_ext_line_install(%s, %s)\n", args, expname);
188   line_key = __collector_tsd_create_key (sizeof (int), NULL, NULL);
189 
190   /* determine experiment name */
191   __collector_strlcpy (linetrace_exp_dir_name, expname, sizeof (linetrace_exp_dir_name));
192   lineage_from_expname (curr_lineage, sizeof (curr_lineage), linetrace_exp_dir_name);
193   user_follow_mode = CALL_UTIL (atoi)(args);
194   TprintfT (DBG_LT0, "__collector_ext_line_install() user_follow_mode=0x%X, linetrace_exp_dir_name=%s\n",
195 	    user_follow_mode, linetrace_exp_dir_name);
196 
197   // determine java mode
198   char * java_follow_env = CALL_UTIL (getenv)(JAVA_TOOL_OPTIONS);
199   if (java_follow_env != NULL && CALL_UTIL (strstr)(java_follow_env, COLLECTOR_JVMTI_OPTION))
200     java_mode = 1;
201 
202   // backup collector specific env
203   if (sp_env_backup == NULL)
204     {
205       sp_env_backup = __collector_env_backup ();
206       TprintfT (DBG_LT0, "__collector_ext_line_install creating sp_env_backup -- 0x%p\n", sp_env_backup);
207     }
208   else
209     TprintfT (DBG_LT0, "__collector_ext_line_install existing sp_env_backup -- 0x%p\n", sp_env_backup);
210   if (user_follow_mode == FOLLOW_NONE)
211     __collector_env_unset (NULL);
212 
213   char logmsg[256];
214   logmsg[0] = '\0';
215   if (user_follow_mode != FOLLOW_NONE)
216     CALL_UTIL (strlcat)(logmsg, "fork|exec|combo", sizeof (logmsg));
217   size_t slen = __collector_strlen (logmsg);
218   if (slen > 0)
219     logmsg[slen] = '\0';
220   else
221     CALL_UTIL (strlcat)(logmsg, "none", sizeof (logmsg));
222 
223   /* report which line events are followed */
224   (void) __collector_log_write ("<setting %s=\"%s\"/>\n", SP_JCMD_LINETRACE, logmsg);
225   TprintfT (DBG_LT0, "__collector_ext_line_install(%s): %s \n", expname, logmsg);
226   return COL_ERROR_NONE;
227 }
228 
229 char *
lineage_from_expname(char * lineage_str,size_t lstr_sz,const char * expname)230 lineage_from_expname (char *lineage_str, size_t lstr_sz, const char *expname)
231 {
232   TprintfT (DBG_LT0, "lineage_from_expname(%s, %s)\n", lineage_str, expname);
233   char *p = NULL;
234   if (lstr_sz < 1 || !lineage_str || !expname)
235     {
236       TprintfT (DBG_LT0, "lineage_from_expname(): ERROR, null string\n");
237       return NULL;
238     }
239   /* determine lineage from experiment name */
240   p = __collector_strrchr (expname, '/');
241   if ((p == NULL) || (*++p != '_'))
242     {
243       lineage_str[0] = 0;
244       TprintfT (DBG_LT2, "lineage_from_expname(): expt=%s lineage=\".\" (founder)\n", expname);
245     }
246   else
247     {
248       size_t tmp = __collector_strlcpy (lineage_str, p, lstr_sz);
249       if (tmp >= lstr_sz)
250 	TprintfT (DBG_LT0, "lineage_from_expname(): ERROR: expt=%s lineage=\"%s\" truncated %ld characters\n",
251 		  expname, lineage_str, (long) (tmp - lstr_sz));
252       lineage_str[lstr_sz - 1] = 0;
253       p = __collector_strchr (lineage_str, '.');
254       if (p != NULL)
255 	*p = '\0';
256       TprintfT (DBG_LT2, "lineage_from_expname(): expt=%s lineage=\"%s\"\n", expname, lineage_str);
257     }
258   return lineage_str;
259 }
260 
261 /*
262  * void __collector_line_cleanup (void)
263  * Disable logging. Clear backup ENV.
264  */
265 void
__collector_line_cleanup(void)266 __collector_line_cleanup (void)
267 {
268   if (line_mode == LM_CLOSED)
269     {
270       TprintfT (DBG_LT0, "__collector_line_cleanup(): WARNING, line is already closed\n");
271       return;
272     }
273   else if (line_mode == LM_DORMANT)
274     TprintfT (DBG_LT0, "__collector_line_cleanup(): ERROR, line is DORMANT\n");
275   else
276     TprintfT (DBG_LT0, "__collector_line_cleanup()\n");
277   line_mode = LM_CLOSED;
278   user_follow_mode = FOLLOW_NONE;
279   dbg_current_mode = FOLLOW_NONE; /* for debug only */
280   line_key = COLLECTOR_TSD_INVALID_KEY;
281   java_mode = 0;
282   if (sp_env_backup != NULL)
283     {
284       __collector_env_backup_free ();
285       sp_env_backup = NULL;
286     }
287   return;
288 }
289 
290 /*
291  * void __collector_ext_line_close (void)
292  *	Disable logging.  Cleans ENV vars. Clear backup ENV.
293  */
294 void
__collector_ext_line_close(void)295 __collector_ext_line_close (void)
296 {
297   TprintfT (DBG_LT0, "__collector_ext_line_close()\n");
298   __collector_line_cleanup ();
299   __collector_env_unset (NULL);
300   return;
301 }
302 
303 /*
304  * void linetrace_dormant(void)
305  *	Disable logging.  Preserve ENV vars.
306  */
307 static void
linetrace_dormant(void)308 linetrace_dormant (void)
309 {
310   if (line_mode == LM_DORMANT)
311     {
312       TprintfT (DBG_LT0, "linetrace_dormant() -- already dormant\n");
313       return;
314     }
315   else if (line_mode == LM_CLOSED)
316     {
317       TprintfT (DBG_LT0, "linetrace_dormant(): ERROR, line is already CLOSED\n");
318       return;
319     }
320   else
321     TprintfT (DBG_LT0, "linetrace_dormant()\n");
322   line_mode = LM_DORMANT;
323   return;
324 }
325 
326 static int
check_follow_fork()327 check_follow_fork ()
328 {
329   int follow = (user_follow_mode != FOLLOW_NONE);
330   TprintfT (DBG_LT0, "check_follow_fork()=%d\n", follow);
331   return follow;
332 }
333 
334 static int
check_follow_exec(const char * execfile)335 check_follow_exec (const char *execfile)
336 {
337   int follow = (user_follow_mode != FOLLOW_NONE);
338   if (follow)
339     {
340       /* revise based on collectability of execfile */
341       follow = path_collectable (execfile);
342     }
343   TprintfT (DBG_LT0, "check_follow_exec(%s)=%d\n", execfile, follow);
344   return follow;
345 }
346 
347 static int
check_follow_combo(const char * execfile)348 check_follow_combo (const char *execfile)
349 {
350   int follow = (user_follow_mode != FOLLOW_NONE);
351   TprintfT (DBG_LT0, "check_follow_combo(%s)=%d\n", execfile, follow);
352   return follow;
353 }
354 
355 static int
check_fd_dynamic(int fd)356 check_fd_dynamic (int fd)
357 {
358   TprintfT (DBG_LT0, "check_fd_dynamic(%d)\n", fd);
359   off_t off = CALL_UTIL (lseek)(fd, (off_t) 0, SEEK_END);
360   size_t sz = (size_t) 8192; /* one page should suffice */
361   if (sz > off)
362     sz = off;
363   char *p = CALL_UTIL (mmap64)((char *) 0, sz, PROT_READ, MAP_PRIVATE, fd, (off64_t) 0);
364   if (p == MAP_FAILED)
365     {
366       TprintfT (DBG_LT0, "check_fd_dynamic(): ERROR/WARNING: mmap failed for `%d'\n", fd);
367       (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
368 				    COL_WARN_NOFOLLOW, "mmap-failed");
369       return 0;
370     }
371   char elfclass = p[EI_CLASS];
372   if ((p[EI_MAG0] != ELFMAG0) ||
373       (p[EI_MAG1] != ELFMAG1) ||
374       (p[EI_MAG2] != ELFMAG2) ||
375       (p[EI_MAG3] != ELFMAG3) ||
376       (elfclass != ELFCLASS32 && elfclass != ELFCLASS64)
377       )
378     {
379       TprintfT (DBG_LT0, "check_fd_dynamic(): WARNING: Command `%d' is not executable ELF!\n", fd);
380       CALL_UTIL (munmap)(p, sz);
381       return 1;
382     }
383   Elf32_Ehdr *ehdr32 = (Elf32_Ehdr*) p;
384   Elf64_Ehdr *ehdr64 = (Elf64_Ehdr*) p;
385   Elf64_Off e_phoff;
386   Elf64_Half e_phnum;
387   Elf64_Half e_phentsize;
388   if (elfclass == ELFCLASS32)
389     {
390       e_phoff = ehdr32->e_phoff;
391       e_phnum = ehdr32->e_phnum;
392       e_phentsize = ehdr32->e_phentsize;
393     }
394   else
395     {
396       e_phoff = ehdr64->e_phoff;
397       e_phnum = ehdr64->e_phnum;
398       e_phentsize = ehdr64->e_phentsize;
399     }
400   if ((sizeof (Elf32_Ehdr) > sz) ||
401       (sizeof (Elf64_Ehdr) > sz) ||
402       (e_phoff + e_phentsize * (e_phnum - 1) > sz))
403     {
404       TprintfT (DBG_LT0, "check_fd_dynamic(): WARNING: Command `%d' ELF file did not fit in page!\n", fd);
405 #if 0
406       (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
407 				    COL_WARN_RISKYFOLLOW, "ELF header size");
408 #endif
409       CALL_UTIL (munmap)(p, sz);
410       return 1;
411     }
412   TprintfT (DBG_LT2, "check_fd_dynamic(): elfclass=%d, e_phoff=%lu e_phnum=%lu e_phentsize=%lu\n",
413 	    (int) elfclass, (unsigned long) e_phoff, (unsigned long) e_phnum,
414 	    (unsigned long) e_phentsize);
415   int dynamic = 0;
416   Elf64_Half i;
417   for (i = 0; i < e_phnum; i++)
418     {
419       if (elfclass == ELFCLASS32)
420 	{
421 	  if (PT_DYNAMIC ==
422 	      ((Elf32_Phdr*) (p + e_phoff + e_phentsize * i))->p_type)
423 	    {
424 	      dynamic = 1;
425 	      break;
426 	    }
427 	}
428       else
429 	{
430 	  if (PT_DYNAMIC ==
431 	      ((Elf64_Phdr*) (p + e_phoff + e_phentsize * i))->p_type)
432 	    {
433 	      dynamic = 1;
434 	      break;
435 	    }
436 	}
437     }
438   if (!dynamic)
439     {
440       TprintfT (DBG_LT0, "check_fd_dynamic(): ERROR/WARNING: Command `%d' is not a dynamic executable!\n", fd);
441 #if 0
442       (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
443 				    COL_WARN_NOFOLLOW, "!dynamic");
444 #endif
445     }
446   else
447     TprintfT (DBG_LT2, "check_fd_dynamic(): Command `%d' is a dynamic executable!\n", fd);
448   CALL_UTIL (munmap)(p, sz);
449   return dynamic;
450 }
451 
452 static int
check_dynamic(const char * execfile)453 check_dynamic (const char *execfile)
454 {
455   TprintfT (DBG_LT2, "check_dynamic(%s)\n", execfile);
456   int fd = CALL_UTIL (open)(execfile, O_RDONLY);
457   if (fd == -1)
458     {
459       TprintfT (DBG_LT0, "check_dynamic(): ERROR/WARNING: Command `%s' could not be opened!\n", execfile);
460       (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
461 				    COL_WARN_RISKYFOLLOW, "open");
462       return 1; /* follow, though exec will presumably fail */
463     }
464   int ret = check_fd_dynamic (fd);
465   CALL_UTIL (close)(fd);
466   return ret;
467 }
468 
469 static int
path_collectable(const char * execfile)470 path_collectable (const char *execfile)
471 {
472   TprintfT (DBG_LT0, "path_collectable(%s)\n", execfile);
473   /* Check that execfile exists and is a collectable executable */
474   /* logging warning when collection is likely to be unsuccessful */
475   /* (if check isn't accurate, generally best not to include it) */
476 
477   if (execfile && !__collector_strchr (execfile, '/'))
478     { /* got an unqualified name */
479       /* XXXX locate execfile on PATH to be able to check it */
480       TprintfT (DBG_LT0, "path_collectable(): WARNING: Can't check unqualified executable `%s'\n", execfile);
481 #if 0
482       (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
483 				    COL_WARN_RISKYFOLLOW, "path");
484 #endif
485       return 1; /* follow unqualified execfile unchecked */
486     }
487   struct stat sbuf;
488   if (stat (execfile, &sbuf))
489     { /* can't stat it */
490       TprintfT (DBG_LT0, "path_collectable(): WARNING: Can't stat `%s'\n", execfile);
491 #if 0
492       (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
493 				    COL_WARN_RISKYFOLLOW, "stat");
494 #endif
495       return 1; /* follow, though exec will probably fail */
496     }
497   TprintfT (DBG_LT2, "path_collectable(%s) mode=0%o uid=%d gid=%d\n",
498 	    execfile, sbuf.st_mode, sbuf.st_uid, sbuf.st_gid);
499   if (((sbuf.st_mode & S_IXUSR) == 0) || ((sbuf.st_mode & S_IFMT) == S_IFDIR))
500     {
501       TprintfT (DBG_LT0, "path_collectable(): WARNING: Command `%s' is NOT an executable file!\n", execfile);
502 #if 0
503       (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
504 				    COL_WARN_RISKYFOLLOW, "mode");
505 #endif
506       return 1; /* follow, though exec will presumably fail */
507     }
508   /* XXXX setxid(root) is OK iff libcollector is registered as secure */
509   /* XXXX setxid(non-root) is OK iff umask is accomodating */
510   if (((sbuf.st_mode & S_ISUID) != 0) || ((sbuf.st_mode & S_ISGID) != 0))
511     {
512       TprintfT (DBG_LT0, "path_collectable(): WARNING: Command `%s' is SetXID!\n", execfile);
513 #if 0
514       (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
515 				    COL_WARN_RISKYFOLLOW, "setxid");
516 #endif
517       return 1; /* follow, though collection may be unreliable */
518     }
519   if (!check_dynamic (execfile))
520     {
521       TprintfT (DBG_LT0, "path_collectable(%s) WARNING/ERROR: not dynamic, not collectng!\n", execfile);
522       return 0; /* don't follow, collection will fail unpredictably */
523     }
524   TprintfT (DBG_LT2, "path_collectable(%s) OK!\n", execfile);
525   return 1; /* OK to follow */
526 }
527 
528 static char *
build_experiment_path(char * instring,size_t instring_sz,const char * lineage_str)529 build_experiment_path (char * instring, size_t instring_sz, const char *lineage_str)
530 {
531   TprintfT (DBG_LT0, "build_experiment_path(,%ld, %s)\n",
532 	    (long) instring_sz, lineage_str);
533   const char *p = CALL_UTIL (strstr)(linetrace_exp_dir_name, DESCENDANT_EXPT_KEY);
534   int basedir_sz;
535   if (p)
536     basedir_sz = p - linetrace_exp_dir_name + 4; /* +3 because of DESCENDANT_EXPT_KEY */
537   else
538     basedir_sz = __collector_strlen (linetrace_exp_dir_name) + 1;
539   int additional_sz = __collector_strlen (lineage_str) + 4;
540   if (basedir_sz + additional_sz > instring_sz)
541     {
542       TprintfT (DBG_LT0, "build_experiment_path(%s,%s): ERROR: path too long: %d > %ld\n",
543 		linetrace_exp_dir_name, lineage_str,
544 		basedir_sz + additional_sz, (long) instring_sz);
545       *instring = 0;
546       return NULL;
547     }
548   __collector_strlcpy (instring, linetrace_exp_dir_name, basedir_sz);
549   size_t slen = __collector_strlen (instring);
550   CALL_UTIL (snprintf)(instring + slen, instring_sz - slen, "/%s.er", lineage_str);
551   assert (__collector_strlen (instring) + 1 == basedir_sz + additional_sz);
552   return instring;
553 }
554 
555 static void
check_reuid_change(uid_t ruid,uid_t euid)556 check_reuid_change (uid_t ruid, uid_t euid)
557 {
558   uid_t curr_ruid = getuid ();
559   uid_t curr_euid = geteuid ();
560   mode_t curr_umask = umask (0);
561   umask (curr_umask); /* restore original umask */
562   int W_oth = !(curr_umask & S_IWOTH);
563   TprintfT (DBG_LT0, "check_reuid_change(%d,%d): umask=%03o\n", ruid, euid, curr_umask);
564   TprintfT (DBG_LT0, "check_reuid_change(): umask W usr=%d grp=%d oth=%d\n",
565 	    (int) (!(curr_umask & S_IWUSR)), (int) (!(curr_umask & S_IWGRP)), W_oth);
566   if (ruid != -1)
567     {
568       TprintfT (DBG_LT0, "check_reuid_change(%d->%d)\n", curr_ruid, ruid);
569       if ((curr_euid == 0) && (ruid != 0) && !W_oth)
570 	{
571 	  /* changing to non-root ID, with umask blocking writes by other */
572 	  TprintfT (DBG_LT0, "check_reuid_change(): ERROR/WARNING: umask blocks write other after ruid change (%d->%d)\n",
573 		    curr_ruid, ruid);
574 	  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o ruid %d->%d</event>\n",
575 					SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_ruid, ruid);
576 	}
577     }
578   if (euid != -1)
579     {
580       TprintfT (DBG_LT0, "check_reuid_change(%d->%d)\n", curr_euid, euid);
581       if ((curr_euid == 0) && (euid != 0) && !W_oth)
582 	{
583 	  /* changing to non-root ID, with umask blocking writes by other */
584 	  TprintfT (DBG_LT0, "check_reuid_change(): ERROR/WARNING: umask blocks write other after euid change (%d->%d)\n",
585 		    curr_euid, euid);
586 	  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o euid %d->%d</event>\n",
587 					SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_euid, euid);
588 	}
589     }
590 }
591 
592 static void
check_regid_change(gid_t rgid,gid_t egid)593 check_regid_change (gid_t rgid, gid_t egid)
594 {
595   gid_t curr_rgid = getgid ();
596   gid_t curr_egid = getegid ();
597   uid_t curr_euid = geteuid ();
598   mode_t curr_umask = umask (0);
599   umask (curr_umask); /* restore original umask */
600   int W_oth = !(curr_umask & S_IWOTH);
601   TprintfT (DBG_LT0, "check_regid_change(%d,%d): umask=%03o euid=%d\n",
602 	    rgid, egid, curr_umask, curr_euid);
603   TprintfT (DBG_LT0, "umask W usr=%d grp=%d oth=%d\n",
604 	    (int) (!(curr_umask & S_IWUSR)), (int) (!(curr_umask & S_IWGRP)), W_oth);
605   if (rgid != -1)
606     {
607       TprintfT (DBG_LT0, "check_regid_change(%d->%d)\n", curr_rgid, rgid);
608       if ((curr_euid == 0) && (rgid != 0) && !W_oth)
609 	{
610 	  /* changing to non-root ID, with umask blocking writes by other */
611 	  TprintfT (DBG_LT0, "check_regid_change(): WARNING/ERROR: umask blocks write other after rgid change (%d->%d)\n",
612 		    curr_rgid, rgid);
613 	  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o rgid %d->%d</event>\n",
614 					SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_rgid, rgid);
615 	}
616     }
617   if (egid != -1)
618     {
619       TprintfT (DBG_LT0, "check_regid_change(): check_egid_change(%d->%d)\n", curr_egid, egid);
620       if ((curr_euid == 0) && (egid != 0) && !W_oth)
621 	{
622 	  /* changing to non-root ID, with umask blocking writes by other */
623 	  TprintfT (DBG_LT0, "check_regid_change(): WARNING/ERROR: umask blocks write other after egid change (%d->%d)\n",
624 		    curr_egid, egid);
625 	  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o egid %d->%d</event>\n",
626 					SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_egid, egid);
627 	}
628     }
629 }
630 
631 static int
init_lineage_intf()632 init_lineage_intf ()
633 {
634   void *dlflag;
635   TprintfT (DBG_LT2, "init_lineage_intf()\n");
636 
637   static int nesting_check = 0;
638   if (nesting_check >= 2)
639     {
640       /* segv before stack blows up */
641       nesting_check /= (nesting_check - 2);
642     }
643   nesting_check++;
644 
645   __real_fork = dlsym (RTLD_NEXT, "fork");
646   if (__real_fork == NULL)
647     {
648       __real_fork = dlsym (RTLD_DEFAULT, "fork");
649       if (__real_fork == NULL)
650 	return 1;
651       dlflag = RTLD_DEFAULT;
652     }
653   else
654     dlflag = RTLD_NEXT;
655   TprintfT (DBG_LT2, "init_lineage_intf() using RTLD_%s\n",
656 	    dlflag == RTLD_DEFAULT ? "DEFAULT" : "NEXT");
657   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_fork\n", __real_fork);
658   __real_vfork = dlsym (dlflag, "vfork");
659   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_vfork\n", __real_vfork);
660   __real_execve = dlsym (dlflag, "execve");
661   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execve\n", __real_execve);
662   __real_execvp = dlsym (dlflag, "execvp");
663   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execvp\n", __real_execvp);
664   __real_execv = dlsym (dlflag, "execv");
665   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execv\n", __real_execv);
666   __real_execle = dlsym (dlflag, "execle");
667   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execle\n", __real_execle);
668   __real_execlp = dlsym (dlflag, "execlp");
669   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execlp\n", __real_execlp);
670   __real_execl = dlsym (dlflag, "execl");
671   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execl\n", __real_execl);
672   __real_clone = dlsym (dlflag, "clone");
673   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_clone\n", __real_clone);
674   __real_posix_spawn = dlsym (dlflag, "posix_spawn");
675   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_posix_spawn\n",
676 	    __real_posix_spawn);
677   __real_posix_spawnp = dlsym (dlflag, "posix_spawnp");
678   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_posix_spawnp\n",
679 	    __real_posix_spawnp);
680   __real_popen = dlvsym (dlflag, "popen", SYS_POPEN_VERSION);
681   TprintfT (DBG_LT2, "init_lineage_intf()[%s] @0x%p __real_popen\n",
682 	    SYS_POPEN_VERSION, __real_popen);
683 #if ARCH(Intel)
684   __real_posix_spawn_2_15 = dlvsym (dlflag, "posix_spawn", SYS_POSIX_SPAWN_VERSION);
685   __real_posix_spawnp_2_15 = dlvsym (dlflag, "posix_spawnp", SYS_POSIX_SPAWN_VERSION);
686 #if WSIZE(32)
687   __real_popen_2_1 = __real_popen;
688   __real_popen_2_0 = dlvsym (dlflag, "popen", "GLIBC_2.0");
689   __real_posix_spawn_2_2 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.2");
690   __real_posix_spawnp_2_2 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.2");
691 #elif WSIZE(64)
692   __real_posix_spawn_2_2_5 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.2.5");
693   __real_posix_spawnp_2_2_5 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.2.5");
694 #endif /* WSIZE() */
695 #endif /* ARCH(Intel) */
696   __real_grantpt = dlsym (dlflag, "grantpt");
697   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_grantpt\n", __real_grantpt);
698   __real_ptsname = dlsym (dlflag, "ptsname");
699   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_ptsname\n", __real_ptsname);
700   __real_system = dlsym (dlflag, "system");
701   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_system\n", __real_system);
702   __real_setuid = dlsym (dlflag, "setuid");
703   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setuid\n", __real_setuid);
704   __real_seteuid = dlsym (dlflag, "seteuid");
705   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_seteuid\n", __real_seteuid);
706   __real_setreuid = dlsym (dlflag, "setreuid");
707   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setreuid\n", __real_setreuid);
708   __real_setgid = dlsym (dlflag, "setgid");
709   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setgid\n", __real_setgid);
710   __real_setegid = dlsym (dlflag, "setegid");
711   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setegid\n", __real_setegid);
712   __real_setregid = dlsym (dlflag, "setregid");
713   TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setregid\n", __real_setregid);
714   return 0;
715 }
716 
717 /*------------------------------------------------------------------------ */
718 /* Note: The following _prologue and _epilogue functions used to be dbx-visible.
719 
720    They are used to appropriately manage lineage-changing events, by
721    quiescing and re-enabling/re-setting experiment collection before and after,
722    and logging the lineage-change in the process/experiment undertaking it.
723    As shown by the interposition functions for fork, exec, etc., which follow,
724    the _prologue should be called immediately prior (such as a breakpoint
725    action defined at function entry) and the _epilogue called immediately
726    after (such as a breakpoint action defined at function return).
727  */
728 
729 /*
730    Notes on MT from Solaris 10 man pthread_atfork:
731 
732      All multithreaded applications that call fork() in  a  POSIX
733      threads  program and do more than simply call exec(2) in the
734      child of the fork need to ensure that the child is protected
735      from deadlock.
736 
737      Since the "fork-one" model results in duplicating  only  the
738      thread  that  called fork(), it is possible that at the time
739      of the call another thread in the parent owns a  lock.  This
740      thread  is  not  duplicated  in the child, so no thread will
741      unlock this lock in the child.  Deadlock occurs if the  sin-
742      gle thread in the child needs this lock.
743 
744      The problem is more serious with locks in libraries.   Since
745      a  library writer does not know if the application using the
746      library calls fork(), the library must protect  itself  from
747      such  a  deadlock  scenario.   If the application that links
748      with this library calls fork() and does not call  exec()  in
749      the  child,  and if it needs a library lock that may be held
750      by some other thread  in  the  parent  that  is  inside  the
751      library  at  the time of the fork, the application deadlocks
752      inside the library.
753  */
754 
755 static void
linetrace_ext_fork_prologue(const char * variant,char * n_lineage,int * following_fork)756 linetrace_ext_fork_prologue (const char *variant, char * n_lineage, int *following_fork)
757 {
758   TprintfT (DBG_LT0, "linetrace_ext_fork_prologue; variant=%s; new_lineage=%s; follow=%d\n",
759 	    variant, n_lineage, *following_fork);
760   __collector_env_print ("fork_prologue start");
761   if (dbg_current_mode != FOLLOW_NONE)
762     TprintfT (DBG_LT0, "linetrace_ext_fork_prologue(%s) ERROR: dbg_current_mode=%d, changing to FOLLOW_FORK!\n",
763 		variant, dbg_current_mode);
764   dbg_current_mode = FOLLOW_ON;
765   if (__collector_strncmp ((char *) variant, "clone", sizeof ("clone") - 1) == 0)
766     {
767       __collector_mutex_lock (&clone_lineage_lock);
768       CALL_UTIL (snprintf)(n_lineage, LT_MAXNAMELEN, "%s_C%d", curr_lineage, ++clone_linenum);
769       __collector_mutex_unlock (&clone_lineage_lock);
770     }
771   else
772     {
773       __collector_mutex_lock (&fork_lineage_lock);
774       CALL_UTIL (snprintf)(n_lineage, LT_MAXNAMELEN, "%s_f%d", curr_lineage, ++fork_linenum);
775       __collector_mutex_unlock (&fork_lineage_lock);
776     }
777   *following_fork = check_follow_fork ();
778 
779   /* write message before suspending, or it won't be written */
780   hrtime_t ts = GETRELTIME ();
781   TprintfT (DBG_LT0, "linetrace_ext_fork_prologue; variant=%s; new_lineage=%s; follow=%d\n",
782 	    variant, n_lineage, *following_fork);
783   __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\"/>\n",
784 			 SP_JCMD_DESC_START,
785 			 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
786 			 variant, n_lineage, *following_fork);
787   __collector_ext_dispatcher_thread_timer_suspend ();
788   __collector_ext_hwc_lwp_suspend ();
789   __collector_env_print ("fork_prologue end");
790 }
791 
792 static void
linetrace_ext_fork_epilogue(const char * variant,const pid_t ret,char * n_lineage,int * following_fork)793 linetrace_ext_fork_epilogue (const char *variant, const pid_t ret, char * n_lineage, int *following_fork)
794 {
795   if (dbg_current_mode == FOLLOW_NONE)
796     TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) ERROR: dbg_current_mode=%d!\n",
797 	      variant, dbg_current_mode);
798   /* compute descendant experiment name */
799   char new_exp_name[LT_MAXPATHLEN];
800   /* save exp_name to global var */
801   if (!build_experiment_path (new_exp_name, sizeof (new_exp_name), n_lineage))
802     TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s): ERROR SP_COLLECTOR_EXPNAME not set\n", n_lineage);
803   TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s):%d() returned %d %s; child experiment name = %s\n",
804 	    variant, *following_fork, ret, (ret ? "parent" : "child"), new_exp_name);
805   if (ret == 0)
806     {
807       /* *************************************child */
808       __collector_env_print ("fork_epilogue child at start");
809       /* start a new line */
810       fork_linenum = 0;
811       __collector_mutex_init (&fork_lineage_lock);
812       clone_linenum = 0;
813       __collector_mutex_init (&clone_lineage_lock);
814       __collector_env_update (NULL);
815       __collector_env_print ("fork_epilogue child after env_update");
816       __collector_clean_state ();
817       __collector_env_print ("fork_epilogue child after clean_slate");
818       __collector_line_cleanup ();
819       __collector_env_print ("fork_epilogue child after line_cleanup");
820       if (*following_fork)
821 	{
822 	  /* stop recording this experiment, but preserve env vars */
823 	  linetrace_dormant ();
824 	  __collector_env_print ("fork_epilogue child after linetrace_dormant");
825 
826 	  //static char exp_name_env[LT_MAXPATHLEN];
827 	  char * exp_name_env = CALL_UTIL (calloc)(LT_MAXPATHLEN, 1);
828 	  CALL_UTIL (snprintf)(exp_name_env, LT_MAXPATHLEN, "%s=%s", SP_COLLECTOR_EXPNAME, new_exp_name);
829 	  CALL_UTIL (putenv)(exp_name_env);
830 
831 	  const char *params = CALL_UTIL (getenv)(SP_COLLECTOR_PARAMS);
832 	  int ret;
833 	  if (new_exp_name == NULL)
834 	    TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: getenv(%s) undefined -- new expt aborted!\n",
835 		      SP_COLLECTOR_EXPNAME);
836 	  else if (params == NULL)
837 	    TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: getenv(%s) undefined -- new expt aborted!\n",
838 		      SP_COLLECTOR_PARAMS);
839 	  else if ((ret = __collector_open_experiment (new_exp_name, params, SP_ORIGIN_FORK)))
840 	    TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: '%s' open failed, ret=%d\n",
841 		      new_exp_name, ret);
842 	  else
843 	    TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: opened(%s)\n", new_exp_name);
844 	  TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) returning to *child*\n", variant);
845 	}
846       else
847 	{
848 	  /* disable current and further linetrace experiment resumption */
849 	  TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) child calling line_close\n", variant);
850 	  __collector_ext_line_close ();
851 	}
852       __collector_env_print ("fork_epilogue child at end");
853       /* *************************************end child */
854     }
855   else
856     {
857       /* *************************************parent */
858       __collector_env_print ("fork_epilogue parent at start");
859       __collector_ext_dispatcher_thread_timer_resume ();
860       __collector_ext_hwc_lwp_resume ();
861       hrtime_t ts = GETRELTIME ();
862       char msg[256 + LT_MAXPATHLEN];
863       if (ret >= 0)
864 	CALL_UTIL (snprintf)(msg, sizeof (msg), "pid=%d", ret);
865       else
866 	{
867 	  /* delete stillborn experiment? */
868 	  char errmsg[256];
869 	  strerror_r (errno, errmsg, sizeof (errmsg));
870 	  CALL_UTIL (snprintf)(msg, sizeof (msg), "err %s", errmsg);
871 	}
872       __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
873 			     SP_JCMD_DESC_STARTED,
874 			     (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
875 			     variant, n_lineage, *following_fork, msg);
876       /* environment remains set for collection */
877       __collector_env_print ("fork_epilogue parent at end");
878       /* *************************************end parent */
879     }
880   dbg_current_mode = FOLLOW_NONE;
881   *following_fork = 0;
882 }
883 
884 static char**
linetrace_ext_exec_prologue_end(const char * variant,const char * cmd_string,char * const envp[],int following_exec)885 linetrace_ext_exec_prologue_end (const char *variant, const char* cmd_string,
886 				 char *const envp[], int following_exec)
887 {
888   char **coll_env;
889   TprintfT (DBG_LT0, "linetrace_ext_exec_prologue_end; variant=%s; cmd_string=%s; follow=%d\n",
890 	    variant, cmd_string, following_exec);
891   /* write message before suspending, or it won't be written */
892   hrtime_t ts = GETRELTIME ();
893   __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
894 			 SP_JCMD_EXEC_START,
895 			 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
896 			 variant, new_lineage, following_exec, cmd_string);
897   if (following_exec)
898     {
899       coll_env = __collector_env_allocate (envp, 0);
900       __collector_env_update (coll_env);
901       extern char **environ; /* the process' actual environment */
902       if (environ == envp)   /* user selected process environment */
903 	environ = coll_env;
904     }
905   else
906     coll_env = (char**) envp;
907   __collector_env_printall ("linetrace_ext_exec_prologue_end", coll_env);
908   if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
909     {
910       __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
911       __collector_suspend_experiment ("suspend_for_exec");
912       __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
913     }
914   if (CALL_UTIL (strstr)(variant, "posix_spawn"))
915     {
916       __collector_ext_dispatcher_thread_timer_suspend ();
917       __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
918       __collector_ext_hwc_lwp_suspend ();
919       __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
920     }
921   return (coll_env);
922 }
923 
924 static char**
linetrace_ext_exec_prologue(const char * variant,const char * path,char * const argv[],char * const envp[],int * following_exec)925 linetrace_ext_exec_prologue (const char *variant,
926 			     const char* path, char *const argv[],
927 			     char *const envp[], int *following_exec)
928 {
929   char cmd_string[_POSIX_ARG_MAX] = {'\0'};
930 
931   if (dbg_current_mode != FOLLOW_NONE)
932     TprintfT (DBG_LT0, "linetrace_ext_exec_prologue() ERROR: dbg_current_mode=%d, changing to FOLLOW_EXEC!\n", dbg_current_mode);
933   dbg_current_mode = FOLLOW_ON;
934   *following_exec = check_follow_exec (path);
935   if (path != NULL)
936     {
937       /* escape any newline, " or \ characters in the exec command */
938       TprintfT (DBG_LT3, "linetrace_ext_exec_prologue(): arg0=%s\n", path);
939       /* leave space in log message for terminator (and header) */
940       __collector_strlcpy (cmd_string, path, sizeof (cmd_string));
941       size_t len;
942       unsigned argn = 0;
943       if (argv[0])
944 	{
945 	  char *p;
946 	  while (((p = argv[++argn]) != 0) &&
947 		 (len = __collector_strlen (cmd_string)) < sizeof (cmd_string) - 2)
948 	    {
949 	      cmd_string[len++] = ' ';
950 	      __collector_strlcpy (cmd_string + len, p, sizeof (cmd_string) - len);
951 	    }
952 	}
953     }
954   TprintfT (DBG_LT0, "linetrace_ext_exec_prologue(%s), lineage=%s, follow=%d, prog=%s, path=%s \n",
955 	    variant, new_lineage, *following_exec, cmd_string, path);
956   return linetrace_ext_exec_prologue_end (variant, cmd_string, envp, *following_exec);
957 }
958 
959 static void
linetrace_ext_exec_epilogue(const char * variant,char * const envp[],const int ret,int * following_exec)960 linetrace_ext_exec_epilogue (const char *variant, char *const envp[], const int ret, int *following_exec)
961 {
962   /* For exec, this routine is only entered if the exec failed */
963   /* However, posix_spawn() is expected to return */
964   if (dbg_current_mode == FOLLOW_NONE)
965     TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue() ERROR: dbg_current_mode=%d!\n", dbg_current_mode);
966   TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue(%s):%d returned: %d, errno=%d\n",
967 	    variant, *following_exec, ret, errno);
968   if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
969     {
970       __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
971       __collector_resume_experiment ();
972       __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
973     }
974   if (CALL_UTIL (strstr)(variant, "posix_spawn"))
975     {
976       __collector_ext_dispatcher_thread_timer_resume ();
977       __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
978       __collector_ext_hwc_lwp_resume ();
979       __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
980     }
981   hrtime_t ts = GETRELTIME ();
982   char msg[256];
983   if (ret)
984     {
985       char errmsg[256];
986       strerror_r (errno, errmsg, sizeof (errmsg));
987       CALL_UTIL (snprintf)(msg, sizeof (msg), "err %s", errmsg);
988     }
989   else
990     CALL_UTIL (snprintf)(msg, sizeof (msg), "rc=%d", ret);
991   if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
992     __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
993 			   SP_JCMD_EXEC_ERROR,
994 			   (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
995 			   variant, new_lineage, *following_exec, msg);
996   if (envp == NULL)
997     TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue() ERROR: envp NULL after %s!\n", variant);
998   dbg_current_mode = FOLLOW_NONE;
999   *following_exec = 0;
1000 }
1001 
1002 static void
linetrace_ext_combo_prologue(const char * variant,const char * cmd,int * following_combo)1003 linetrace_ext_combo_prologue (const char *variant, const char *cmd, int *following_combo)
1004 {
1005   char cmd_string[_POSIX_ARG_MAX] = {'\0'};
1006   char execfile[_POSIX_ARG_MAX] = {'\0'};
1007 
1008   if (dbg_current_mode != FOLLOW_NONE)
1009     TprintfT (DBG_LT0, "linetrace_ext_combo_prologue() ERROR: dbg_current_mode=%d!  changing to FOLLOW_ON\n",
1010 	      dbg_current_mode);
1011   dbg_current_mode = FOLLOW_ON;
1012   if (cmd != NULL)
1013     {
1014       /* extract executable name from combo command */
1015       unsigned len = strcspn (cmd, " ");
1016       __collector_strlcpy (execfile, cmd, len + 1);
1017 
1018       /* escape any newline, " or \ characters in the combo command */
1019       /* leave space in log message for terminator (and header) */
1020       __collector_strlcpy (cmd_string, cmd, sizeof (cmd_string));
1021     }
1022 
1023   *following_combo = check_follow_combo (execfile);
1024   TprintfT (DBG_LT0, "linetrace_ext_combo_prologue(%s) follow=%d, prog=%s\n\n",
1025 	    variant, *following_combo, cmd_string);
1026 
1027   /* Construct the lineage string for the new image */
1028   new_lineage[0] = 0;
1029   __collector_strcat (new_lineage, "XXX");
1030 
1031   /* write message before suspending, or it won't be written */
1032   hrtime_t ts = GETRELTIME ();
1033   __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
1034 			 SP_JCMD_DESC_START,
1035 			 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
1036 			 variant, new_lineage, *following_combo, cmd_string);
1037   if (*following_combo)
1038     {
1039       __collector_env_update (NULL);
1040       TprintfT (DBG_LT0, "linetrace_ext_combo_prologue(): Following %s(\"%s\")\n", variant, execfile);
1041     }
1042   __collector_ext_dispatcher_thread_timer_suspend ();
1043   __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
1044   __collector_ext_hwc_lwp_suspend ();
1045   __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
1046 }
1047 
1048 static void
linetrace_ext_combo_epilogue(const char * variant,const int ret,int * following_combo)1049 linetrace_ext_combo_epilogue (const char *variant, const int ret, int *following_combo)
1050 {
1051   if (dbg_current_mode == FOLLOW_NONE)
1052     TprintfT (DBG_LT0, "linetrace_ext_combo_epilogue() ERROR: dbg_current_mode=FOLLOW_NONE\n");
1053   TprintfT (DBG_LT0, "linetrace_ext_combo_epilogue(%s):%d() returned %d\n",
1054 	    variant, *following_combo, ret);
1055   __collector_ext_dispatcher_thread_timer_resume ();
1056   __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
1057   __collector_ext_hwc_lwp_resume ();
1058   __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
1059   hrtime_t ts = GETRELTIME ();
1060   __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" follow=\"%d\" msg=\"rc=%d\"/>\n",
1061 			 SP_JCMD_DESC_STARTED,
1062 			 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
1063 			 variant, *following_combo, ret);
1064 
1065   dbg_current_mode = FOLLOW_NONE;
1066   *following_combo = 0;
1067 }
1068 
1069 /*------------------------------------------------------------- fork */
1070 pid_t fork () __attribute__ ((weak, alias ("__collector_fork")));
1071 pid_t _fork () __attribute__ ((weak, alias ("__collector_fork")));
1072 
1073 pid_t
__collector_fork(void)1074 __collector_fork (void)
1075 {
1076   pid_t ret;
1077   if (NULL_PTR (fork))
1078     {
1079       TprintfT (DBG_LT0, "__collector_fork() calling init_lineage_intf()\n");
1080       init_lineage_intf ();
1081     }
1082   __collector_env_print ("__collector_fork start");
1083   int * guard = NULL;
1084   int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1085   TprintfT (DBG_LT0, "__collector_fork() interposition: line_mode=%d combo=%d\n",
1086 	    line_mode, combo_flag);
1087   if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
1088     {
1089       TprintfT (DBG_LT0, "__collector_fork() not following, returning CALL_REAL(fork)()\n");
1090       return CALL_REAL (fork)();
1091     }
1092   int following_fork = 0;
1093   linetrace_ext_fork_prologue ("fork", new_lineage, &following_fork);
1094 
1095   /* since libpthread/fork ends up calling fork1, it's a combo */
1096   PUSH_REENTRANCE (guard);
1097   ret = CALL_REAL (fork)();
1098   POP_REENTRANCE (guard);
1099   linetrace_ext_fork_epilogue ("fork", ret, new_lineage, &following_fork);
1100   return ret;
1101 }
1102 
1103 /*------------------------------------------------------------- vfork */
1104 /* vfork interposition in the usual sense is not possible, since vfork(2)
1105    relies on specifics of the stack frames in the parent and child which
1106    only work when the child's exec (or _exit) are in the same stack frame
1107    as the vfork: this isn't the case when there's interposition on exec.
1108    As a workaround, the interposing vfork calls fork1 instead of the real
1109    vfork.  Note that fork1 is somewhat less efficient than vfork, and requires
1110    additional memory, which may result in a change of application behaviour
1111    when libcollector is loaded (even when collection is not active),
1112    affecting not only direct use of vfork by the subject application,
1113    but also indirect use through system, popen, and the other combos.
1114  */
1115 pid_t vfork () __attribute__ ((weak, alias ("__collector_vfork")));
1116 pid_t _vfork () __attribute__ ((weak, alias ("__collector_vfork")));
1117 
1118 pid_t
__collector_vfork(void)1119 __collector_vfork (void)
1120 {
1121   if (NULL_PTR (vfork))
1122     init_lineage_intf ();
1123 
1124   int * guard = NULL;
1125   int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1126 
1127   TprintfT (DBG_LT0, "__collector_vfork() interposing: line_mode=%d combo=%d\n",
1128 	    line_mode, combo_flag);
1129   if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
1130     return CALL_REAL (fork)();
1131 
1132   /* this warning is also appropriate for combos which use vfork,
1133      however, let's assume this is achieved elsewhere */
1134   (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
1135 				COL_WARN_VFORK, "fork");
1136 
1137   char new_lineage[LT_MAXNAMELEN];
1138   new_lineage[0] = 0;
1139   int following_fork = 0;
1140   linetrace_ext_fork_prologue ("vfork", new_lineage, &following_fork);
1141 
1142   pid_t ret = CALL_REAL (fork)();
1143   linetrace_ext_fork_epilogue ("vfork", ret, new_lineage, &following_fork);
1144   return ret;
1145 }
1146 
1147 /*------------------------------------------------------------- execve */
1148 int execve () __attribute__ ((weak, alias ("__collector_execve")));
1149 
1150 int
__collector_execve(const char * path,char * const argv[],char * const envp[])1151 __collector_execve (const char* path, char *const argv[], char *const envp[])
1152 {
1153   static char **coll_env = NULL; /* environment for collection */
1154   if (NULL_PTR (execve))
1155     init_lineage_intf ();
1156   int * guard = NULL;
1157   int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1158   TprintfT (DBG_LT0,
1159 	    "__collector_execve(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n",
1160 	    path ? path : "NULL",
1161 	    argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
1162 	    envp ? (envp[0] ? envp[0] : "NULL") : "NULL",
1163 	    line_mode, combo_flag);
1164   if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
1165     __collector_env_unset ((char**) envp);
1166   if (line_mode != LM_TRACK_LINEAGE || combo_flag)
1167     return CALL_REAL (execve)(path, argv, envp);
1168 
1169   int following_exec = 0;
1170   coll_env = linetrace_ext_exec_prologue ("execve", path, argv, envp, &following_exec);
1171   TprintfT (DBG_LT2, "__collector_execve(): coll_env=0x%p\n", coll_env);
1172   __collector_env_printall ("__collector_execve", coll_env);
1173   int ret = CALL_REAL (execve)(path, argv, coll_env);
1174   linetrace_ext_exec_epilogue ("execve", envp, ret, &following_exec);
1175   return ret;
1176 }
1177 
1178 int execvp () __attribute__ ((weak, alias ("__collector_execvp")));
1179 
1180 int
__collector_execvp(const char * file,char * const argv[])1181 __collector_execvp (const char* file, char *const argv[])
1182 {
1183   extern char **environ; /* the process' actual environment */
1184   char ** envp = environ;
1185   if (NULL_PTR (execvp))
1186     init_lineage_intf ();
1187   int * guard = NULL;
1188   int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1189   TprintfT (DBG_LT0,
1190 	    "__collector_execvp(file=%s, argv[0]=%s) interposing: line_mode=%d combo=%d\n",
1191 	    file ? file : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
1192 	    line_mode, combo_flag);
1193   if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
1194     __collector_env_unset ((char**) envp);
1195   if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
1196     return CALL_REAL (execvp)(file, argv);
1197 
1198   int following_exec = 0;
1199 #ifdef DEBUG
1200   char **coll_env = /* environment for collection */
1201 #endif /* DEBUG */
1202 	  linetrace_ext_exec_prologue ("execvp", file, argv, envp, &following_exec);
1203   TprintfT (DBG_LT0, "__collector_execvp(): coll_env=0x%p\n", coll_env);
1204 
1205   int ret = CALL_REAL (execvp)(file, argv);
1206   linetrace_ext_exec_epilogue ("execvp", envp, ret, &following_exec);
1207   return ret;
1208 }
1209 
1210 int execv () __attribute__ ((weak, alias ("__collector_execv")));
1211 
1212 int
__collector_execv(const char * path,char * const argv[])1213 __collector_execv (const char* path, char *const argv[])
1214 {
1215   int ret;
1216   extern char **environ; /* the process' actual environment */
1217   char ** envp = environ;
1218   TprintfT (DBG_LT0, "__collector_execv(path=%s, argv[0]=%s) interposing: line_mode=%d combo=%d\n",
1219 	    path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
1220 	    line_mode, get_combo_flag ());
1221 
1222   ret = __collector_execve (path, argv, envp);
1223   return ret;
1224 }
1225 
1226 int execle (const char* path, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execle")));
1227 
1228 int
__collector_execle(const char * path,const char * arg0,...)1229 __collector_execle (const char* path, const char *arg0, ...)
1230 {
1231   TprintfT (DBG_LT0,
1232 	    "__collector_execle(path=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
1233 	    path ? path : "NULL", arg0 ? arg0 : "NULL",
1234 	    line_mode, get_combo_flag ());
1235 
1236   char **argp;
1237   va_list args;
1238   char **argvec;
1239   register char **environmentp;
1240   int nargs = 0;
1241   char *nextarg;
1242 
1243   va_start (args, arg0);
1244   while (va_arg (args, char *) != (char *) 0)
1245     nargs++;
1246 
1247   /*
1248    * save the environment pointer, which is at the end of the
1249    * variable argument list
1250    */
1251   environmentp = va_arg (args, char **);
1252   va_end (args);
1253 
1254   /*
1255    * load the arguments in the variable argument list
1256    * into the argument vector, and add the terminating null pointer
1257    */
1258   va_start (args, arg0);
1259   /* workaround for bugid 1242839 */
1260   argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
1261   argp = argvec;
1262   *argp++ = (char *) arg0;
1263   while ((nextarg = va_arg (args, char *)) != (char *) 0)
1264     *argp++ = nextarg;
1265   va_end (args);
1266   *argp = (char *) 0;
1267   return __collector_execve (path, argvec, environmentp);
1268 }
1269 
1270 int execlp (const char* file, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execlp")));
1271 
1272 int
__collector_execlp(const char * file,const char * arg0,...)1273 __collector_execlp (const char* file, const char *arg0, ...)
1274 {
1275   TprintfT (DBG_LT0,
1276 	    "__collector_execlp(file=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
1277 	    file ? file : "NULL", arg0 ? arg0 : "NULL",
1278 	    line_mode, get_combo_flag ());
1279   char **argp;
1280   va_list args;
1281   char **argvec;
1282   int nargs = 0;
1283   char *nextarg;
1284 
1285   va_start (args, arg0);
1286   while (va_arg (args, char *) != (char *) 0)
1287     nargs++;
1288   va_end (args);
1289 
1290   /*
1291    * load the arguments in the variable argument list
1292    * into the argument vector and add the terminating null pointer
1293    */
1294   va_start (args, arg0);
1295 
1296   /* workaround for bugid 1242839 */
1297   argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
1298   argp = argvec;
1299   *argp++ = (char *) arg0;
1300   while ((nextarg = va_arg (args, char *)) != (char *) 0)
1301     *argp++ = nextarg;
1302   va_end (args);
1303   *argp = (char *) 0;
1304   return __collector_execvp (file, argvec);
1305 }
1306 
1307 int execl (const char* path, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execl")));
1308 
1309 int
__collector_execl(const char * path,const char * arg0,...)1310 __collector_execl (const char* path, const char *arg0, ...)
1311 {
1312   TprintfT (DBG_LT0,
1313 	    "__collector_execl(path=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
1314 	    path ? path : "NULL", arg0 ? arg0 : "NULL",
1315 	    line_mode, get_combo_flag ());
1316   char **argp;
1317   va_list args;
1318   char **argvec;
1319   extern char **environ;
1320   int nargs = 0;
1321   char *nextarg;
1322   va_start (args, arg0);
1323   while (va_arg (args, char *) != (char *) 0)
1324     nargs++;
1325   va_end (args);
1326 
1327   /*
1328    * load the arguments in the variable argument list
1329    * into the argument vector and add the terminating null pointer
1330    */
1331   va_start (args, arg0);
1332 
1333   /* workaround for bugid 1242839 */
1334   argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
1335   argp = argvec;
1336   *argp++ = (char *) arg0;
1337   while ((nextarg = va_arg (args, char *)) != (char *) 0)
1338     *argp++ = nextarg;
1339   va_end (args);
1340   *argp = (char *) 0;
1341   return __collector_execve (path, argvec, environ);
1342 }
1343 
1344 #include <spawn.h>
1345 
1346 /*-------------------------------------------------------- posix_spawn */
1347 #if ARCH(Intel)
1348 // map interposed symbol versions
1349 static int
1350 __collector_posix_spawn_symver (int(real_posix_spawn) (),
1351 				pid_t *pidp, const char *path,
1352 				const posix_spawn_file_actions_t *file_actions,
1353 				const posix_spawnattr_t *attrp,
1354 				char *const argv[], char *const envp[]);
1355 
1356 SYMVER_ATTRIBUTE (__collector_posix_spawn_2_15, posix_spawn@@GLIBC_2.15)
1357 int
__collector_posix_spawn_2_15(pid_t * pidp,const char * path,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])1358 __collector_posix_spawn_2_15 (pid_t *pidp, const char *path,
1359 			      const posix_spawn_file_actions_t *file_actions,
1360 			      const posix_spawnattr_t *attrp,
1361 			      char *const argv[], char *const envp[])
1362 {
1363   TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawn_2_15@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
1364 	    CALL_REAL (posix_spawn_2_15), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
1365   if (NULL_PTR (posix_spawn))
1366     init_lineage_intf ();
1367   return __collector_posix_spawn_symver (CALL_REAL (posix_spawn_2_15), pidp,
1368 					 path, file_actions, attrp, argv, envp);
1369 }
1370 
1371 #if WSIZE(32)
1372 SYMVER_ATTRIBUTE (__collector_posix_spawn_2_2, posix_spawn@GLIBC_2.2)
1373 int
__collector_posix_spawn_2_2(pid_t * pidp,const char * path,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])1374 __collector_posix_spawn_2_2 (pid_t *pidp, const char *path,
1375 			     const posix_spawn_file_actions_t *file_actions,
1376 			     const posix_spawnattr_t *attrp,
1377 			     char *const argv[], char *const envp[])
1378 {
1379   TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawn_2_2@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
1380 	    CALL_REAL (posix_spawn_2_2), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
1381   if (NULL_PTR (posix_spawn))
1382     init_lineage_intf ();
1383   return __collector_posix_spawn_symver (CALL_REAL (posix_spawn_2_2), pidp,
1384 					 path, file_actions, attrp, argv, envp);
1385 }
1386 
1387 #else /* ^WSIZE(32) */
1388 SYMVER_ATTRIBUTE (__collector_posix_spawn_2_2_5, posix_spawn@GLIBC_2.2.5)
1389 int
__collector_posix_spawn_2_2_5(pid_t * pidp,const char * path,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])1390 __collector_posix_spawn_2_2_5 (pid_t *pidp, const char *path,
1391 			       const posix_spawn_file_actions_t *file_actions,
1392 			       const posix_spawnattr_t *attrp,
1393 			       char *const argv[], char *const envp[])
1394 {
1395   TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawn_2_2_5@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
1396 	    CALL_REAL (posix_spawn_2_2_5), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
1397   if (NULL_PTR (posix_spawn))
1398     init_lineage_intf ();
1399   return __collector_posix_spawn_symver (CALL_REAL (posix_spawn_2_2_5), pidp,
1400 					 path, file_actions, attrp, argv, envp);
1401 }
1402 #endif /* ^WSIZE(32) */
1403 
1404 static int
__collector_posix_spawn_symver(int (real_posix_spawn)(),pid_t * pidp,const char * path,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])1405 __collector_posix_spawn_symver (int(real_posix_spawn) (),
1406 #else /* ^ARCH(Intel) */
1407 int
1408 __collector_posix_spawn (
1409 #endif /* ARCH() */
1410 	pid_t *pidp, const char *path,
1411 			 const posix_spawn_file_actions_t *file_actions,
1412 			 const posix_spawnattr_t *attrp,
1413 			 char *const argv[], char *const envp[])
1414 {
1415   int ret;
1416   static char **coll_env = NULL; /* environment for collection */
1417   if (NULL_PTR (posix_spawn))
1418     init_lineage_intf ();
1419   if (NULL_PTR (posix_spawn))
1420     {
1421       TprintfT (DBG_LT0, "__collector_posix_spawn(path=%s) interposing: ERROR, posix_spawn() not found by dlsym\n",
1422 		path ? path : "NULL");
1423       return -1; /* probably should set errno */
1424     }
1425   int * guard = NULL;
1426   int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1427   TprintfT (DBG_LT0, "__collector_posix_spawn(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n",
1428 	    path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL", line_mode, combo_flag);
1429   if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
1430     __collector_env_unset ((char**) envp);
1431 
1432   if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
1433     {
1434 #if ARCH(Intel)
1435       return (real_posix_spawn) (pidp, path, file_actions, attrp, argv, envp);
1436 #else
1437       return CALL_REAL (posix_spawn)(pidp, path, file_actions, attrp, argv, envp);
1438 #endif
1439     }
1440   int following_exec = 0;
1441   coll_env = linetrace_ext_exec_prologue ("posix_spawn", path, argv, envp, &following_exec);
1442   TprintfT (DBG_LT0, "__collector_posix_spawn(): coll_env=0x%p\n", coll_env);
1443   __collector_env_printall ("__collector_posix_spawn", coll_env);
1444   PUSH_REENTRANCE (guard);
1445 #if ARCH(Intel)
1446   ret = (real_posix_spawn) (pidp, path, file_actions, attrp, argv, coll_env);
1447 #else
1448   ret = CALL_REAL (posix_spawn)(pidp, path, file_actions, attrp, argv, coll_env);
1449 #endif
1450   POP_REENTRANCE (guard);
1451   linetrace_ext_exec_epilogue ("posix_spawn", envp, ret, &following_exec);
1452   return ret;
1453 }
1454 
1455 /*-------------------------------------------------------- posix_spawnp */
1456 #if ARCH(Intel)
1457 // map interposed symbol versions
1458 
1459 static int
1460 __collector_posix_spawnp_symver (int(real_posix_spawnp) (), pid_t *pidp,
1461 				 const char *path,
1462 				 const posix_spawn_file_actions_t *file_actions,
1463 				 const posix_spawnattr_t *attrp,
1464 				 char *const argv[], char *const envp[]);
1465 
1466 SYMVER_ATTRIBUTE (__collector_posix_spawnp_2_15, posix_spawnp@@GLIBC_2.15)
1467 int // Common interposition
__collector_posix_spawnp_2_15(pid_t * pidp,const char * path,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])1468 __collector_posix_spawnp_2_15 (pid_t *pidp, const char *path,
1469 			       const posix_spawn_file_actions_t *file_actions,
1470 			       const posix_spawnattr_t *attrp,
1471 			       char *const argv[], char *const envp[])
1472 {
1473   TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawnp_2_15@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
1474 	    CALL_REAL (posix_spawnp_2_15), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
1475   if (NULL_PTR (posix_spawnp))
1476     init_lineage_intf ();
1477   return __collector_posix_spawnp_symver (CALL_REAL (posix_spawnp_2_15), pidp,
1478 					  path, file_actions, attrp, argv, envp);
1479 }
1480 
1481 #if WSIZE(32)
1482 
1483 SYMVER_ATTRIBUTE (__collector_posix_spawnp_2_2, posix_spawnp@GLIBC_2.2)
1484 int
__collector_posix_spawnp_2_2(pid_t * pidp,const char * path,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])1485 __collector_posix_spawnp_2_2 (pid_t *pidp, const char *path,
1486 			      const posix_spawn_file_actions_t *file_actions,
1487 			      const posix_spawnattr_t *attrp,
1488 			      char *const argv[], char *const envp[])
1489 {
1490   TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawnp_2_2@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
1491 	    CALL_REAL (posix_spawnp_2_2), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
1492   if (NULL_PTR (posix_spawnp))
1493     init_lineage_intf ();
1494   return __collector_posix_spawnp_symver (CALL_REAL (posix_spawnp_2_2), pidp,
1495 					  path, file_actions, attrp, argv, envp);
1496 }
1497 
1498 #else /* ^WSIZE(32) */
1499 SYMVER_ATTRIBUTE (__collector_posix_spawnp_2_2_5, posix_spawnp@GLIBC_2.2.5)
1500 int
__collector_posix_spawnp_2_2_5(pid_t * pidp,const char * path,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])1501 __collector_posix_spawnp_2_2_5 (pid_t *pidp, const char *path,
1502 				const posix_spawn_file_actions_t *file_actions,
1503 				const posix_spawnattr_t *attrp,
1504 				char *const argv[], char *const envp[])
1505 {
1506   TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawnp_2_2_5@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
1507 	    CALL_REAL (posix_spawnp_2_2_5), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
1508   if (NULL_PTR (posix_spawnp))
1509     init_lineage_intf ();
1510   return __collector_posix_spawnp_symver (CALL_REAL (posix_spawnp_2_2_5), pidp,
1511 					  path, file_actions, attrp, argv, envp);
1512 }
1513 
1514 #endif /* ^WSIZE(32) */
1515 
1516 static int
__collector_posix_spawnp_symver(int (real_posix_spawnp)(),pid_t * pidp,const char * path,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])1517 __collector_posix_spawnp_symver (int(real_posix_spawnp) (),
1518 #else /* ^ARCH(Intel) */
1519 int
1520 __collector_posix_spawnp (
1521 #endif /* ARCH() */
1522 	pid_t *pidp, const char *path,
1523 			  const posix_spawn_file_actions_t *file_actions,
1524 			  const posix_spawnattr_t *attrp,
1525 			  char *const argv[], char *const envp[]){
1526   int ret;
1527   static char **coll_env = NULL; /* environment for collection */
1528   if (NULL_PTR (posix_spawnp))
1529     init_lineage_intf ();
1530   if (NULL_PTR (posix_spawnp))
1531     {
1532       TprintfT (DBG_LT0, "__collector_posix_spawnp(path=%s) interposing: ERROR, posix_spawnp() not found by dlsym\n",
1533 		path ? path : "NULL");
1534       return -1; /* probably should set errno */
1535     }
1536   int * guard = NULL;
1537   int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1538   TprintfT (DBG_LT0, "__collector_posix_spawnp(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n",
1539 	    path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
1540 	    envp ? (envp[0] ? envp[0] : "NULL") : "NULL", line_mode, combo_flag);
1541 
1542   if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
1543     __collector_env_unset ((char**) envp);
1544   if (line_mode != LM_TRACK_LINEAGE || combo_flag)
1545     {
1546 #if ARCH(Intel)
1547       return (real_posix_spawnp) (pidp, path, file_actions, attrp, argv, envp);
1548 #else
1549       return CALL_REAL (posix_spawnp)(pidp, path, file_actions, attrp, argv, envp);
1550 #endif
1551     }
1552   int following_exec = 0;
1553   coll_env = linetrace_ext_exec_prologue ("posix_spawnp", path, argv, envp, &following_exec);
1554   TprintfT (DBG_LT0, "__collector_posix_spawnp(): coll_env=0x%p\n", coll_env);
1555   __collector_env_printall ("__collector_posix_spawnp", coll_env);
1556   PUSH_REENTRANCE (guard);
1557 #if ARCH(Intel)
1558   ret = (real_posix_spawnp) (pidp, path, file_actions, attrp, argv, coll_env);
1559 #else
1560   ret = CALL_REAL (posix_spawnp)(pidp, path, file_actions, attrp, argv, coll_env);
1561 #endif
1562   POP_REENTRANCE (guard);
1563   linetrace_ext_exec_epilogue ("posix_spawnp", envp, ret, &following_exec);
1564   return ret;
1565 }
1566 
1567 /*------------------------------------------------------------- system */
1568 int system () __attribute__ ((weak, alias ("__collector_system")));
1569 
1570 int
__collector_system(const char * cmd)1571 __collector_system (const char *cmd)
1572 {
1573   if (NULL_PTR (system))
1574     init_lineage_intf ();
1575   TprintfT (DBG_LT0,
1576 	    "__collector_system(cmd=%s) interposing: line_mode=%d combo=%d\n",
1577 	    cmd ? cmd : "NULL", line_mode, get_combo_flag ());
1578   int *guard = NULL;
1579   if (line_mode == LM_TRACK_LINEAGE)
1580     INIT_REENTRANCE (guard);
1581   if (guard == NULL)
1582     return CALL_REAL (system)(cmd);
1583   int following_combo = 0;
1584   linetrace_ext_combo_prologue ("system", cmd, &following_combo);
1585   PUSH_REENTRANCE (guard);
1586   int ret = CALL_REAL (system)(cmd);
1587   POP_REENTRANCE (guard);
1588   linetrace_ext_combo_epilogue ("system", ret, &following_combo);
1589   return ret;
1590 }
1591 
1592 /*------------------------------------------------------------- popen */
1593 // map interposed symbol versions
1594 #if ARCH(Intel) && WSIZE(32)
1595 static FILE *
1596 __collector_popen_symver (FILE*(real_popen) (), const char *cmd, const char *mode);
1597 
1598 SYMVER_ATTRIBUTE (__collector_popen_2_1, popen@@GLIBC_2.1)
1599 FILE *
__collector_popen_2_1(const char * cmd,const char * mode)1600 __collector_popen_2_1 (const char *cmd, const char *mode)
1601 {
1602   if (NULL_PTR (popen))
1603     init_lineage_intf ();
1604   TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_popen_2_1@%p\n", CALL_REAL (popen_2_1));
1605   return __collector_popen_symver (CALL_REALF (popen_2_1), cmd, mode);
1606 }
1607 
1608 SYMVER_ATTRIBUTE (__collector_popen_2_0, popen@GLIBC_2.0)
1609 FILE *
__collector_popen_2_0(const char * cmd,const char * mode)1610 __collector_popen_2_0 (const char *cmd, const char *mode)
1611 {
1612   if (NULL_PTR (popen))
1613     init_lineage_intf ();
1614   TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_popen_2_0@%p\n", CALL_REAL (popen_2_0));
1615   return __collector_popen_symver (CALL_REALF (popen_2_0), cmd, mode);
1616 }
1617 
1618 SYMVER_ATTRIBUTE (__collector__popen_2_1, _popen@@GLIBC_2.1)
1619 FILE *
__collector__popen_2_1(const char * cmd,const char * mode)1620 __collector__popen_2_1 (const char *cmd, const char *mode)
1621 {
1622   if (NULL_PTR (popen))
1623     init_lineage_intf ();
1624   TprintfT (DBG_LTT, "linetrace: GLIBC: __collector__popen_2_1@%p\n", CALL_REAL (popen_2_1));
1625   return __collector_popen_symver (CALL_REALF (popen_2_1), cmd, mode);
1626 }
1627 
1628 SYMVER_ATTRIBUTE (__collector__popen_2_0, _popen@GLIBC_2.0)
1629 FILE *
__collector__popen_2_0(const char * cmd,const char * mode)1630 __collector__popen_2_0 (const char *cmd, const char *mode)
1631 {
1632   if (NULL_PTR (popen))
1633     init_lineage_intf ();
1634   return __collector_popen_symver (CALL_REALF (popen_2_0), cmd, mode);
1635 }
1636 #else // WSIZE(64)
1637 FILE * popen () __attribute__ ((weak, alias ("__collector_popen")));
1638 #endif
1639 
1640 #if ARCH(Intel) && WSIZE(32)
1641 static FILE *
__collector_popen_symver(FILE * (real_popen)(),const char * cmd,const char * mode)1642 __collector_popen_symver (FILE*(real_popen) (), const char *cmd, const char *mode)
1643 #else
1644 
1645 FILE *
1646 __collector_popen (const char *cmd, const char *mode)
1647 #endif
1648 {
1649   FILE *ret;
1650   if (NULL_PTR (popen))
1651     init_lineage_intf ();
1652   TprintfT (DBG_LT0,
1653 	    "__collector_popen(cmd=%s) interposing: line_mode=%d combo=%d\n",
1654 	    cmd ? cmd : "NULL", line_mode, get_combo_flag ());
1655   int *guard = NULL;
1656   if (line_mode == LM_TRACK_LINEAGE)
1657     INIT_REENTRANCE (guard);
1658   if (guard == NULL)
1659     {
1660 #if ARCH(Intel) && WSIZE(32)
1661       return (real_popen) (cmd, mode);
1662 #else
1663       return CALL_REALF (popen)(cmd, mode);
1664 #endif
1665     }
1666   int following_combo = 0;
1667   linetrace_ext_combo_prologue ("popen", cmd, &following_combo);
1668   PUSH_REENTRANCE (guard);
1669 #if ARCH(Intel) && WSIZE(32)
1670   ret = (real_popen) (cmd, mode);
1671 #else
1672   ret = CALL_REALF (popen)(cmd, mode);
1673 #endif
1674   POP_REENTRANCE (guard);
1675   linetrace_ext_combo_epilogue ("popen", (ret == NULL) ? (-1) : 0, &following_combo);
1676   return ret;
1677 }
1678 
1679 /*------------------------------------------------------------- grantpt */
1680 int grantpt () __attribute__ ((weak, alias ("__collector_grantpt")));
1681 
1682 int
__collector_grantpt(const int fildes)1683 __collector_grantpt (const int fildes)
1684 {
1685   if (NULL_PTR (grantpt))
1686     init_lineage_intf ();
1687   TprintfT (DBG_LT0,
1688 	    "__collector_grantpt(%d) interposing: line_mode=%d combo=%d\n",
1689 	    fildes, line_mode, get_combo_flag ());
1690   int *guard = NULL;
1691   if (line_mode == LM_TRACK_LINEAGE)
1692     INIT_REENTRANCE (guard);
1693   if (guard == NULL)
1694     return CALL_REAL (grantpt)(fildes);
1695   int following_combo = 0;
1696   linetrace_ext_combo_prologue ("grantpt", "/usr/lib/pt_chmod", &following_combo);
1697   PUSH_REENTRANCE (guard);
1698   int ret = CALL_REAL (grantpt)(fildes);
1699   POP_REENTRANCE (guard);
1700   linetrace_ext_combo_epilogue ("grantpt", ret, &following_combo);
1701   return ret;
1702 }
1703 
1704 /*------------------------------------------------------------- ptsname */
1705 char *ptsname () __attribute__ ((weak, alias ("__collector_ptsname")));
1706 
1707 char *
__collector_ptsname(const int fildes)1708 __collector_ptsname (const int fildes)
1709 {
1710   if (NULL_PTR (ptsname))
1711     init_lineage_intf ();
1712   TprintfT (DBG_LT0,
1713 	    "__collector_ptsname(%d) interposing: line_mode=%d combo=%d\n",
1714 	    fildes, line_mode, get_combo_flag ());
1715   int *guard = NULL;
1716   if (line_mode == LM_TRACK_LINEAGE)
1717     INIT_REENTRANCE (guard);
1718   if (guard == NULL)
1719     return CALL_REALC (ptsname)(fildes);
1720   int following_combo = 0;
1721   linetrace_ext_combo_prologue ("ptsname", "/usr/lib/pt_chmod", &following_combo);
1722   PUSH_REENTRANCE (guard);
1723   char *ret = CALL_REALC (ptsname)(fildes);
1724   POP_REENTRANCE (guard);
1725   linetrace_ext_combo_epilogue ("ptsname", (ret == NULL) ? (-1) : 1, &following_combo);
1726   return ret;
1727 }
1728 
1729 /*------------------------------------------------------------- clone */
1730 /* clone can be fork-like or pthread_create-like, depending on whether
1731  * the flag CLONE_VM is set. If CLONE_VM is not set, then we interpose
1732  * clone in the way similar to interposing fork; if CLONE_VM is set,
1733  * then we interpose clone in the way similar to interposing pthread_create.
1734  * One special case is not handled: when CLONE_VM is set but CLONE_THREAD
1735  * is not, if the parent process exits earlier than the child process,
1736  * experiment will close, losing data from child process.
1737  */
1738 typedef struct __collector_clone_arg
1739 {
1740   int (*fn)(void *);
1741   void * arg;
1742   char * new_lineage;
1743   int following_fork;
1744 } __collector_clone_arg_t;
1745 
1746 static int
__collector_clone_fn(void * fn_arg)1747 __collector_clone_fn (void *fn_arg)
1748 {
1749   int (*fn)(void *) = ((__collector_clone_arg_t*) fn_arg)->fn;
1750   void * arg = ((__collector_clone_arg_t*) fn_arg)->arg;
1751   char * new_lineage = ((__collector_clone_arg_t*) fn_arg)->new_lineage;
1752   int following_fork = ((__collector_clone_arg_t*) fn_arg)->following_fork;
1753   __collector_freeCSize (__collector_heap, fn_arg, sizeof (__collector_clone_arg_t));
1754   linetrace_ext_fork_epilogue ("clone", 0, new_lineage, &following_fork);
1755   return fn (arg);
1756 }
1757 
1758 int clone (int (*fn)(void *), void *, int, void *, ...) __attribute__ ((weak, alias ("__collector_clone")));
1759 
1760 int
__collector_clone(int (* fn)(void *),void * child_stack,int flags,void * arg,...)1761 __collector_clone (int (*fn)(void *), void *child_stack, int flags, void *arg,
1762 		   ... /* pid_t *ptid, struct user_desc *tls, pid_t *" ctid" */)
1763 {
1764   int ret;
1765   va_list va;
1766   if (flags & CLONE_VM)
1767     {
1768       va_start (va, arg);
1769       ret = __collector_ext_clone_pthread (fn, child_stack, flags, arg, va);
1770       va_end (va);
1771     }
1772   else
1773     {
1774       if (NULL_PTR (clone))
1775 	init_lineage_intf ();
1776       int *guard = NULL;
1777       int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
1778       TprintfT (DBG_LT0, "__collector_clone() interposition: line_mode=%d combo=%d\n",
1779 		line_mode, combo_flag);
1780       char new_lineage[LT_MAXNAMELEN];
1781       int following_fork = 0;
1782       __collector_clone_arg_t *funcinfo = __collector_allocCSize (__collector_heap, sizeof (__collector_clone_arg_t), 1);
1783       (*funcinfo).fn = fn;
1784       (*funcinfo).arg = arg;
1785       (*funcinfo).new_lineage = new_lineage;
1786       (*funcinfo).following_fork = 0;
1787       pid_t * ptid = NULL;
1788       struct user_desc * tls = NULL;
1789       pid_t * ctid = NULL;
1790       int num_args = 0;
1791       va_start (va, arg);
1792       if (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))
1793 	{
1794 	  ptid = va_arg (va, pid_t *);
1795 	  tls = va_arg (va, struct user_desc*);
1796 	  ctid = va_arg (va, pid_t *);
1797 	  num_args = 3;
1798 	}
1799       else if (flags & CLONE_SETTLS)
1800 	{
1801 	  ptid = va_arg (va, pid_t *);
1802 	  tls = va_arg (va, struct user_desc*);
1803 	  num_args = 2;
1804 	}
1805       else if (flags & CLONE_PARENT_SETTID)
1806 	{
1807 	  ptid = va_arg (va, pid_t *);
1808 	  num_args = 1;
1809 	}
1810       if ((line_mode != LM_TRACK_LINEAGE) || combo_flag || funcinfo == NULL)
1811 	{
1812 	  switch (num_args)
1813 	    {
1814 	    case 3:
1815 	      ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
1816 	      break;
1817 	    case 2:
1818 	      ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
1819 	      break;
1820 	    case 1:
1821 	      ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
1822 	      break;
1823 	    default:
1824 	      ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
1825 	      break;
1826 	    }
1827 
1828 	  va_end (va);
1829 	  return ret;
1830 	}
1831       linetrace_ext_fork_prologue ("clone", new_lineage, &following_fork);
1832       (*funcinfo).following_fork = following_fork;
1833       switch (num_args)
1834 	{
1835 	case 3:
1836 	  ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid, tls, ctid);
1837 	  break;
1838 	case 2:
1839 	  ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid, tls);
1840 	  break;
1841 	case 1:
1842 	  ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid);
1843 	  break;
1844 	default:
1845 	  ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo);
1846 	  break;
1847 	}
1848       va_end (va);
1849       if (ret < 0)
1850 	__collector_freeCSize (__collector_heap, funcinfo, sizeof (__collector_clone_arg_t));
1851       TprintfT (DBG_LT0, "__collector_clone() interposing: pid=%d\n", ret);
1852       linetrace_ext_fork_epilogue ("clone", ret, new_lineage, &following_fork);
1853     }
1854   return ret;
1855 }
1856 
1857 /*-------------------------------------------------------------------- setuid */
1858 int setuid () __attribute__ ((weak, alias ("__collector_setuid")));
1859 int _setuid () __attribute__ ((weak, alias ("__collector_setuid")));
1860 
1861 int
__collector_setuid(uid_t ruid)1862 __collector_setuid (uid_t ruid)
1863 {
1864   if (NULL_PTR (setuid))
1865     init_lineage_intf ();
1866   TprintfT (DBG_LT0, "__collector_setuid(0x%x) interposing\n", ruid);
1867   check_reuid_change (ruid, -1);
1868   int ret = CALL_REAL (setuid)(ruid);
1869   TprintfT (DBG_LT0, "__collector_setuid(0x%x) returning %d\n", ruid, ret);
1870   return ret;
1871 }
1872 
1873 /*------------------------------------------------------------------- seteuid */
1874 int seteuid () __attribute__ ((weak, alias ("__collector_seteuid")));
1875 int _seteuid () __attribute__ ((weak, alias ("__collector_seteuid")));
1876 
1877 int
__collector_seteuid(uid_t euid)1878 __collector_seteuid (uid_t euid)
1879 {
1880   if (NULL_PTR (seteuid))
1881     init_lineage_intf ();
1882   TprintfT (DBG_LT0, "__collector_seteuid(0x%x) interposing\n", euid);
1883   check_reuid_change (-1, euid);
1884   int ret = CALL_REAL (seteuid)(euid);
1885   TprintfT (DBG_LT0, "__collector_seteuid(0x%x) returning %d\n", euid, ret);
1886   return ret;
1887 }
1888 
1889 /*------------------------------------------------------------------ setreuid */
1890 int setreuid () __attribute__ ((weak, alias ("__collector_setreuid")));
1891 int _setreuid () __attribute__ ((weak, alias ("__collector_setreuid")));
1892 
1893 int
__collector_setreuid(uid_t ruid,uid_t euid)1894 __collector_setreuid (uid_t ruid, uid_t euid)
1895 {
1896   if (NULL_PTR (setreuid))
1897     init_lineage_intf ();
1898   TprintfT (DBG_LT0, "__collector_setreuid(0x%x,0x%x) interposing\n", ruid, euid);
1899   check_reuid_change (ruid, euid);
1900   int ret = CALL_REAL (setreuid)(ruid, euid);
1901   TprintfT (DBG_LT0, "__collector_setreuid(0x%x,0x%x) returning %d\n", ruid, euid, ret);
1902   return ret;
1903 }
1904 
1905 /*-------------------------------------------------------------------- setgid */
1906 int setgid () __attribute__ ((weak, alias ("__collector_setgid")));
1907 int _setgid () __attribute__ ((weak, alias ("__collector_setgid")));
1908 
1909 int
__collector_setgid(gid_t rgid)1910 __collector_setgid (gid_t rgid)
1911 {
1912   if (NULL_PTR (setgid))
1913     init_lineage_intf ();
1914   TprintfT (DBG_LT0, "__collector_setgid(0x%x) interposing\n", rgid);
1915   check_regid_change (rgid, -1);
1916   int ret = CALL_REAL (setgid)(rgid);
1917   TprintfT (DBG_LT0, "__collector_setgid(0x%x) returning %d\n", rgid, ret);
1918   return ret;
1919 }
1920 
1921 /*------------------------------------------------------------------- setegid */
1922 int setegid () __attribute__ ((weak, alias ("__collector_setegid")));
1923 int _setegid () __attribute__ ((weak, alias ("__collector_setegid")));
1924 
1925 int
__collector_setegid(gid_t egid)1926 __collector_setegid (gid_t egid)
1927 {
1928   if (NULL_PTR (setegid))
1929     init_lineage_intf ();
1930   TprintfT (DBG_LT0, "__collector_setegid(0x%x) interposing\n", egid);
1931   check_regid_change (-1, egid);
1932   int ret = CALL_REAL (setegid)(egid);
1933   TprintfT (DBG_LT0, "__collector_setegid(0x%x) returning %d\n", egid, ret);
1934   return ret;
1935 }
1936 
1937 /*------------------------------------------------------------------ setregid */
1938 int setregid () __attribute__ ((weak, alias ("__collector_setregid")));
1939 int _setregid () __attribute__ ((weak, alias ("__collector_setregid")));
1940 
1941 int
__collector_setregid(gid_t rgid,gid_t egid)1942 __collector_setregid (gid_t rgid, gid_t egid)
1943 {
1944   if (NULL_PTR (setregid))
1945     init_lineage_intf ();
1946   TprintfT (DBG_LT0, "__collector_setregid(0x%x,0x%x) interposing\n", rgid, egid);
1947   check_regid_change (rgid, egid);
1948   int ret = CALL_REAL (setregid)(rgid, egid);
1949   TprintfT (DBG_LT0, "__collector_setregid(0x%x,0x%x) returning %d\n", rgid, egid, ret);
1950   return ret;
1951 }
1952 
1953 /*------------------------------------------------------- selective following */
1954 
1955 static int
linetrace_follow_experiment(const char * follow_spec,const char * lineage_str,const char * progname)1956 linetrace_follow_experiment (const char *follow_spec, const char *lineage_str, const char *progname)
1957 {
1958   regex_t regex_desc;
1959   if (!follow_spec)
1960     {
1961       TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES NULL follow_spec\n");
1962       return 1;
1963     }
1964   int ercode = regcomp (&regex_desc, follow_spec, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
1965   if (ercode)
1966     {
1967       // syntax error in parsing string
1968 #ifdef DEBUG
1969       char errbuf[256];
1970       regerror (ercode, &regex_desc, errbuf, sizeof (errbuf));
1971       TprintfT (DBG_LT0, "linetrace_follow_experiment: regerror()=%s\n", errbuf);
1972 #endif
1973       return 1;
1974     }
1975   TprintfT (DBG_LT0, "linetrace_follow_experiment(): compiled spec='%s'\n", follow_spec);
1976   if (lineage_str)
1977     {
1978       if (!regexec (&regex_desc, lineage_str, 0, NULL, 0))
1979 	{
1980 	  TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES lineage (follow_spec=%s,lineage=%s)\n",
1981 		    follow_spec, lineage_str);
1982 	  return 1;
1983 	}
1984     }
1985   if (progname)
1986     {
1987       if (!regexec (&regex_desc, progname, 0, NULL, 0))
1988 	{
1989 	  TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES progname (follow_spec=%s,progname=%s)\n",
1990 		    follow_spec, progname);
1991 	  return 1;
1992 	}
1993     }
1994   TprintfT (DBG_LT0, "linetrace_follow_experiment(): DOES NOT MATCH (follow_spec=%s,lineage=%s,progname=%s)\n",
1995 	    follow_spec, lineage_str ? lineage_str : "NULL",
1996 	    progname ? progname : "NULL");
1997   return 0;
1998 }
1999