File & I/O · Section 2
close(2)
Release a file descriptor.
Signature
#include <unistd.h>
int close(int fd);- fd
- File descriptor to close. After a successful return, fd is invalid in this process; do not use it again.
Description
close() releases the file descriptor fd, allowing it to be reused by the next open()/socket()/pipe()/etc. call. If fd is the last reference to its underlying open-file description, the kernel releases the file as well — flushing buffered writes, releasing record locks held by this process, removing memory mappings created by mmap on the descriptor, and (for sockets) starting the TCP shutdown sequence. close() returns 0 on success and -1 with errno set on failure. The traditional advice to retry close() on EINTR is wrong on Linux: once close() returns, the descriptor is gone regardless of the return value. The return value reports an asynchronous error (typically a deferred write-back failure) but does not give you a second chance to close.
Architecture mapping
| Architecture | Number | ABI | Entry point |
|---|---|---|---|
| x86 (i386) | 6 | i386 | sys_close |
| x64 (x86_64) | 3 | common | sys_close |
| ARM64 (aarch64) | 57 | — | sys_close |
Kernel history
Introduced in Linux 1.0.
1.0
close() has been part of Linux since 1.0 with POSIX.1 semantics, modulo the Linux-specific EINTR rule above.
5.9
close_range(first, last, flags) was added to close a contiguous range of file descriptors in one syscall — useful in post-fork() child code that wants to close everything except a small allow-list, replacing the slow /proc/self/fd-scan pattern.
seccomp & containers
Docker default profile
Allowed
Podman default profile
Allowed
close() is on every default profile and is impossible to block usefully: every program closes descriptors. The interesting filtering is on close_range() and the CLOSE_RANGE_UNSHARE flag (Linux 5.11+), which can be used to selectively close descriptors after sharing the fd table — restricting it makes some sandboxing patterns awkward. For normal workloads, allow both.
libseccomp
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);strace example
$ strace -e openat,close cat /etc/hostname > /dev/null
openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3
close(3) = 0
close(1) = 0close() output is one-line and uninteresting on its own; pair it with openat() in the -e set to see the full open/close lifecycle. A process leaking fds shows up as long runs of openat() without matching close() — easy to spot in strace -c summary mode.
Security & observability
close() itself is rarely a primary security event, but its absence is interesting: a process that opens sensitive files (/etc/shadow, /proc/<pid>/mem) and never closes them may be staging an exploit. fd accounting via /proc/<pid>/fd is the easier audit surface. The one real footgun is the EINTR retry pattern — pre-2008 code that loops on close() can close a file descriptor that the kernel has already reissued to another thread, leaking sensitive data to the wrong consumer. Always treat close() as a fire-and-forget on Linux.
Errors
- EBADF
- fd is not a valid open descriptor.
- EINTR
- On Linux, EINTR after close() means the descriptor has already been released — DO NOT retry the close with the same fd. (Other Unixes behave differently; Linux semantics are documented in close(2).)
- EIO
- An I/O error occurred — typically a deferred write-back failure surfaced at close time. The data was lost; the fd is still closed.
- ENOSPC
- On NFS and some other filesystems, close-time write-back can surface ENOSPC even though the original write() returned success.