In the previous lesson you read app.log and shipments.csv without trouble, but sooner or later you will run into a Permission denied when trying to write to /var/log/veloz or when running your first script from ~/veloz-ops/bin. Permissions are not an administrative obstacle: they are the mechanism that stops a bug in veloz-api from deleting the business data, or any user on the system from reading the payment gateway credentials. In this lesson you will learn to read them, to modify them with judgment, and to leave ~/veloz-ops and /srv/veloz/data properly protected.

Contents

  1. The user / group / others model
  2. Reading the output of ls -l field by field
  3. What x means on a file and what it means on a directory
  4. Symbolic chmod
  5. Octal chmod
  6. Ownership: chown, chgrp, id and groups
  7. umask: the default permissions
  8. Special bits: sticky, setgid and setuid
  9. sudo and the principle of least privilege
  10. Hands-on case: securing the Veloz Envíos toolkit and data

  1. The user / group / others model

Every file and every directory in Linux has one owner (a user) and one group. From there, permissions are defined for three classes of subject:

Class Letter Who it is
User (user) u The owner of the file
Group (group) g The members of the group assigned to the file
Others (others) o Every other user on the system

And for each class there are three permissions:

Permission Letter On a file On a directory
Read r See the content List the names it contains
Write w Modify the content Create, delete and rename entries
Execute x Run it as a program Traverse it to reach what is inside

The evaluation rule is important and surprises a lot of people: the system checks only the first class that matches. If you are the owner, the u permissions apply and the g and o ones are never looked at, even if they were more permissive. A file with permissions ----rwxrwx is unreadable for its owner and accessible to everyone else.

  1. Reading the output of ls -l field by field

ls -l /srv/veloz/data/shipments.csv
-rw-r----- 1 veloz veloz 21504 Aug  3 09:14 shipments.csv

The fields, in order, are: type and permissions (-rw-r-----), number of hard links (1, a topic for 05-01), owner (veloz), group (veloz), size in bytes (21504), last modification date and name. The interesting part is the first ten characters:

 -   rw-    r--    ---
type  u      g      o
  • Type -: regular file. It would be d for a directory and l for a symbolic link.
  • u = rw-: the user veloz can read and write, but not execute.
  • g = r--: the members of the veloz group can only read.
  • o = ---: the rest of the system cannot even open it.

That is exactly the design we want for business data: the application writes, the operations team reads, nobody else sees anything.

  1. What x means on a file and what it means on a directory

This distinction is the number one source of confusion with permissions.

On a file, x means "the system may attempt to run it as a program". Without x, a perfectly written script fails with bash: ./daily-report.sh: Permission denied.

On a directory, x means something completely different: permission to traverse it. Without x on a directory you cannot cd into it, nor reach anything inside it, not even files you do have read permission on.

From that, three combinations follow that are worth being clear about:

Directory permissions What you can do
r-- List the names with ls, but not see details or go in
--x Go in and open files if you know their exact name, but not list
r-x The normal case: list and access

The --x combination is the one websites use for configuration directories: you can get in if you know the path, but you cannot browse. And the most useful practical consequence: if a read permission on a file does not work, check the x on every directory along the path. It only has to be missing on one for the whole path to be inaccessible.

  1. Symbolic chmod

chmod (change mode) modifies permissions. In its symbolic form it reads almost like a sentence: chmod [who][operator][permissions] file.

Who Operator Permissions
u user, g group, o others, a all + add, - remove, = set exactly r, w, x
chmod u+x ~/veloz-ops/bin/daily-report.sh     # make it executable for the owner
chmod go-w /srv/veloz/data                     # remove write from group and others
chmod a=r /srv/veloz/data/archive/*.csv        # everyone read ONLY (sets, does not add)
chmod u+rw,go-rwx ~/veloz-ops/etc/veloz-ops.conf  # several rules separated by commas

The difference between + and = is crucial: +r adds read while keeping everything else, whereas =r sets that class's permissions to exactly read, removing write and execute if it had them. When you want a deterministic state, use =.

chmod accepts -R to apply recursively, but use it carefully: chmod -R 755 over a tree turns data files that should not be executable into executables. Later on, with find (05-01), you will learn to apply different permissions to files and directories in a single pass.

  1. Octal chmod

The octal form is the one you will see in documentation and scripts, because it is compact and deterministic. Each permission has a numeric value and they add up:

r is worth 4, w is worth 2 and x is worth 1. Adding those values gives the eight possible digits:

Digit 0 1 2 3 4 5 6 7
Permissions --- --x -w- -wx r-- r-x rw- rwx

You write three digits, one per class: user, group, others. The cases that cover 95 % of practice:

Octal Symbolic Typical use
644 rw-r--r-- Normal files: data, logs, documents
755 rwxr-xr-x Scripts and directories: executable by everyone
600 rw------- Files with secrets: keys, credentials
700 rwx------ Private directories and personal scripts
640 rw-r----- Data the group reads and nobody else sees

A quick mental rule for converting: think of rwx as three switches worth 4, 2 and 1. rw- = 4+2 = 6; r-x = 4+1 = 5; r-- = 4.

  1. Ownership: chown, chgrp, id and groups

Before changing ownership, check who you are:

id
uid=1000(joan) gid=1000(joan) groups=1000(joan),27(sudo),1002(veloz)

id shows your user, your primary group and all the secondary groups you belong to. groups gives the short version. The fact that joan is in the veloz group is what lets him read the 640 files owned by veloz.

sudo chown veloz /srv/veloz/data/shipments.csv        # change the owner
sudo chgrp veloz /srv/veloz/data/shipments.csv        # change the group
sudo chown veloz:veloz /srv/veloz/data/shipments.csv  # both at once
sudo chown -R veloz:veloz /srv/veloz/data             # recursive

Two important notes:

  • Changing the owner requires root. A normal user cannot "gift" a file to someone else, because that would allow disk quotas to be bypassed and files to be slipped into other people's space.
  • Changing the group can be done by the owner, as long as he himself belongs to the destination group.

Adding a user to a group is done with sudo usermod -aG veloz joan. The -a (append) is mandatory: without it, usermod replaces the list of secondary groups instead of adding to it, a classic mistake that leaves someone locked out of sudo. Group changes do not affect sessions that are already open: you have to log out and log back in.

  1. umask: the default permissions

When you create a file, why does it come out with 644 and not 777? Because the system starts from a base set of permissions and subtracts the bits indicated in the umask.

umask
0022

The base permission is 666 (rw-rw-rw-) for files and 777 for directories; the umask turns off bits on that base (it does not subtract arithmetically). Notice that files are never born executable: their base does not include x. That is deliberate, and that is why you have to run chmod +x explicitly on every new script.

umask Files Directories Scenario
022 644 755 The default on most systems
002 664 775 Teams working on a shared directory
077 600 700 Machines with sensitive data: nobody else sees anything

You change it with umask 077, and to make it permanent you add it to ~/.bashrc (lesson 01-02). Careful: the umask only affects files created afterwards; it does not modify existing ones.

  1. Special bits: sticky, setgid and setuid

Besides the nine rwx bits there are three special bits, which show up as a fourth octal digit on the left.

Sticky bit (1000) — On a directory that is writable by everyone, it stops one user from deleting another's files. It is what protects /tmp:

ls -ld /tmp shows drwxrwxrwt. That trailing t is the sticky bit: without it, any user could delete everyone else's temporary files. It is applied with chmod 1777 dir or chmod +t dir.

Setgid (2000) — On a directory, it makes everything created inside inherit the directory's group instead of the primary group of whoever creates it. It is the key piece of shared directories:

sudo chgrp veloz /srv/veloz/data
sudo chmod 2775 /srv/veloz/data
ls -ld /srv/veloz/data
drwxrwsr-x 3 root veloz 4096 Aug  3 11:32 /srv/veloz/data

The s in the position of the group's x indicates setgid. From now on, any CSV that veloz-api or any member of the team leaves there will belong to the veloz group and will be readable by the whole team with no manual intervention.

Setuid (4000) — On an executable, it makes it run with the privileges of its owner, not of whoever launches it. It is how passwd can modify /etc/shadow while you are a normal user.

Serious warning: setuid is a first-order attack vector. A root-owned setuid executable with a programming bug hands over the entire system. Never set setuid on a shell script —many systems ignore it precisely for that reason— and do not apply it to your own programs unless you know exactly what you are doing. Defense in depth is covered in 08-03.

  1. sudo and the principle of least privilege

sudo runs one specific command with root privileges, leaving a record in /var/log/auth.log of who did what and when. That trail is the main reason it is preferred over logging in as root.

The principle of least privilege says that every process and every person should have exactly the permissions they need, not one more. Translated into your day-to-day:

  • Always work as a normal user; use sudo only for the command that requires it.
  • Avoid sudo su - and long-running root sessions: you lose the audit trail and the safety net disappears.
  • Solve access problems with groups, not by handing out sudo. Operations being able to read /srv/veloz/data is a question of veloz group membership, not of administrator privileges.
  • Be suspicious of chmod 777. It is the quick answer to a Permission denied and almost always the wrong one: it leaves the file writable by any process on the machine. The correct solution is to adjust the owner or the group.

  1. Hands-on case: securing the Veloz Envíos toolkit and data

# 1. The script must be executable by its owner and readable by the rest
chmod 755 ~/veloz-ops/bin/daily-report.sh

# 2. The configuration will contain gateway credentials: owner only
chmod 600 ~/veloz-ops/etc/veloz-ops.conf

# 3. The data directory belongs to the veloz group and inherits it (setgid)
sudo chgrp -R veloz /srv/veloz/data
sudo chmod 2775 /srv/veloz/data
sudo chmod 640 /srv/veloz/data/shipments.csv

# 4. Check the result
ls -ld /srv/veloz/data && ls -l /srv/veloz/data/shipments.csv
drwxrwsr-x 3 root  veloz 4096 Aug  3 11:32 /srv/veloz/data
-rw-r----- 1 veloz veloz 21504 Aug  3 09:14 /srv/veloz/data/shipments.csv

The reasoning behind each decision:

  • 755 on the script: it needs x to run. It holds no secrets, so r-x for group and others is harmless and makes it easy for a colleague to audit it.
  • 600 on the configuration: as soon as it stores an API key, any read permission for "others" is equivalent to publishing it. 600 is non-negotiable on files with credentials.
  • 2775 on the directory: 775 gives the veloz group control over the content; the leading 2 (setgid) guarantees that new files inherit that group automatically.
  • 640 on the CSV: the owner (the application) writes, the team reads, nobody else sees the business data.

Common Mistakes and Tips

  • Answering a Permission denied with chmod 777. It works, and it opens a hole. Ask yourself first who should have access and fix it with owner or group.
  • Forgetting the x on the directories along the path. If cat /srv/veloz/data/shipments.csv fails despite you having read permission on the file, check ls -ld /srv and ls -ld /srv/veloz.
  • Using chmod -R 755 over a mixed tree. It turns data files into executables. Apply different permissions to files and directories (with find, 05-01).
  • Confusing +r with =r. The first adds, the second sets the exact state.
  • usermod -G without -a. It replaces the secondary groups instead of adding and can lock you out of sudo.
  • Expecting a group change to take effect immediately. You have to log out and log back in.
  • Leaving a credentials file at 644. It is the most frequent security flaw and the easiest one to avoid.

Exercises

Exercise 1 — Reading permissions. Interpret these three ls -l lines by saying, for each one, what the owner can do, what the group can do and what everyone else can do, and express its permissions in octal:

-rwxr-x---  1 joan  veloz   512 Aug  3 11:20 daily-report.sh
drwxrwsr-x  3 root  veloz  4096 Aug  3 11:32 data
-rw-------  1 joan  joan     84 Aug  3 11:22 veloz-ops.conf

Exercise 2 — The script that will not start. You have created ~/veloz-ops/bin/shipment-summary.sh with an editor and when you launch it you get Permission denied. ls -l shows -rw-rw-r--. Explain the cause, fix it in two ways (symbolic and octal) and justify why the file was born without x.

Exercise 3 — Designing the permissions of a shared directory. The operations team (group veloz, three people) needs a /srv/veloz/reports directory where everyone can create reports and read everyone else's, but where nobody can delete somebody else's report and where users outside the group see nothing. Write the commands and explain each bit.

Solutions

Solution to Exercise 1

File Octal Owner Group Others
daily-report.sh 750 rwx: reads, modifies and executes r-x: reads and executes, does not modify ---: nothing
data 2775 rwx: lists, creates and enters rws: the same, and inherits the group (setgid) r-x: lists and enters, does not create
veloz-ops.conf 600 rw-: reads and writes ---: nothing ---: nothing

On data, the s takes the place of the group's x: the x is still active (if it were not, you would see an uppercase S) and on top of that there is the setgid bit, which in octal is the leading 2.

Solution to Exercise 2

chmod u+x ~/veloz-ops/bin/shipment-summary.sh   # symbolic: the bare minimum
chmod 755 ~/veloz-ops/bin/shipment-summary.sh   # octal: executable by the team too
ls -l ~/veloz-ops/bin/shipment-summary.sh
-rwxr-xr-x 1 joan joan 340 Aug  3 11:40 /home/joan/veloz-ops/bin/shipment-summary.sh

Cause: the file has no x bit in any class, so the kernel refuses to run it, even though its content is a valid script. Why it was born without x: files are created with base permissions 666 (rw-rw-rw-), with no execute in any case, and the umask 022 additionally removes write from group and others, leaving 644. The system never marks a file as executable on its own: it is a conscious decision that a person has to take, and that is precisely the protection.

Solution to Exercise 3

sudo mkdir -p /srv/veloz/reports
sudo chgrp veloz /srv/veloz/reports
sudo chmod 3770 /srv/veloz/reports
ls -ld /srv/veloz/reports
drwxrws--T 2 root veloz 4096 Aug  3 11:45 /srv/veloz/reports

Breakdown of 3770:

  • 770: owner and the veloz group have rwx (list, create, enter); others have nothing, which meets the invisibility requirement for outside users.
  • 3 = 2 + 1, that is, two special bits at once:
    • 2 (setgid): the reports created inside will belong to the veloz group regardless of the primary group of whoever creates them, so the whole team can read them.
    • 1 (sticky): even though everyone has w on the directory, each user can only delete or rename their own files. It is the same mechanism that protects /tmp.

The trailing uppercase T indicates a sticky bit without x permission for others; if others had x you would see a lowercase t. This directory is the canonical example of how the special bits solve a collaboration requirement that the nine rwx bits cannot express.

Conclusion

You can now read an ls -l line field by field, tell apart the role of the x bit on files and on directories —the hidden cause of so many "permission denied" messages— and modify permissions in both symbolic and octal form, with the four patterns that solve almost everything: 644, 755, 600 and 700. You control ownership with chown and chgrp, you know how to check your groups with id, you understand why the umask decides the permissions of every new file, and you know the three special bits, including the setgid that makes a real shared directory work. And above all, you have the judgment: least privilege, groups before sudo, and never 777.

~/veloz-ops is left with its script executable and its configuration locked down to 600, and /srv/veloz/data with the veloz group and automatic inheritance. Defense in depth —command injection, safe temporary files, secret management— is tackled in 08-03.

In lesson 02-04 comes the piece that multiplies everything you have learned: redirection and pipes. You will learn to separate normal output from errors, to save results into files, to discard noise with /dev/null and to chain the Module 2 filters into pipelines that answer complex questions about access.log in a single line.

Bash Programming Course

Module 1: Introduction to Bash

Module 2: Basic Bash Commands

Module 3: Scripting Fundamentals

Module 4: Intermediate Scripting

Module 5: Advanced Scripting Techniques

Module 6: Working with External Tools

Module 7: Automation and Scheduling

Module 8: Best Practices and Optimization

Module 9: Real-World Projects

© Copyright 2026. All rights reserved