Todo article: Caveats of sending file descriptors over a security boundary
I couldn't think of a good place where to file this idea, but since Wayland is a security boundary and the most familiar to me, this is here for starters.
We should have a peer reviewed article somewhere explaining the security problems around sharing file descriptors between processes which have a security boundary between them. Wayland and DBus come to mind.
This write-up was inspired by wayland#296.
Caveats of sending file descriptors over a security boundary
Most problems stem from the fact that while sharing a file descriptor to another process creates a new independent file descriptor in that other process, both the original and the new file descriptor still point to the same file description. The file description, not the file descriptor, holds important metadata that you might not expect to change from under you.
The only way to create a new file description is the open()
syscall. dup()
and all other fd dupping functions only create a new file descriptor pointing to the original file description.
Here are some problems when you have a file descriptor pointing to a shared file description:
- Regular file contents: The remote party can modify the file contents at any time. Opening a read-only file description and sending that may not be a reliable way to stop the remote side from writing, and only if the local side is the one opening the file.
-
Regular file size: The remote party can change the file size at any time with e.g.
ftruncate()
call. This is particularly hazardous when yoummap()
the fd, as it exposes you to gettingSIGBUS
signals. -
File offset: The classic file read and write operations use the file offset as the position in the file to read from or write to. File offset is stored in file description, and therefore the remote side can change it at any time. Using
pread()
andpwrite()
avoids this problem. -
Open file flags: Flags are stored in the file descriptor, including
O_NONBLOCK
. The remote side can change the flags at any time. E.g. removingO_NONBLOCK
can result in your program stalling unexpectedly on a read or write, as a form of denial of service. -
Polling: The remote side can read and write the fd at any time, making your
poll()
for readable or writable unreliable.
Furthermore, sharing DRM device file descriptors has special caveats:
- DRM master: DRM master status (the ability to drive KMS) is stored with the file description. If you have it, then the remote side can also program whatever it wants to KMS.
- FB IDs: Framebuffer and KMS property blob IDs are tied to the file description. If you have an ID, the remote side can guess that ID or simply read it out from KMS, and at least read its contents back. This can be used for e.g. spying on screen contents. This may or may not be conditional to holding DRM master status.