Chapter 06Lesson 02~65 minutes

chmod: Symbolic and Octal Permissions

chmod changes mode bits; it does not determine what the correct policy should be. Good permission work starts from an intended access contract, applies the smallest change, and verifies the resulting behavior. This lesson covers both symbolic and octal forms, including the recursion hazards that commonly break deployments.

BeginnerchmodSafe bulk changes

Learning objectives

By the end of this lesson

  • Construct symbolic mode clauses with u, g, o, a, +, -, and =.
  • Translate common modes between symbolic and octal notation.
  • Use conditional execute X and --reference appropriately.
  • Avoid unsafe chmod -R patterns by treating files and directories separately.
  • Implement and verify a deployment-tree permission policy.

1. Symbolic chmod expresses a relative policy change

A symbolic clause has the conceptual form who operation permissions. The who set is owner (u), group (g), other (o), or all (a). The operation adds (+), removes (-), or assigns exactly (=) the selected bits.

How a symbolic chmod clause is interpreted
flowchart LR
  W["Who?
u g o a"] --> O["Operation?
+ - ="] O --> B["Bits?
r w x X s t"] B --> M["Modify the existing mode"] M --> V["Verify resulting access"]
file="$HOME/devops-academy/linux/chapter06/lesson02/example.txt"
mkdir -p -- "$(dirname -- "$file")"
printf 'release metadata
' > "$file"

chmod u=rw,go=r -- "$file"   # exact: 0644
chmod g+w -- "$file"         # add group write: 0664
chmod o-r -- "$file"         # remove other read: 0660
chmod a-rwx,u=rw,g=r -- "$file"  # explicit reset: 0640
stat -c '%A %a %n' -- "$file"

When who is omitted, the current umask influences which classes are changed. Production automation should normally state the classes explicitly so behavior does not depend on the invoking environment.

2. Octal modes assign an exact bit pattern

An octal triplet assigns owner, group, and other permissions. Each digit is the sum of read 4, write 2, and execute 1. A leading fourth digit represents special bits, covered in Lesson 4.

ModeSymbolic formTypical use
600rw-------Private secret or user configuration
640rw-r-----Owner-managed file readable by a service group
644rw-r--r--Publicly readable non-secret file
750rwxr-x---Private application directory or executable
755rwxr-xr-xWorld-traversable directory or public executable
700rwx------Private directory
Exact versus relative intent

Use octal when you want a known final mode. Use symbolic clauses when you want to preserve unrelated bits while adding or removing a specific capability.

3. Conditional execute X protects ordinary files

Symbolic X adds execute only to directories and to files that already have at least one execute bit. It is useful when fixing traversal across a mixed tree without turning every data file into an executable.

tree="$HOME/devops-academy/linux/chapter06/lesson02/tree"
mkdir -p -- "$tree/bin" "$tree/config"
printf '#!/usr/bin/env bash
echo ok
' > "$tree/bin/check"
printf 'port=8080
' > "$tree/config/app.conf"
chmod 700 -- "$tree/bin/check"
chmod 600 -- "$tree/config/app.conf"

# Add group read everywhere and group traversal where appropriate.
chmod -R g+rX -- "$tree"
find "$tree" -printf '%M %m %p
' | LC_ALL=C sort

Lowercase x would add execute to every selected object. That can mask packaging errors, expand attack surface, and confuse tools that discover executables by mode.

4. Recursive changes require an object-type policy

A common failure is assigning one mode to an entire application tree. Directories need execute for traversal; ordinary configuration files usually do not. Use find with explicit type predicates when the final modes differ.

release="$HOME/devops-academy/linux/chapter06/lesson02/release"

# Preview targets before changing anything.
find "$release" -type d -print
find "$release" -type f -print

# Apply separate directory and file policies.
find "$release" -type d -exec chmod 750 -- {} +
find "$release" -type f -exec chmod 640 -- {} +
find "$release/bin" -type f -exec chmod 750 -- {} +

# Verify exact resulting modes.
find "$release" -printf '%y %m %u:%g %p
' | LC_ALL=C sort

GNU chmod offers recursive options and symlink handling, but portability and traversal behavior vary. Avoid following untrusted symlinks during bulk permission repair. Work on a bounded root and verify with find -xdev when crossing mounted filesystems would be dangerous.

5. Reference modes reduce duplicated policy literals

chmod --reference=MODEL TARGET copies the mode from a known-good object. This is useful when a package or deployment creates a canonical file and related files must match it.

model="$HOME/devops-academy/linux/chapter06/lesson02/model.conf"
target="$HOME/devops-academy/linux/chapter06/lesson02/generated.conf"
printf 'model=true
' > "$model"
printf 'generated=true
' > "$target"
chmod 640 -- "$model"
chmod --reference="$model" -- "$target"
stat -c '%A %a %n' -- "$model" "$target"

The reference copies mode bits, not owner or group. Ownership is a separate control plane covered in Lesson 3.

6. Hands-on lab: enforce a release permission contract

set -eu
lab="$HOME/devops-academy/linux/chapter06/lesson02"
release="$lab/release"
rm -rf -- "$release"
mkdir -p -- "$release/bin" "$release/config" "$release/logs"

printf '#!/usr/bin/env bash
printf "service=ready\n"
' > "$release/bin/service-check"
printf 'listen=127.0.0.1:8080
' > "$release/config/service.conf"
printf 'initial log
' > "$release/logs/service.log"
printf 'release notes
' > "$release/README.txt"

# Begin from intentionally inconsistent modes.
chmod 777 -- "$release/bin/service-check"
chmod 666 -- "$release/config/service.conf" "$release/README.txt"
chmod 777 -- "$release/logs"

# Contract: directories 750, ordinary files 640, executable files 750,
# writable runtime directory 770.
find "$release" -type d -exec chmod 750 -- {} +
find "$release" -type f -exec chmod 640 -- {} +
chmod 750 -- "$release/bin/service-check"
chmod 770 -- "$release/logs"

find "$release" -printf '%y %m %p
' | LC_ALL=C sort > "$lab/mode-report.txt"
cat -- "$lab/mode-report.txt"
"$release/bin/service-check"
test "$(stat -c %a -- "$release/config/service.conf")" = 640
test "$(stat -c %a -- "$release/logs")" = 770

Verification checklist

7. Common chmod mistakes

chmod -R 777

This removes meaningful boundaries and often introduces executable bits where they do not belong.

One mode for files and directories

The execute bit has different semantics. Separate policies by object type.

Using relative changes in idempotent automation

g+w preserves unknown state. An exact mode is often clearer when configuration management owns the object.

Skipping verification

A successful command may have targeted the wrong tree or preserved unexpected special bits.

8. Knowledge check

Question 1. What is the difference between chmod g+w and chmod g=rw?

Question 2. Why is g+X safer than g+x on a mixed directory tree?

Question 3. Why should recursive permission automation separate files from directories?

9. Summary

chmod implements a permission policy through relative symbolic clauses or exact octal modes. Safe automation names the affected classes, treats files and directories separately, uses capital X deliberately, bounds recursive operations, and verifies final state with stat or find.

Next lesson

Ownership with chown and chgrp

The next lesson explains UID/GID ownership, allowable group changes, recursive ownership hazards, and how deployment identities map onto filesystem objects.

10. Further reading

  • GNU Coreutils manual: mode structure and chmod invocation.
  • Linux man-pages: chmod(2), fchmodat(2), and inode(7).
  • GNU Findutils manual for bounded type-specific bulk operations.
  • POSIX file modes and symbolic mode notation.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.