skip to content

Why does tcpdump offer -Z to switch to an unprivileged user after opening the capture device, and what does it change for the files it writes?

level: seniorimportance: nice to knowfreq 6%

answer

  1. privilege to open, not to parse
  2. C printers read hostile bytes
  3. the switch precedes the output file
  4. packaged builds may drop anyway

basics

~20 s

Opening a live device needs root; parsing hostile packets does not, so -Z user drops root once the device is open. The -w file and rotated files are opened after the switch, so normally that user must be able to write them.

solid answer

~40 s

Only opening the capture device needs privilege (root, or `CAP_NET_RAW` on Linux); everything after that is tcpdump's C protocol printers parsing bytes an attacker can choose, and tcpdump's change log lists more than a hundred CVEs, mostly in those printers. `-Z user` makes a root tcpdump switch UID and GID to that user after opening the device but before opening any output savefile. The capture still sees the same packets, but the `-w` file and every `-C` or `-G` rotation are opened as that user, so the directory normally has to be writable by it. Packages built with a default user drop privileges even without `-Z` and print `dropped privs to <user>`; `-Z root` keeps root.

go deeper

for a junior

Recall that capturing needs root or a capture privilege but reading a saved file does not, and that -Z names the user tcpdump switches to.

for a middle

Explain the order: the device is opened as root, then the user switches, then output files are opened, which is why the -w directory must suit the -Z user.

for a senior

Justify privilege dropping by the parser attack surface, plan writable capture directories for rotation, and recognise packaged builds that drop privileges by default.

for a principal

Set a policy for capture on shared hosts: unprivileged capture accounts, where capture files live and who may read them, and whether long-running captures belong on hosts at all.

## Why tcpdump needs privilege at all Opening a live capture device requires privilege. On Linux that means root or the `CAP_NET_RAW` capability (how capabilities are granted is a separate subject); on BSD and macOS it means access to the `/dev/bpf*` devices. Reading a saved capture file needs no privilege at all. ## Why it should not keep it Once the device is open, everything else tcpdump does is parsing. Well over a hundred protocol printers written in C decode bytes chosen by whoever sent the packet. tcpdump's `CHANGES` file lists more than a hundred CVE identifiers, most of them fixed in individual protocol printers. A long-running capture as root turns any such bug into a potential root compromise triggered from the network. ## What `-Z` does - `-Z user` (long form `--relinquish-privileges=`): if tcpdump is running as root, it changes the user ID to *user* and the group ID to that user's primary group **after opening the capture device or input savefile, but before opening any savefiles for output**. - The capture handle that is already open keeps working, so the capture sees exactly the same packets. - Builds configured with `--with-user` do this **by default** when started as root, even without `-Z`; tcpdump announces `dropped privs to <user>` on standard error. `-Z root` keeps the old behaviour of staying root. - Builds configured with `--with-chroot` also change root into a directory before opening output files. | | Running as root throughout | With `-Z capture` | |---|---|---| | Opening the device | as root | as root | | Parsing and printing packets | as root | as `capture` | | Opening the `-w` file | as root | after the switch | | Opening rotated files | as root | as `capture` | | Impact of a printer bug | root on the host | limited to the `capture` account | ## What changes for the files it writes 1. The `-w` file is opened **after** the switch, so the directory normally has to be writable by the `-Z` user. A command such as `sudo tcpdump -Z capture -w /root/cap.pcap` can fail with a permission error even though you ran it with sudo. 2. Every file opened later by `-C` or `-G` rotation is opened after the switch too, so a ring can start fine and the next file still has to be creatable by that user. 3. Builds linked with libcap-ng briefly raise a capability that overrides file permissions just for these opens, so the same command can work on one host and fail on another; do not depend on it. 4. On a build with a compiled-in chroot, the `-w` path is resolved inside that chroot directory. ## A setup that works everywhere 1. Create a capture directory owned by the unprivileged account, for example `/var/capture` owned by `capture`. 2. Start the capture as root with the switch: `sudo tcpdump -i eth0 -Z capture -C 500 -W 20 -w /var/capture/edge.pcap 'tcp port 5432'`. 3. Check standard error for `dropped privs to capture`. 4. Analyse the files with `tcpdump -r` or Wireshark as an ordinary user, since reading a savefile needs no privilege. ## Checking that it took effect - tcpdump writes `dropped privs to <user>` to standard error when the switch succeeds; no such line means it is still running as root. - While the capture runs, the process list shows tcpdump owned by the unprivileged account rather than root. - tcpdump's own source comments describe the intended pattern: start it with sudo and let `-Z` move it into a restricted account, rather than leaving a privileged process parsing traffic for days. ## What `-Z` does not do - It does not restrict **which packets** are captured; that is the filter's job. - It does not make tcpdump runnable without privilege; the device is still opened before the switch. - It does not protect the capture files themselves; they hold whatever the snapshot length kept, and they need the same care as any other sensitive data.

  • A packaged tcpdump prints `dropped privs to tcpdump` though you never passed `-Z`; why, and how do you keep root?
    The package was built with a compiled-in default user (`--with-user`), so a root tcpdump switches to it automatically after opening the device. Output files are then opened as that user. Pass `-Z root` to keep running as root, or better, write into a directory the default user can write to.
  • Does `-Z` limit which packets the capture can see?
    No. tcpdump opens the capture device as root first and keeps using that open handle after switching user, so it receives exactly the same packets. What changes is what a compromised protocol printer could do: it would run as the unprivileged account rather than as root.

saying these in an interview costs you the question

  • -Z makes tcpdump capture only the named user's traffic.
  • With -Z, tcpdump always creates its output files as root, so any path works.
  • Dropping privileges after opening the device stops the capture from receiving packets.
  • Privilege dropping is pointless because tcpdump only reads packets and never executes them.