Signal9Signal9 — home
online
all lessons

Virtual Filesystems: /proc, /sys and tmpfs

Intermediate20 min5 steps
What you'll learn
  • Recognise proc, sysfs, tmpfs and devtmpfs mounts and what each holds
  • Read live kernel and process information from /proc and /sys
  • Mount a tmpfs with a size cap, owner and mode, and make it persistent in fstab
  • Hide other users' processes with the hidepid option, now and at boot
  1. Filesystems with no disk behind them

    Recognise the virtual filesystems on a running system and what each one is for.

    Most filesystems store data on a disk. A virtual filesystem stores nothing on disk at all. The kernel makes its contents up on the fly, or keeps them in memory, and presents them through the same open, read and write calls as ordinary files. That's the Unix idea of "everything is a file" carried to its conclusion: process tables, kernel settings and device lists all become files you can read with cat.

    You'll meet four constantly:

    • proc at /proc: one directory per running process, plus kernel state and tunables under /proc/sys.
    • sysfs at /sys: the kernel's model of devices, drivers and buses.
    • tmpfs: a filesystem that lives in RAM (and swap). /dev/shm and often /run are tmpfs, and you can mount your own.
    • devtmpfs at /dev: device nodes the kernel creates for hardware it finds.
    findmnt -t proc,sysfs,tmpfs,devtmpfs -o TARGET,FSTYPE,OPTIONS | head -8
    TARGET           FSTYPE OPTIONS
    /proc            proc   rw,nosuid,nodev,noexec,relatime
    /dev             tmpfs  rw,nosuid,size=65536k,mode=755
    └─/dev/shm       tmpfs  rw,nosuid,nodev,noexec,relatime,size=65536k
    /sys             sysfs  rw,nosuid,nodev,noexec,relatime
    └─/sys/fs/cgroup tmpfs  rw,nosuid,nodev,noexec,relatime,mode=755
    -t TYPES
    Show only mounts of these filesystem types.
    -o COLS
    Choose the output columns.
    findmnt filters by type with -t. Every row here is a mount that occupies no disk space. The OPTIONS column matters: tmpfs mounts show their size= cap, and /proc shows its hardening options, which you'll change later.

    Check yourself

    Does writing a 50 MB file to a tmpfs mount use disk space?

  2. Reading the kernel through /proc and /sys

    Pull live information from /proc and /sys with ordinary file tools.

    Because these are files, the tools you already know are the interface. cat reads a value and echo into a writable file changes a setting at once. Changes made this way last until reboot, which is why permanent kernel settings go through sysctl.d files, a topic of its own. Here the goal is to get comfortable reading.

    grep -E '^(MemTotal|MemAvailable|SwapTotal):' /proc/meminfo
    MemTotal:       16480968 kB
    MemAvailable:   15644964 kB
    SwapTotal:             0 kB
    /proc/meminfo is where free gets its numbers. MemAvailable is the honest answer to "how much memory can a new program get", because it counts cache that the kernel can reclaim.
    grep -E '^(Name|State|PPid|VmRSS):' /proc/self/status
    Name:	grep
    State:	R (running)
    PPid:	22
    VmRSS:	    2248 kB
    Every process has a directory named after its PID, and /proc/self always points at the process doing the reading, here grep itself. status shows its name, state, parent PID and resident memory. This is the raw data ps and top format for you.
    ls /sys/class/net && cat /sys/class/net/lo/mtu
    eth0
    lo
    65536
    sysfs groups devices by class. Each network interface has a directory full of one-value files. lo's MTU is 65536. Writing a new value into such a file changes it live, the same way ip link set would.

    A useful way to keep the two apart: /proc is about processes and the running kernel, and /sys is about devices. When you need to know what a program is doing, its open files (/proc/PID/fd), its limits (/proc/PID/limits) or its environment, you look in /proc. When you need to know what hardware the kernel found, which driver claimed it, or a device setting such as an interface MTU or a disk's scheduler, you look in /sys. Many command-line tools are thin readers of these two trees.

    Check yourself

    Which file shows the status of the process that reads it, whatever its PID?

  3. Mounting a tmpfs with a size, an owner and a mode

    Create a RAM-backed scratch area with the right limits and ownership, now and at boot.

    An unlimited tmpfs can grow until it eats half of RAM, its default cap, so you always give it a size. Its root directory is created fresh at every mount, so ownership and permissions have to be set as mount options (uid=, gid=, mode=). A chown after mounting works until the next reboot and then silently disappears.

    id app >/dev/null 2>&1 || useradd -m -s /bin/bash app; mkdir -p /srv/scratch && mount -t tmpfs -o size=64M,uid=app,gid=app,mode=0750 tmpfs /srv/scratch && findmnt /srv/scratch && stat -c '%U %G %a' /srv/scratch
    TARGET       SOURCE FSTYPE OPTIONS
    /srv/scratch tmpfs  tmpfs  rw,relatime,size=65536k,mode=750,uid=1001,gid=1001
    app app 750
    -t tmpfs
    The filesystem type.
    size=64M
    Cap the filesystem at 64 MiB.
    uid=/gid=
    Owner and group of the root directory.
    mode=0750
    Permissions of the root directory.
    This mounts a 64 MiB tmpfs owned by app with mode 750. findmnt reports the size as 65536k, the kernel's own unit, and stat confirms the owner and mode came from the options.
    umount /srv/scratch && echo 'tmpfs  /srv/scratch  tmpfs  size=64M,uid=app,gid=app,mode=0750  0 0' >> /etc/fstab && mount /srv/scratch && findmnt --fstab /srv/scratch
    TARGET       SOURCE FSTYPE OPTIONS
    /srv/scratch tmpfs  tmpfs  size=64M,uid=app,gid=app,mode=0750
    --fstab
    Show the entry from /etc/fstab instead of the live mount.
    To make it permanent, add an fstab line and mount from it. If mount /srv/scratch works with no other arguments, the line is valid, and you've proved it before a reboot depends on it. For tmpfs the first field is only a label. tmpfs or none are conventional.

    Check yourself

    You mounted a tmpfs and then ran chown app /srv/scratch. Who owns /srv/scratch after a reboot?

  4. Hiding other users' processes with hidepid

    Remount /proc so ordinary users only see their own processes, and keep it that way.

    By default any user can list every process on the box and read its command line, which can include passwords passed as arguments, internal hostnames and file paths. procfs has a mount option, hidepid, that fixes this: with hidepid=invisible (older spelling: hidepid=2) an unprivileged user can only see their own process directories. root still sees everything.

    id intern >/dev/null 2>&1 || useradd -m -s /bin/bash intern; runuser -u intern -- ls /proc | grep -c '^[0-9]'
    5
    Before the change: intern counts every PID directory on the system, including root's. The number depends on what's running, but it's more than intern's own handful.
    mount -o remount,hidepid=invisible /proc && findmnt -n -o OPTIONS /proc && runuser -u intern -- ls /proc | grep -c '^[0-9]'
    rw,nosuid,nodev,noexec,relatime,hidepid=invisible
    1
    -o remount,OPTS
    Change the options of an already-mounted filesystem.
    remount changes the options of the mounted /proc in place. The count drops to intern's own processes, here just the ls itself. For persistence, add proc /proc proc defaults,hidepid=invisible 0 0 to /etc/fstab, then mount -o remount /proc re-reads it.
    mount -o remount,hidepid=0 /proc && findmnt -n -o OPTIONS /proc
    rw,nosuid,nodev,noexec,relatime
    hidepid=0
    Show all processes to everyone again (the default).
    This puts the lesson box back the way it was, so the practice step starts from the default. On a real server you'd leave hidepid on.

    Check yourself

    Which /proc mount option lets members of the group monitor see all processes while hidepid=invisible is on?

  5. Now do it — in your live terminal

    Configure a tmpfs and harden /proc yourself on the sandbox to your right.

    Put it together on the sandbox. For each step, write down what findmnt or stat should print before you press Enter, then compare. Keep the habit of writing the fstab line first and mounting from it. That's how you know a reboot won't surprise you, and it's exactly what the lab grades: the live mount and the fstab entry, which have to agree with each other.

    mkdir -p /mnt/fast && echo 'tmpfs /mnt/fast tmpfs size=32M,mode=1777 0 0' >> /etc/fstab && mount /mnt/fast && df -h /mnt/fast
    df should show a 32M filesystem of type tmpfs.
    echo 'proc /proc proc defaults,hidepid=invisible 0 0' >> /etc/fstab && mount -o remount /proc && findmnt -n -o OPTIONS /proc
    The options should now include hidepid=invisible, read from fstab.
    useradd -m peek; runuser -u peek -- ps -e | wc -l
    A brand-new user should see only a couple of lines: their own processes.
Recap
  • Virtual filesystems have no disk behind them: proc and sysfs are generated by the kernel, and tmpfs lives in RAM.
  • /proc holds a directory per process plus kernel state and tunables; /sys models devices. Read them with cat and grep.
  • Always give a tmpfs a size=, and set ownership with uid=, gid= and mode= mount options, because the root directory is recreated at every mount.
  • hidepid=invisible on /proc limits ordinary users to their own processes; gid= exempts a monitoring group.
  • Write the fstab line first, then mount from it, so the live state and the boot state can't disagree.
Virtual filesystems at a glance
Command / optionWhat it does
findmnt -t proc,sysfs,tmpfsList virtual filesystem mounts and their options
/proc/PID/status, /proc/meminfoProcess details and memory figures
/sys/class/net/IFACE/One-value files describing a network interface
mount -t tmpfs -o size=64M,uid=U,mode=0750 tmpfs DIRRAM-backed mount with a cap, owner and mode
mount -o remount,hidepid=invisible /procHide other users' processes now
findmnt --fstab DIRCheck what fstab will mount at boot