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 (®ex_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, ®ex_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 (®ex_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 (®ex_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