Skip to content

Skip filesystem checks for abstract namespace unix sockets - #3718

Merged
benoitc merged 1 commit into
benoitc:masterfrom
afonsojanu:fix/unix-socket-abstract-namespace
Aug 31, 2026
Merged

benoitc merged 1 commit into
benoitc:masterfrom
afonsojanu:fix/unix-socket-abstract-namespace

Conversation

@afonsojanu

Copy link
Copy Markdown
Contributor

Fixes #2699.

Linux supports abstract namespace unix sockets, whose address starts with a null byte and has no presence on the filesystem. Binding gunicorn to one currently crashes before the server starts:

bind = "unix:\0my-socket"
ValueError: embedded null byte

UnixSocket.__init__ always calls os.stat() on the address to check for and remove a stale socket file from a previous run. os.stat() rejects any path with an embedded null byte outright, so it never has a chance to return ENOENT the way a genuinely missing path would, and the ValueError propagates straight out of the constructor.

bind() has the same problem a step later: it unconditionally chowns the socket path, which would fail the same way once the stat call above stops being in the way.

Since abstract sockets don't exist on the filesystem, there's nothing to stat, remove, or chown for them, so both operations are skipped when the address starts with a null byte.

Added tests covering:

  • the abstract-namespace case skips os.stat()
  • a normal filesystem path still goes through the existing stat/remove logic
  • bind() skips chown() for an abstract-namespace address

Ran the full test suite plus pylint and pycodestyle on the touched files, all clean.

Linux supports abstract namespace unix sockets, whose address starts
with a null byte and has no presence on the filesystem. Binding
gunicorn to one (e.g. bind = "unix:\0my-socket") currently crashes
before the server even starts:

  ValueError: embedded null byte

This happens because UnixSocket.__init__ always calls os.stat() on
the address to check for and remove a stale socket file left over
from a previous run. os.stat() rejects paths containing an embedded
null byte outright, so it never gets a chance to return ENOENT the
way a normal missing path would.

The same problem exists in bind(), which unconditionally chowns the
socket path afterward. That call would fail the same way once the
os.stat() call above is no longer in the way.

Since abstract sockets don't exist on the filesystem, there's nothing
to stat, remove, or chown for them, so both operations are skipped
when the address starts with a null byte.
@benoitc
benoitc merged commit 9178adc into benoitc:master Aug 31, 2026
12 checks passed
@benoitc

benoitc commented Aug 31, 2026

Copy link
Copy Markdown
Owner

Thanks @afonsojanu, merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gunicorn fail to bind abstract unix domain socket

2 participants