Home / Alt manpages / chmod(1)

  • chmod(1)
  • User command
  • linux

Set Linux File Permissions Safely with chmod

One careless sudo chmod -R 777 can expose every secret on a box. Learn to change permissions with chmod precisely, then prove the result with stat. Allow about ten minutes.

  • You need: a shell and a writable test directory. The early examples need no elevated privileges.
  • Tested on: GNU coreutils 9.4, installed here as coreutils 9.4-3ubuntu6.3.
  • The habit: verify the result instead of relying on memory or a shell prompt.

Safety boundary

Permission changes take effect immediately. Work in a scratch directory until the commands make sense. Do not start with sudo chmod -R on a real tree: a broad mode change can expose secrets, break a service, or remove access you need to repair the machine.

1. Check the command and make a scratch file

Confirm the command and version before following a version-specific example:

$ command -v chmod
/usr/bin/chmod
$ chmod --version | head -1
chmod (GNU coreutils) 9.4
$ dpkg-query -W -f='${Package} ${Version}\n' coreutils
coreutils 9.4-3ubuntu6.3

Create a private test directory and a file in it. Holding the path in a variable keeps it visible and makes cleanup less error-prone:

$ workdir="$(mktemp -d)"
$ printf 'permission test\n' > "$workdir/report.txt"
$ ls -l "$workdir/report.txt"
-rw-r--r-- 1 ... report.txt

Your owner, group and timestamps will differ. The first field is the one that matters, and the starting mode is normally shaped by your umask. Get the exact bits with stat:

$ stat -c '%A %a %n' "$workdir/report.txt"
-rw-r--r-- 644 /tmp/tmp.XXXXXXXXXX/report.txt

Tip

The temporary directory name varies by design. Do not copy the displayed path literally if yours differs.

2. Add or remove one permission symbolically

A symbolic mode is a class, an operator and some permissions.

  • Classes: u owner, g the file's group, o everyone else, a all three.
  • Operators: + adds, - removes, = sets the selected classes.

Give the owner execute permission and take write away from the group:

$ chmod u+x,g-w "$workdir/report.txt"
$ stat -c '%A %a %n' "$workdir/report.txt"
-rwxr--r-- 744 /tmp/tmp.XXXXXXXXXX/report.txt
  • On a regular file, x means it can be run as a program. It does not turn a text file into a useful script by itself.
  • On a directory, x means search: a user can reach entries whose names they already know.

Warning

Leave out the class and GNU chmod acts as though you wrote a, except that bits set in the process umask are left alone. That is easy to misread, so name the class explicitly in scripts and security-sensitive changes.

Checkpoint

This scratch file should now report 744. If not, print the variable with printf '%s\n' "$workdir" and make sure you are looking at the same path.

3. Set an exact mode with octal digits

Use octal when the complete permission state should be obvious at a glance. The last three digits are owner, group and others. In each digit, read is 4, write is 2, execute is 1.

$ chmod 640 "$workdir/report.txt"
$ stat -c '%A %a %n' "$workdir/report.txt"
-rw-r----- 640 /tmp/tmp.XXXXXXXXXX/report.txt

Owner reads and writes, group reads, everyone else gets nothing.

An optional leading digit sets the special bits:

  • 4: set-user-ID.
  • 2: set-group-ID.
  • 1: the restricted deletion flag, better known as the sticky bit.

Warning

Do not set set-user-ID or set-group-ID casually. They change the identity a program runs as and need a specific, reviewed reason.

Tip

chmod changes mode bits, never the owner or group. Use your system's ownership tools for that separate job.

4. Lock down a directory

Directories use the same symbols with different meanings:

  • Read lists names.
  • Write creates or removes entries.
  • Execute searches through the directory.

A common private directory mode is 700:

$ mkdir "$workdir/private"
$ chmod 700 "$workdir/private"
$ stat -c '%A %a %n' "$workdir/private"
drwx------ 700 /tmp/tmp.XXXXXXXXXX/private

For a shared project directory, settle the group and policy before using a mode such as 2770. The leading 2 sets set-group-ID on the directory, so new entries inherit the directory's group on systems that support that behaviour. It is a real access-control decision, not a cosmetic one.

The sticky bit on a world-writable directory stops unprivileged users removing or renaming entries unless they own the entry or the directory. It does not make files private.

Warning

A system directory such as /tmp may show mode 1777. Never change a system directory just to make an example match.

5. Use X to keep recursion sane

chmod -R walks a whole tree. The capital X permission adds execute only to directories, or to files that already have execute for at least one user. That is exactly what you want when a tree mixes directories and ordinary data files:

$ mkdir -p "$workdir/tree/subdir"
$ printf 'data\n' > "$workdir/tree/data.txt"
$ chmod 644 "$workdir/tree/data.txt"
$ chmod 755 "$workdir/tree/subdir"
$ chmod -R a+rX "$workdir/tree"
$ stat -c '%A %a %n' "$workdir/tree/data.txt" "$workdir/tree/subdir"
-rw-r--r-- 644 /tmp/tmp.XXXXXXXXXX/tree/data.txt
drwxr-xr-x 755 /tmp/tmp.XXXXXXXXXX/tree/subdir

Checkpoint

The file gained read but not execute; the directory gained search.

Tip

If files and directories need different exact policies, use separate, reviewed commands with find rather than hoping one recursive mode expresses both.

Symlinks behave in two different ways:

  • During recursion, GNU chmod ignores symbolic links it meets.
  • Named on the command line, a symlink is followed and the target file changes, because the link itself has no useful changeable permission bits.

Warning

Check paths with find -type l before a recursive change, and stop if any link leads outside the tree you mean to manage.

6. Copy a mode from a reference file

When one file is the reviewed model, --reference saves retyping its mode:

$ printf 'model\n' > "$workdir/model.txt"
$ printf 'copy\n' > "$workdir/copy.txt"
$ chmod 640 "$workdir/model.txt"
$ chmod --reference="$workdir/model.txt" "$workdir/copy.txt"
$ stat -c '%a %n' "$workdir/model.txt" "$workdir/copy.txt"
640 /tmp/tmp.XXXXXXXXXX/model.txt
640 /tmp/tmp.XXXXXXXXXX/copy.txt

Only the mode is copied, not the owner, group or contents. If the reference is a symlink, GNU chmod follows it.

Warning

Inspect both paths before using a reference supplied by another process or user.

7. Recover from a mistaken change

There is no undo history for file modes.

  • You know the old mode: set it back explicitly, for example chmod 644 FILE.
  • You do not: stop changing things. Recover the intended policy from version-controlled deployment files, package documentation or a known-good peer.
  • Never guess with 777. A permissive mode can hide the fault by exposing the data.

Before a real change, record the paths and modes you are about to touch:

$ find /path/to/tree -maxdepth 2 -printf '%m %p\n' > modes-before.txt
$ chmod -R --changes a+rX /path/to/tree
$ find /path/to/tree -maxdepth 2 -printf '%m %p\n' > modes-after.txt
$ diff -u modes-before.txt modes-after.txt

--changes reports only files whose mode actually changed. The find snapshots are evidence for review, not an automatic rollback. Delete them when you are done if they contain sensitive path information.

For the scratch work in this guide, remove only the directory you created, once you have checked the results:

$ rm -r -- "$workdir"

Warning

This deletion is irreversible. Check printf '%s\n' "$workdir" first, and never substitute a broad path or an unset variable.

Done means

  • Modes understood: you can say whether a symbolic or octal mode changes the classes you intended.
  • Result verified: you checked the mode with stat, not a remembered command.
  • Decisions kept separate: directory search, special bits and recursive changes were each treated as their own access-control choice.
  • Recursion checked: you looked for symlinks first and did not start with sudo.
  • Recovery ready: you know the intended mode, or kept enough evidence to investigate without guessing.