Linux's abstract namespace for Unix domain sockets

August 19, 2015

The address of ordinary Unix domain sockets for servers is the file name of a socket file that actually appears in the filesystem. This is pleasantly Unix-y on the surface but winds up requiring you to do a bunch of bureaucracy to manage these socket files, and the socket files by themselves don't actually do anything that would make it useful for them to be in the filesystem; you can't interact with them and the server behind them with normal Unix file tools, for example.

Linux offers you a second choice. Rather than dealing with socket files in the filesystem, you can use names in an abstract (socket) namespace. Each name must be unique, but the namespace is otherwise flat and unstructured, and you can call your server socket whatever you want. Conveniently and unlike socket files, abstract names vanish when the socket is closed (either by you or because your program exited).

Apart from being Linux-only, the abstract socket namespace suffers from two limitations: you have to find a way to get a unique name and it has no permissions. With regular socket files you can use regular Unix file and directory permissions to insure that only you can talk to your server socket. With abstract socket names, anyone who knows or can find the name can connect to your server. If this matters you will have to do access control yourself.

(One approach is to use getsockopt() with SO_PEERCRED to get the UID and so on of the client connecting to you. SO_PEERCRED is Linux specific as far as I know, but then so is the abstract socket namespace.)

Lsof and other tools conventionally represent socket names in the abstract socket namespace by putting an @ in front of them. This is not actually how they're specified at the C API level, but it's a distinct marker and some higher level tools follow it for, eg, specifying socket names.

(The Go net package is one such piece of software.)

As far as picking unique names goes, one trick many programs seem to use is to use whatever filename they would be using if they didn't have the abstract socket namespace available. This gives you a convenient way of expressing, eg, per-user sockets; you can just give it a name based on the user's home directory. Other programs use a hierarchical namespace of their own; Ubuntu's upstart listens on the abstract socket name '/com/ubuntu/upstart', for example.

(For personal hacks, you can of course just make up your own little short names. Little hacks don't need a big process; that's the whole attraction of the abstract namespace.)

Now that I've poked around this, I'm going to use it for future little Linux-only hacks because checking permissions (if it's even necessary) is a lot more convenient than the whole hassle of dealing with socket files. For things I write that are intended to be portable, I don't see much point; portable code has to deal with socket files so I might as well use regular Unix domain socket names and socket files all the time.

(A bunch of my personal hacks are de facto Linux only because my desktop machines are Linux. I'll regret that laziness if I ever try to move my desktop environment to FreeBSD or the like, but that seems highly unlikely at the moment.)


Comments on this page:

By Lennart at 2015-08-19 06:24:29:

abstract namespace sockets are highly problematic: they define a shared namespace, meaning any process can pick any socket name that is not taken yet, regardless of any privileges. That means that when picking a socket name in the abstract namespace you only have two safe options:

a) you do so during early boot, before the first user is allowed to log in.

or

b) you strictly use randomized names

However, if you use guessable names during later runtime, then you make your code vulnerable to DoS attacks and worse, given that any unprivileged client might have taken the name before you and thus make your code fail...

Ultimately this already makes these types of sockets close to useless.

However, it gets even worse if you start thinking about containers and network namespacing: AF_UNIX sockets in the abstract namespace are subject to CLONE_NEWNET network namespaces. However, AF_UNIX sockets in the file system are not subject to network namespaces, but are purely subject to visibility in the file system. This is really nasty actually as this means that on containers that run in the same shared network namespace as the host (which is often desirable since it allows you to avoid IP setup, masquerading, ...) even abstract namespace local IPC gets shared! Thus software inside the container and on the host will fight over socket names and can connect to each other.

Long story short: don't ever use them AF_UNIX abstract namespace sockets. They are awful. Stick to file system AF_UNIX sockets. Otherwise you are likely to make your code vulnerable to DoS attacks and break in containers.

Lennart

By cks at 2015-08-20 15:33:14:

Given the issues with the abstract namespace, I wonder why various Linux programs seem to like them. My machines seem to have a fair number of active sockets with abstract names, although to be fair they're almost all either DBus or the X server (Chrome also appears to use one).

Written on 19 August 2015.
« Getting dd's skip and seek straight once and for all
Using abstract namespace Unix domain sockets and SO_PEERCRED in Python »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Aug 19 02:17:35 2015
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.