fanf: (Default)
[personal profile] fanf

https://dotat.at/@/2024-10-22-tmp.html

I commented on Lobsters that /tmp is usually a bad idea, which caused some surprise. I suppose /tmp security bugs were common in the 1990s when I was learning Unix, but they are pretty rare now so I can see why less grizzled hackers might not be familiar with the problems.

I guess that's some kind of success, but sadly the fixes have left behind a lot of scar tissue because they didn't address the underlying problem: /tmp should not exist.

It’s a bad idea because it’s shared global mutable state that crosses security boundaries. There’s a ton of complexity at all levels of unix (filesystems, kernel APIs, libc, shell, admin scripts) that only exists as a workaround for the dangers caused by making /tmp shared.

sticky bit

I think the earliest and lowest-level workaround is the sticky bit.

The sticky bit is mode bit 01000 in unix file permissions. It is printed as the t instead of x in rwt.

    drwxrwxrwt  5 root  wheel  160 Oct 22 10:22 /tmp/

Originally in the 1970s the sticky bit was invented to speed up frequently-used programs such as the shell: the sticky bit indicated to the kernel that the executable file should stick in core. This functionality was made obsolete in the 1980s by filesystem page caches.

The sticky bit was re-used to mean something else on directories, to fix a security problem with /tmp.

On unix, permission to delete a file depends on write access to the directory containing the file, independent of the file's own permissions.

So if a directory (such as /tmp) is world-writable, anyone can delete any file in it.

This means /tmp was vulnerable to all sorts of accidental or malicious trouble caused by users deleting each others' files.

To fix this, a file in a sticky directory may only be removed or renamed by a user if the user has write permission for the directory and the user is the owner of the file, the owner of the directory, or the super-user.

tmp stupidity in C

POSIX used to provide 5 (five!) ways to create a temporary file, three of which (most of them!) you must never use and which have subsequently been deprecated -- except the do-not-use footgun tmpnam which is still part of the C standard. Two more safe functions have subsequently been added to support more complicated situations.

There are so many dangerous API design problems in these functions! I'm not going to waste time roasting them in detail because I can cover the important points by discussing ...

mkstemp and mkdtemp

The purpose of all these functions is to create a temporary file (or directory) that doesn't collide with other concurrent activity.

When you are creating a file in /tmp the risk is that another malicious user can make you open a file under their control. To avoid this vulnerability, you (or rather mkstemp) must:

  • Generate an unpredictable filename.

    It isn't enough for the filename to be unique, it must contain sufficient secure randomness that an adversary can't win a race and interfere.

  • Open the file with O_CREAT | O_EXCL.

    This ensures the file has not already been created by another friendly or malicious process, without any time-of-check / time-of-use vulnerabilities. And it ensures that the file isn't a symlink pointing somewhere an attacker wants you to accidentally corrupt.

  • Retry if open fails with EEXIST.

    Together with the randomness in the name, this avoids denial-of-service vulnerabilites.

This is intricate and not entirely obvious, as you can tell from all the previous failed attempts at functions that didn't create temporary files safely.

mktemp in shell

The mktemp(1) command is a wrapper around mkstemp(3). (Slightly confusingly it isn't a wrapper around mktemp(3) because that would be unsafe.) It was introduced by OpenBSD and it's widely supported though it isn't yet in POSIX. Its manual page includes a nice rationale:

The mktemp utility is provided to allow shell scripts to safely use temporary files. Traditionally, many shell scripts take the name of the program with the pid as a suffix and use that as a temporary file name. This kind of naming scheme is predictable and the race condition it creates is easy for an attacker to win. A safer, though still inferior, approach is to make a temporary directory using the same naming scheme. While this does allow one to guarantee that a temporary file will not be subverted, it still allows a simple denial of service attack. For these reasons it is suggested that mktemp be used instead.

Although shell scripts can't avoid using the temporary file by name, mktemp(1) is safe because it creates the file securely and an attacker can't interfere with it after that point. It's OK to re-open a file that you know is yours.

tmp cleanup

The last item on my list of regrets is "admin scripts", an oblique reference to /tmp cleanup jobs.

By its nature /tmp tends to accumulate junk, so it was common to have cron jobs that would delete old files. (Less common now that computers are much bigger.)

These scripts tended to have problems with time-of-check / time-of-use vulnerabilities, careless handling of symlinks, and pulling the rug out from under long-running programs that foolishly used /tmp. (Lots more reasons these scripts are now less common!)

tmp remedy

So I've spent dozens of paragraphs outlining bugs and complications related to /tmp. All of them could have been avoided if /tmp did not exist, and everything would have been simpler as a result.

So where should temporary files go, if not in /tmp?

There should be per-user temporary directories. In fact, on modern systems there are per-user temporary directories! But this solution came several decades too late.

If you have per-user $TMPDIR then temporary filenames can safely be created using the simple mechanisms described in the mktemp(1) rationale or used by the old deprecated C functions. There's no need to defend against an attacker who doesn't have sufficient access to mount an attack! There's no need for sticky directories because there aren't any world-writable directories.

There's a minor wrinkle that setuid programs would have to be more careful about how they create temporary files, but setuid programs have to be more careful about everything.

tmp rationale

So why wasn't per-user $TMPDIR a thing back in the day?

Probably the main reason was path-dependence: /tmp was created and in wide use before its problems became apparent, at which point it was difficult to deprecate.

There are reasons 1990-ish-you didn't want $TMPDIR to be in your home directory:

  • $HOME might be on NFS so a local $TMPDIR might be faster

  • $TMPDIR can be a way to get workspace beyond your disk quota

The fix, way back when, should have been for login(8) to create a per-user temporary directory in a sensible place before it drops privilege, and set $TMPDIR so the user's shell and child processes can find it.

Oh well, think of all the excitement we would have missed if insecure temporary file vulnerabilites had not been a thing!

This account has disabled anonymous posting.
(will be screened if not on Access List)
(will be screened if not on Access List)
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org

June 2025

S M T W T F S
1234567
8 91011121314
15161718192021
22232425262728
2930     

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated 2025-06-12 10:18
Powered by Dreamwidth Studios