Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Thu, 14 Dec 2023 23:15:02 +0100
From: Steffen Nurpmeso <>
Subject: XDG_RUNTIME_DIR "misuse" as $TMPDIR (was: Re: 
 budgie-extras: multiple predictable /tmp path issues in various applications)

Matthias Gerstner wrote in
 |this report is about a range of predictable /tmp path issues in various
 |Without the Linux kernel's symlink protection many of these findings
 |where files are created look like they might allow symlink attacks to
 |have files created in arbitrary locations. The Vala file creation calls
 |I looked into are mostly translated into the following system call,
 |    openat(AT_FDCWD, <path>, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0666)
 |Even tough this is missing the `O_NOFOLLOW` flag, symlinks would not be
 |followed, due to the combination of O_CREAT and O_EXCL. I will point
 |out cases where symlink attacks might still be possible in spite of
 |As a quick fix for all of these issues I suggested to use
 |`$XDG_RUNTIME_DIR` instead of /tmp. This directory is private to the
 |logged in user and cannot be manipulated by other users in the system.

This sprang into my eyes as this directory is defined (XDG Base
Directory Specification, Version 0.8, 08th May 2021) (further
indented are "secondaries"):

     $XDG_RUNTIME_DIR defines the base directory relative to which
     user-specific non-essential runtime files and other file
     objects (such as sockets, named pipes, ...) should be stored.
     The directory MUST be owned by the user, and he MUST be the
     only one having read and write access to it. Its Unix access
     mode MUST be 0700.

   The lifetime of the directory MUST be bound to the user being
   logged in. It MUST be created when the user first logs in and
   if the user fully logs out the directory MUST be removed.  If

Here i want to point out that on a "normal" UNIX/POSIX system (as
i understand it: without systemd and without kernel "reaper"
support) this is impossible to achieve because any user can leave
login sessions simply by doing for example

  (sleep 10 </dev/null >/dev/null 2>&1 &)

in which case that sleep(1) is reparented to init(8).

Unfortunately even the largest wealth inside the Linux community
has not managed to update any non-systemd infrastructure to newer
kernels which feature PR_SET_CHILD_SUBREAPER (since Linux 3.4),
ie, the PAM subsystem, or, on my box, for example, inittab-started
agetty then calls /bin/login:

  $ pkginfo -o /bin/login
  Package  File
  shadow   bin/login
  $ prt-get info shadow|grep URL

Shadow tools anyone else has forgotten, but anyway not upgraded.

Ie even "normal UNIX" tools should optionally make use of the
REAPER technique, which is also present on FreeBSD, at least.
I wanted to point this out again.  (Without having looked whether
any such effort was undertaken.  I think not.  Not on FreeBSD,
which' source changes i superficially track.)

So *this requirement alone* cannot be satisfied for real, which is
why my pam_xdg has this is in its manual:

  On Unix systems any "daemonized" program or script is reparented to the
  program running with PID 1, most likely leaving the PAM user session
  without PAM recognizing this.  Yet careless such code may hold or expect
  availability of resources of the session it just left, truly performing
  cleanup when sessions end seems thus unwise.  Since so many PAM modules
  do support session tracking and cleanup readded optional sup-
  port for this.

Ie this is for

 track_sessions will enable session tracking: once the last session ends,
 the user's XDG_RUNTIME_DIR will be recursively removed

but is not by default enabled --- because of the below, and
therefore back to XDG as such:

    the user logs in more than once he should get pointed to the
    same directory, and it is mandatory that the directory
    continues to exist from his first login to his last logout on
    the system, and not removed in between. Files in the directory
    MUST not survive reboot or a full logout/login cycle.  The
    directory MUST be on a local file system and not shared with
    any other system. The directory MUST by fully-featured by the
    standards of the operating system. More specifically, on
    Unix-like operating systems AF_UNIX sockets, symbolic links,
    hard links, proper permissions, file locking, sparse files,
    memory mapping, file change notifications, a reliable hard link
    count must be supported, and no restrictions on the file name
    character set should be imposed. Files in this directory MAY be
    subjected to periodic clean-up. To ensure that your files are
    not removed, they should have their access time timestamp
    modified at least once every 6 hours of monotonic time or the
    'sticky' bit should be set on the file.

   If $XDG_RUNTIME_DIR is not set applications should fall back to
   a replacement directory with similar capabilities and print
   a warning message. Applications should use this directory for
   communication and synchronization purposes and should not place
   larger files in it, since it might reside in runtime memory and
   cannot necessarily be swapped out to disk.

This!  "Should not place larger files"!
In fact it can be expected that /run/user/UID lives in a tmpfs
environment, especially so on Linux, from my point of view at
Quite the opposite i for myself would expect further restrictions
to apply to avoid misuse.  (Like using small tmpfs filesystems.
I am thinking to implement an "exec hook" for pam_xdg to let
people for example mount a specific tmpfs on top of that user dir
once it is created.  Like this

  mount -t tmpfs -o size=1% tmpfs ${rundir} || exit 11

for my personal which creates an overlay environment.
This 1% is still 80 MB!  (It has "meat" in other directories, but
also space constrained, of course.))

I mean Linux or MacOS are not OpenBSD which threw away any $TMPDIR
in favour of a fixed "/tmp".  One can easily create per-user /tmp
via tmpfs mounts as above, for example, even if programs like
OpenSSH's can then not easily be controlled except via "pkill
-TERM" or such upon LID close or other such "shall loose keys"
events, like my

  if command -v ssh-add >/dev/null 2>&1; then
    for a in /tmp/ssh-*/agent.*; do
      [ -e "$a" ] || continue
      act "SSH_AUTH_SOCK=\"$a\" ssh-add -D </dev/null >/dev/null 2>&1 &"
      inc 1 2

which then does not work as easily, or i had to use GnuPG's agent,
which can do this via a simple "pkill -SIG".

All that makes me think whether XDG_RUNTIME_DIR is such a good
target for temporary files, generally speaking.

|Der Kragenbaer,                The moon bear,
|der holt sich munter           he cheerfully and one by one
|einen nach dem anderen runter  wa.ks himself off
|(By Robert Gernhardt)
| Only in December: lightful Dubai COP28 Narendra Modi quote:
|  A small part of humanity has ruthlessly exploited nature.
|  But the entire humanity is bearing the cost of it,
|  especially the inhabitants of the Global South.
|  The selfishness of a few will lead the world into darkness,
|  not just for themselves but for the entire world.
|  [Christians might think of Revelation 11:18
|    The nations were angry, and your wrath has come[.]
|    [.]for destroying those who destroy the earth.
|   But i find the above more kind, and much friendlier]

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.