← Back to list

Tracing Processes in Go with Ptrace and Seccomp

In this article, we’ll explore how to use Linux’s ptrace and seccomp mechanisms in Go to trace system calls and enforce security policies.

Robert Mindo · 2025-01-26 23:36 · 0 claps · 3.4 min read
#ptrace #tracing #seccomp #golang #security
Open on Medium ↗
Wiki topics: SOC · Sociology & Politics 🔓 · Open Source

Tracing Processes in Go with Ptrace and Seccomp

In this article, we’ll explore how to use Linux’s ptrace and seccomp mechanisms in Go to trace system calls and enforce security policies.

Tracing System Calls with ptrace

First we’ll make a simple go program to trace, intercept and print syscalls. We’ll use U-root’s ptrace package to make the process easier :)

First what is ptrace? (Process Trace) is a Linux system call that allows one process to observe and control the execution of another. With ptrace, we can monitor a running process in real-time, allowing us to track every action it takes. This capability is particularly useful for analyzing potentially unsafe programs and detecting malicious or unexpected behavior.

[embed]GitHub - robertmin1/strace: Simple demonstration of tracing processes in Go using ptrace and… Simple demonstration of tracing processes in Go using ptrace and seccomp - robertmin1/stracegithub.com

func main() {
 flag.Parse()
 args := flag.Args()
 if len(args) < 1 {
  fmt.Println(errUsage)
  os.Exit(1)
 }

 c := exec.Command(args[0], args[1:]...)
 c.Stdin, c.Stdout, c.Stderr = os.Stdin, os.Stdout, os.Stderr

 if err := strace.New(c, false, func(task strace.Task, record *strace.TraceRecord) error {
  if record.Event == strace.SyscallExit || record.Event == strace.SyscallEnter {
   log.Printf("\033[1;34mpid %d: \033[1;33mSyscall Number %d\033[0m", record.PID, record.Syscall.Sysno)
  }
  return nil
 }); err != nil {
  panic(err)
 }
}

The program is pretty simple: it first collects the command-line arguments from the user, specifically the program to run and its associated arguments. These are then passed to the strace package. The strace package expects three arguments (e.g go run main.go wget google.com) :

  1. An exec.Cmd containing the program and its arguments to execute.
  2. A boolean flag (seccomp) that determines whether seccomp is enabled or disabled.
  3. A recordCallback function, which is invoked after each system call is made.

Adding Seccomp for Enhanced Security and Speed Bumping

Seccomp (Secure Computing Mode) is a security mechanism that limits the system calls (syscalls) a process can make, helping to reduce the attack surface and mitigate the risk of exploitation via harmful or unnecessary syscalls.

In our implementation, seccomp can act as a “speed bump,” allowing us to focus on tracing only a subset of syscalls instead of tracking all system calls made by the process. This can help improve performance by reducing the overhead associated with syscall tracing.

How it works in the background

If seccomp is enabled, instead of stopping at every syscall, we only intercept and handle the syscalls that we are interested in, leaving others to be processed normally.

Here’s a simplified breakdown of the code implementing this logic:

func (p *process) cont(signal unix.Signal) error {
 // Event has been processed. Restart 'em.
 if p.SecComp.Load() {
  // If seccomp is enabled, continue the process without stopping at each syscall.
  if err := unix.PtraceCont(p.pid, int(signal)); err != nil {
   return os.NewSyscallError("ptrace(PTRACE_SYSCALL)", fmt.Errorf("on pid %d: %w", p.pid, err))
  }
  return nil
 }
 // If seccomp is not enabled, continue the process and stop at each syscall.
 if err := unix.PtraceSyscall(p.pid, int(signal)); err != nil {
  return os.NewSyscallError("ptrace(PTRACE_SYSCALL)", fmt.Errorf("on pid %d: %w", p.pid, err))
 }
 return nil
}
  • Seccomp flag: The SecComp flag is checked to determine if seccomp is enabled for the process. If it is enabled, instead of stopping at every syscall, we use unix.PtraceCont to continue execution without pausing at each syscall.

Now, for the syscalls we’re interested in, seccomp will send a PTRACE_EVENT_SECCOMP signal to ptrace. We can then handle the event by calling the syscall, which sends the syscall to userspace for further inspection.

case unix.PTRACE_EVENT_SECCOMP:
     // Handle seccomp event by continuing the syscall.
     if err := syscall.PtraceSyscall(pid, 0); err != nil {
      return os.NewSyscallError("ptrace(PTRACE_SYSCALL)", fmt.Errorf("on pid %d: %w", p.pid, err))
     }
     continue

PS : Tracer needs the unix.PTRACE_O_TRACESECCOMP option enabled to receive seccomp events. Seccomp must be active on the tracee for the kernel to trigger seccomp events. The seccomp argument in the new function mentioned above must be set to true

Implementing Seccomp in the Tracee

We’ll use [libseccomp-golang](https://github.com/seccomp/libseccomp-golang)to implement a seccomp filter.

func setupSeccomp() error {
 // Create a new filter with a default action to allow all syscalls.
 filter, err := seccomp.NewFilter(seccomp.ActAllow)
 if err != nil {
  return fmt.Errorf("failed to create seccomp filter: %w", err)
 }

 if err := filter.AddRule(unix.SYS_CONNECT, seccomp.ActTrace); err != nil {
  return fmt.Errorf("failed to add connect syscall to seccomp filter: %w", err)
 }

 // Load the filter into the kernel.
 if err := filter.Load(); err != nil {
  return fmt.Errorf("failed to load seccomp filter: %w", err)
 }

 return nil
}

We set up a simple seccomp filter to trace only connect syscalls, allowing all other syscalls to pass through. This approach speeds up the tracing process by avoiding the interception of unnecessary syscalls. However, despite the seccomp speed bump, this method is still relatively slow, and faces issues when tracing larger applications such as web browsers.

To address this performance bottleneck, I recommend leveraging the user-space notification mechanism provided by seccomp. This alternative is not only easier to implement but also significantly faster — up to three times faster based on personal testing.

P.S.: I have a working proof of concept (PoC) for this solution, which I plan to write about soon. In Golang of course :)


메타데이터
post_id
9904cfa7121e
slug
tracing-processes-in-go-with-ptrace-and-seccomp-9904cfa7121e
url
https://medium.com/@mindo.robert1/tracing-processes-in-go-with-ptrace-and-seccomp-9904cfa7121e
canonical_url
https://medium.com/@mindo.robert1/tracing-processes-in-go-with-ptrace-and-seccomp-9904cfa7121e
author_url
https://medium.com/@mindo.robert1
status
ok
fetched_at
2026-07-21 04:51:34