Skip to content
/linux-syscalls

IPC · Section 2

pipe2(2)

Create a unidirectional pipe and atomically set O_CLOEXEC / O_NONBLOCK on the resulting descriptors.

Signature

#include <unistd.h>

int pipe2(int [2] pipefd, int flags);
pipefd
Out-parameter: a 2-element int array. The kernel writes the read end to pipefd[0] and the write end to pipefd[1].
flags
Bitwise OR of O_CLOEXEC (close on exec), O_NONBLOCK (non-blocking I/O), O_DIRECT (packet mode — each write becomes a discrete read).

Description

pipe2() creates a unidirectional data channel — a pair of file descriptors where data written to pipefd[1] (the write end) is read from pipefd[0] (the read end), in FIFO order. The kernel buffers up to /proc/sys/fs/pipe-max-size bytes (default 1 MiB; per-pipe size adjustable via fcntl(F_SETPIPE_SZ)). When the last write-end descriptor is closed, subsequent reads return 0 (EOF); when the last read-end descriptor is closed, writes to the write end raise SIGPIPE and return -1/EPIPE. The flags argument lets the caller set O_CLOEXEC and/or O_NONBLOCK atomically at create time — this is the whole reason pipe2() exists; the original pipe() forced a separate fcntl() that could race with a concurrent fork+exec.

Architecture mapping

ArchitectureNumberABIEntry point
x86 (i386)331i386sys_pipe2
x64 (x86_64)293commonsys_pipe2
ARM64 (aarch64)59sys_pipe2

Kernel history

Introduced in Linux 2.6.27.

  1. 2.6.27

    pipe2() was added in 2.6.27 alongside the broader CLOEXEC-atomic family (accept4, dup3, socket SOCK_CLOEXEC, signalfd4, etc.) to close the long-standing race where fcntl(F_SETFD, FD_CLOEXEC) after a syscall could be observed mid-execve by a fork sibling.

  2. 3.4

    O_DIRECT was added so callers can opt into packet-mode pipes (no message-boundary coalescing). Useful for protocols like dbus that need each write() to be a distinct read().

seccomp & containers

Docker default profile

Allowed

Podman default profile

Allowed

pipe() and pipe2() are on every default profile. Effectively un-blockable — every shell pipeline, every async stdout capture, every supervisor's signal pipe relies on them. No useful argument-level filtering.

libseccomp

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(pipe),  0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(pipe2), 0);

strace example

$ strace -e pipe2 bash -c 'echo a | wc -c'
pipe2([3, 4], O_CLOEXEC)                = 0

pipe2() returns the two descriptors as an array — strace prints them as [3, 4]. Following both ends with -y and -e read,write,pipe2 reconstructs the entire pipe traffic. A program with hung pipes shows as a writer blocked on write(pipefd[1], …) and no matching read() on the other side — common in shell-pipeline diagnoses.

Security & observability

pipe() / pipe2() are the underlying mechanism of CVE-2022-0847 'Dirty Pipe' — a kernel bug where the splice path mis-merged pipe pages into the page cache, letting unprivileged users overwrite read-only files. The fix landed in 5.16.11/5.15.25/5.10.102. The CVE is patched in any kernel from mid-2022; verify your /proc/version. Beyond that, pipes are rarely a direct security signal — too universal to monitor usefully. For container forensics, /proc/<pid>/fd inspection shows pipe inodes that can be cross-referenced with the peer process to map IPC topology.

Errors

EFAULT
pipefd points outside the calling process's address space.
EINVAL
Invalid flags.
EMFILE
Per-process fd limit reached (each pipe consumes two descriptors).
ENFILE
System-wide fd limit reached.

Flags

O_CLOEXEC
02000000
Set close-on-exec on both descriptors. Essential — any pipe used internally that isn't supposed to leak to a forked child must have CLOEXEC.
O_NONBLOCK
04000
Both ends become non-blocking. read() returns EAGAIN when empty; write() returns EAGAIN when the buffer is full.
O_DIRECT
040000
Packet-mode pipe (since 3.4). Each write() becomes a separate read() boundary — useful for record-oriented protocols where you don't want the kernel to coalesce.

Related syscalls