/tmp or not /tmp?

Post Syndicated from Lennart Poettering original https://0pointer.net/blog/projects/tmp.html

A number of Linux distributions have recently switched (or started
switching) to /tmp on tmpfs by default (ArchLinux, Debian among
others). Other distributions have plans/are discussing doing the same (Ubuntu, OpenSUSE).
Since we believe this is a good idea and it’s good to keep the delta between
the distributions minimal we are proposing
the same for Fedora 18, too
. On Solaris a similar change has already been
implemented in 1994 (and other Unixes have made a similar change long ago,
too). Yet, not all of our software is written in a way that it works nicely
together with /tmp on tmpfs.

Another Fedora
feature (for Fedora 17)
changed the semantics of /tmp for many
system services to make them more secure, by isolating the /tmp namespaces of the
various services. Handling of temporary files in /tmp has been
security sensitive since it has been introduced since it traditionally has been
a world writable, shared namespace and unless all user code safely uses randomized file names
it is vulnerable to DoS attacks and worse.

In this blog story I’d like to shed some light on proper usage of
/tmp and what your Linux application should use for what purpose. We’ll not
discuss why /tmp on tmpfs is a good idea, for that refer to the Fedora feature
page
. Here we’ll just discuss what /tmp should be used for and for
what it shouldn’t be, as well as what should be used instead. All that in order
to make sure your application remains compatible with these new features
introduced to many newer Linux distributions.

/tmp is (as the name suggests) an area where temporary files
applications require during operation may be placed. Of course, temporary files
differ very much in their properties:

  • They can be large, or very small
  • They might be used for sharing between users, or be private to users
  • They might need to be persistent across boots, or very volatile
  • They might need to be machine-local or shared on the network

Traditionally, /tmp has not only been the place where actual
temporary files are stored, but some software used to place (and often still
continues to place) communication primitives such as sockets, FIFOs, shared
memory there as well. Notably X11, but many others too. Usage of world-writable
shared namespaces for communication purposes has always been problematic, since
to establish communication you need stable names, but stable names open the
doors for DoS attacks. This can be corrected partially, by establishing
protected per-app directories for certain services during early boot (like we
do for X11), but this only fixes the problem partially, since this only works
correctly if every package installation is followed by a reboot.

Besides /tmp there are various other places where temporary files
(or other files that traditionally have been stored in /tmp) can be
stored. Here’s a quick overview of the candidates:

  • /tmp, POSIX suggests this is flushed as boot, FHS says that files
    do not need to be persistent between two runs of the application. Old files are
    often cleaned up automatically after a time (“aging”). Usually it is
    recommended to use $TMPDIR if it is set before falling back to /tmp
    directly. As mentioned, this is a tmpfs on many Linuxes/Unixes (and most likely
    will be for most soon), and hence should be used only for small files. It’s
    generally a shared namespace, hence the only APIs for using it should be mkstemp(), mkdtemp() (and friends)
    to be entirely safe.[1] Recently, improvements have been made to
    turn this shared namespace into a private namespace (see above), but that doesn’t
    relieve developers from writing secure code that is also safe if /tmp is a shared
    namespace. Because /tmp is no longer necessarily a shared namespace it
    is generally unsuitable as a location for communication primitives. It is
    machine-private and local. It’s usually fully featured (locking, …). This
    directory is world writable and thus available for both privileged and
    unprivileged code.
  • /var/tmp, according to FHS “more persistent” than /tmp,
    and is less often cleaned up (it’s persistent across reboots, for example). It’s not on a tmpfs, but on a real disk, and
    hence can be used to store much larger files. The same namespace problems apply
    as with /tmp, hence also exclusively use
    mkstemp()/mkdtemp() for this directory. It is also
    automatically cleaned up by time. It is machine-private. It’s not necessarily
    fully featured (no locking, …). This directory is world writable and thus
    available for both privileged and unprivileged code. We suggest to also check
    $TMPDIR before falling back to /var/tmp. That way if
    $TMPDIR is set this overrides usage of both /tmp and
    /var/tmp.
  • /run (traditionally /var/run) where privileged daemons
    can store runtime data, such as communication primitives. This is where your
    daemon should place its sockets. It’s guaranteed to be a shared namespace, but
    is only writable by privileged code and hence very safe to use. This file
    system is guaranteed to be a tmpfs and is hence automatically flushed at boots.
    No automatic clean-up is done beyond that. It is machine-private and local. It
    is fully-featured, and provides all functionality the local OS can provide
    (locking, sockets, …).
  • $XDG_RUNTIME_DIR
    where unprivileged user software can store runtime data, such as communication
    primitives. This is similar to /run but for user applications. It’s a
    user private namespace, and hence very safe to use. It’s cleaned up
    automatically at logout and also is cleaned up by time via “aging”. It is
    machine-private and fully featured. In GLib applications use
    g_get_user_runtime_dir() to query the path of this directory.
  • $XDG_CACHE_HOME
    where unprivileged user software can store non-essential data. It’s a private
    namespace of the user. It might be shared between machines. It is not
    automatically cleaned up, and not fully featured (no locking, and so on, due to
    NFS). In GLib applications use g_get_user_cache_dir() to query this
    directory.
  • $XDG_DOWNLOAD_DIR
    where unprivileged user software can store downloads and downloads in progress.
    It should only be used for downloads, and is a private namespace fo the user,
    but might be shared between machines. It is not automatically cleaned up and
    not fully featured. In GLib applications use g_get_user_special_dir()
    to query the path of this directory.

Now that we have introduced the contestants, here’s a rough guide how we
suggest you (a Linux application developer) pick the right directory to use:

  1. You need a place to put your socket (or other communication primitive) and your code runs privileged: use a subdirectory beneath /run. (Or beneath /var/run for extra compatibility.)
  2. You need a place to put your socket (or other communication primitive) and your code runs unprivileged: use a subdirectory beneath $XDG_RUNTIME_DIR.
  3. You need a place to put your larger downloads and downloads in progress and run unprivileged: use $XDG_DOWNLOAD_DIR.
  4. You need a place to put cache files which should be persistent and run unprivileged: use $XDG_CACHE_HOME.
  5. Nothing of the above applies and you need to place a small file that needs no persistency: use $TMPDIR with a fallback on /tmp. And use mkstemp(), and mkdtemp() and nothing homegrown.
  6. Otherwise use $TMPDIR with a fallback on /var/tmp. Also use mkstemp()/mkdtemp().

Note that these rules above are only suggested by us. These rules
take into account everything we know about this topic and avoid problems with
current and future distributions, as far as we can see them. Please consider
updating your projects to follow these rules, and keep them in mind if you
write new code.

One thing we’d like to stress is that /tmp and /var/tmp
more often than not are actually not the right choice for your usecase. There
are valid uses of these directories, but quite often another directory might
actually be the better place. So, be careful, consider the other options, but
if you do go for /tmp or /var/tmp then at least make sure to
use mkstemp()/mkdtemp().

Thank you for your interest!

Oh, and if you now complain that we don’t understand Unix, and that we are
morons and worse, then please read this again, and you might notice that this
is just a best practice guide, not a specification we have written. Nothing that
introduces anything new, just something that explains how things are.

If you want to complain about the tmp-on-tmpfs or
ServicesPrivateTmp feature, then this is not the right place either,
because this blog post is not really about that. Please direct this to
fedora-devel instead. Thank you very much.

Footnotes

[1] Well, or to turn this around: unless you have a PhD in advanced
Unixology and are not using mkstemp()/mkdtemp() but use
/tmp nonetheless it’s very likely you are writing vulnerable
code.