Understanding /var/empty: The Secure Directory Usage in SSH Daemon (sshd) Configuration


2 views

In Unix-like systems, /var/empty is a special directory commonly used by sshd (OpenSSH daemon) as a secure chroot directory for privilege separation. This directory is intentionally empty and owned by root with strict permissions (typically 755 or 750) to prevent unauthorized access.

The SSH daemon employs /var/empty as part of its security model:

  • Privilege Separation: When sshd starts, it creates an unprivileged child process that handles network communications
  • Chroot Jail: The unprivileged process gets chrooted to /var/empty, limiting its filesystem access
  • Attack Surface Reduction: Even if compromised, the process can't access sensitive system files

Here's how sshd typically configures this in its source code (simplified example):

/* From OpenSSH privilege-sep.c */
#define PRIVSEP_PATH "/var/empty"

void
privsep_preauth_child(void)
{
    if (chroot(PRIVSEP_PATH) != 0)
        fatal("chroot(\"%s\"): %s", PRIVSEP_PATH, strerror(errno));
    
    /* Drop privileges and chdir to root of chroot */
    if (chdir("/") != 0)
        fatal("chdir(\"/\"): %s", strerror(errno));
}

To properly set up this directory on a Linux system:

# Create the directory (if not exists)
sudo mkdir -p /var/empty

# Set correct ownership and permissions
sudo chown root:root /var/empty
sudo chmod 755 /var/empty

# Verify SELinux context if applicable
sudo restorecon -Rv /var/empty

If sshd fails to start due to /var/empty problems:

# Check directory existence and permissions
ls -ld /var/empty

# Typical error in /var/log/secure:
# "Missing privilege separation directory: /var/empty"

# Debug with strace
strace -f -e trace=file,process /usr/sbin/sshd -D -d

Never place any files in /var/empty:

  • An empty directory is security feature, not a bug
  • Some systems use /var/run/sshd or /empty instead
  • Cloud images might need manual creation of this directory

Some Linux distributions implement variations:

# FreeBSD-style (more secure) approach:
mkdir -p /var/empty
chmod 711 /var/empty

# Systemd-based systems might use:
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755

For containerized environments, ensure the directory exists in your Dockerfile:

RUN mkdir -p /var/empty && \
    chown root:root /var/empty && \
    chmod 755 /var/empty

In Unix/Linux systems, /var/empty is a special directory created specifically for sshd (OpenSSH daemon) to implement privilege separation - a security mechanism where processes run with minimal required permissions. This directory is typically:

  • Owned by root:root
  • Set with 711 permissions (drwx--x--x)
  • Empty by design (no files/subdirectories)

When sshd starts, it creates an unprivileged child process that handles network communications. This child process:

int main(int argc, char **argv) {
    /* Privilege separation */
    if (privsep_chroot) {
        if (chroot("/var/empty") == -1)
            fatal("chroot(\"/var/empty\"): %s", strerror(errno));
        if (chdir("/") == -1)
            fatal("chdir(\"/\"): %s", strerror(errno));
    }
    /* Rest of the daemon code */
}

The directory serves three key security purposes:

  1. Chroot jail: Limits filesystem access during privilege separation
  2. Attack surface reduction: Even if compromised, attacker finds no utilities
  3. Process isolation: Prevents privilege escalation attempts

Some systems may need manual setup. Here's how to create it properly:

# mkdir -p /var/empty
# chown root:root /var/empty
# chmod 711 /var/empty
# ls -ld /var/empty
drwx--x--x 2 root root 4096 Jan 1 00:00 /var/empty

Common issues and solutions:

Issue Solution
Directory missing Create as shown above
Wrong permissions chmod 711 /var/empty
Not empty Remove all contents

For SELinux systems, additional context may be needed:

# semanage fcontext -a -t sshd_var_empty_t "/var/empty(/.*)?" 
# restorecon -Rv /var/empty