Troubleshooting and Fixing /dev/null Becoming a Regular File on Linux Production Servers


3 views

When /dev/null transforms from a character special device into a regular file, it can cripple critical system operations. This pseudo-device serves as a data sink where processes can write output they want to discard, and reads from it return EOF immediately. Major system components like sshd rely on its proper functioning.

In this case, we encountered multiple concerning behaviors:

# Attempting to check file type:
ls -l /dev/null
-rw-r--r-- 1 root root 0 Aug 10 14:30 /dev/null  # Should show 'c' for character device

# Service failure symptoms:
journalctl -u sshd
... failed to open /dev/null: Invalid argument ...

The most puzzling aspect was the immediate recreation of /dev/null as a regular file after deletion. Through investigation, we identified several potential culprits:

  1. udev rules automatically recreating device nodes
  2. Systemd-tmpfiles maintaining persistent files
  3. Security software with abnormal monitoring behaviors

Here's the complete procedure that resolved the issue:

# First, identify what's recreating the file
inotifywait -m /dev -e create &
# In another terminal
rm -f /dev/null

# If udev is responsible (common case):
systemctl stop systemd-udevd
rm -f /dev/null
mknod /dev/null c 1 3
chmod 666 /dev/null
systemctl start systemd-udevd

# Alternative approach if tmpfiles is involved:
echo "d /dev/null 0666 root root -" > /etc/tmpfiles.d/null.conf
systemd-tmpfiles --create

To prevent recurrence, consider these hardening steps:

# Create a persistent configuration
cat > /etc/udev/rules.d/80-null.rules << EOF
KERNEL=="null", SUBSYSTEM=="mem", ACTION=="add", \
    RUN+="/bin/mknod -m 0666 /dev/null c 1 3"
EOF

# Verify after reboot
ls -l /dev/null | grep '^c'

Many system components assume /dev/null behaves as a character device:

  • SSH daemon uses it for session handling
  • Cron jobs redirect output to it
  • System services rely on it for proper stderr handling

A regular file causes subtle but severe failures because:

  1. Writes consume disk space instead of being discarded
  2. Read operations may hang or return unexpected data
  3. File permissions may restrict access

The /dev/null device file plays a fundamental role in Unix-like systems as the black hole for data. When corrupted into a regular file, it breaks core system functions including SSH authentication (as many services redirect output to null). This manifests as failed logins and service crashes.

When observing immediate recreation after deletion, suspect these common culprits:

  • udev rules auto-creating device nodes
  • systemd-tmpfiles restoring configurations
  • Security frameworks like SELinux enforcing baseline states
# Monitor file creation in real-time
sudo inotifywait -m /dev -e create | grep null

# Check active udev rules
grep -r "null" /etc/udev/rules.d/

# Audit tmpfiles configuration
grep -r "null" /usr/lib/tmpfiles.d/ /etc/tmpfiles.d/

When standard recreation prevention fails, use this atomic approach:

# Create temporary bind mount
mount --bind /dev/null /dev/null.bak

# Remove corrupted file and create proper device
rm -f /dev/null && mknod -m 666 /dev/null c 1 3

# Verify major/minor numbers
ls -l /dev/null | grep "crw-rw-rw-.*1,.*3"

Add these measures to prevent recurrence:

# Example udev rule override
echo 'KERNEL=="null", SUBSYSTEM=="mem", MODE="0666"' > /etc/udev/rules.d/99-null.rules

# Systemd tmpfiles exclusion
echo 'x /dev/null' > /etc/tmpfiles.d/no-null-recreate.conf

After restoring /dev/null, SSH may still fail due to:

  • Accumulated failed authentication attempts in logs
  • Session cleanup processes hanging

Force a clean restart with:

systemctl kill --signal=SIGKILL sshd
systemctl restart sshd

Common triggers for /dev/null corruption include:

  • Disk errors affecting /dev filesystem
  • Buggy storage drivers during live migration
  • Malicious overwrites (though rare in practice)
# Confirm device type
file /dev/null | grep "character special"

# Test write/read functionality
echo "test" > /dev/null && echo $? # Should return 0
cat /dev/null | wc -c # Should return 0