@@ -405,10 +405,21 @@ struct ScopedSetTracerPID {
405
405
406
406
// This detects whether ptrace is blocked (e.g., by seccomp), by forking and
407
407
// then attempting ptrace.
408
- // This separate check is necessary because StopTheWorld() creates a child
409
- // process with a shared virtual address space and shared TLS, and therefore
408
+ // This separate check is necessary because StopTheWorld() creates a thread
409
+ // with a shared virtual address space and shared TLS, and therefore
410
410
// cannot use waitpid() due to the shared errno.
411
411
static void TestPTrace () {
412
+ # if SANITIZER_SPARC
413
+ // internal_fork() on SPARC actually calls __fork(). We can't safely fork,
414
+ // because it's possible seccomp has been configured to disallow fork() but
415
+ // allow clone().
416
+ Report (" WARNING: skipping TestPTrace() because this is SPARC\n " );
417
+ Report (
418
+ " If seccomp blocks ptrace, LeakSanitizer may hang without further "
419
+ " notice\n " );
420
+ Report (
421
+ " If seccomp does not block ptrace, you can safely ignore this warning\n " );
422
+ # else
412
423
// Heuristic: only check the first time this is called. This is not always
413
424
// correct (e.g., user manually triggers leak detection, then updates
414
425
// seccomp, then leak detection is triggered again).
@@ -417,35 +428,46 @@ static void TestPTrace() {
417
428
return ;
418
429
checked = true ;
419
430
420
- // We hope that fork () is not too expensive, because of copy-on-write.
431
+ // Hopefully internal_fork () is not too expensive, thanks to copy-on-write.
421
432
// Besides, this is only called the first time.
433
+ // Note that internal_fork() on non-SPARC Linux actually calls
434
+ // SYSCALL(clone); thus, it is reasonable to use it because if seccomp kills
435
+ // TestPTrace(), it would have killed StopTheWorld() anyway.
422
436
int pid = internal_fork ();
423
437
424
438
if (pid < 0 ) {
425
439
int rverrno;
426
- if (internal_iserror (pid, &rverrno)) {
440
+ if (internal_iserror (pid, &rverrno))
427
441
Report (" WARNING: TestPTrace() failed to fork (errno %d)\n " , rverrno);
428
- }
429
- internal__exit (-1 );
442
+
443
+ // We don't abort the sanitizer - it's still worth letting the sanitizer
444
+ // try.
445
+ return ;
430
446
}
431
447
432
448
if (pid == 0 ) {
433
449
// Child subprocess
450
+
451
+ // TODO: consider checking return value of internal_ptrace, to handle
452
+ // SCMP_ACT_ERRNO. However, be careful not to consume too many
453
+ // resources performing a proper ptrace.
434
454
internal_ptrace (PTRACE_ATTACH, 0 , nullptr , nullptr );
435
455
internal__exit (0 );
436
456
} else {
437
457
int wstatus;
438
458
internal_waitpid (pid, &wstatus, 0 );
439
459
460
+ // Handle SCMP_ACT_KILL
440
461
if (WIFSIGNALED (wstatus)) {
441
462
VReport (0 ,
442
- " Warning : ptrace appears to be blocked (is seccomp enabled?). "
463
+ " WARNING : ptrace appears to be blocked (is seccomp enabled?). "
443
464
" LeakSanitizer may hang.\n " );
444
465
VReport (0 , " Child exited with signal %d.\n " , WTERMSIG (wstatus));
445
466
// We don't abort the sanitizer - it's still worth letting the sanitizer
446
467
// try.
447
468
}
448
469
}
470
+ # endif
449
471
}
450
472
451
473
void StopTheWorld (StopTheWorldCallback callback, void *argument) {
0 commit comments