Skip to content
/linux-syscalls

Process & Thread · Section 2

exit_group(2)

Terminate every thread in the calling thread group at once.

Signature

#include <sys/syscall.h>

void exit_group(int status);
status
Exit status. Only the low 8 bits are observable by wait4/waitid; conventionally 0 for success, non-zero for failure. Status > 127 is conventionally reserved for signal-derived exit codes.

Description

exit_group() ends all threads in the calling thread group (i.e. the whole process, in POSIX terminology) immediately, with the given exit status. Unlike exit() — which terminates only the calling thread — exit_group() walks the entire TGID and tears down every task. This is what glibc's exit() and _exit() wrappers ultimately call; only thread-local pthread_exit() routes to the per-thread sys_exit. exit_group() never returns. The low 8 bits of status are reported to the parent via wait4/waitid (the upper bits are silently discarded — pass small integers).

Architecture mapping

ArchitectureNumberABIEntry point
x86 (i386)252i386sys_exit_group
x64 (x86_64)231commonsys_exit_group
ARM64 (aarch64)94sys_exit_group

Kernel history

Introduced in Linux 2.5.35.

  1. 2.5.35

    exit_group() was added in 2.5.35 (the NPTL series) so glibc could exit an entire pthread process with a single syscall, instead of looping through every thread and calling exit() on each (the historical _exit() behaviour on Linux until NPTL).

seccomp & containers

Docker default profile

Allowed

Podman default profile

Allowed

exit_group() and exit() must be on every default profile and every custom allow-list. Blocking them produces a zombie process that cannot terminate — the kernel would deliver SIGKILL eventually, but the diagnostic experience is terrible. Always include SCMP_SYS(exit_group), SCMP_SYS(exit), and SCMP_SYS(rt_sigreturn) in the bare-minimum allow-list of any seccomp filter.

libseccomp

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit),       0);

strace example

$ strace -e exit_group /bin/true
exit_group(0)                           = ?
+++ exited with 0 +++

exit_group() is always the last syscall in any -e exit_group trace; pair it with -f to follow multithreaded teardown. The 'status = ?' annotation is strace's way of saying the kernel doesn't return from this call.

Security & observability

exit_group() is rarely interesting to defenders directly — every process emits exactly one. The eBPF tracepoint sched_process_exit fires with the status; pairing with sched_process_exec gives the full lifecycle. Of more interest: processes that never exit (long-running daemons doing nothing), or processes that exit with status 0 immediately after execve() of a privileged binary (failed exploit attempt). Most monitoring focuses on the exec side, not the exit side.

Related syscalls