Default File Permissions: umask and Fixing Exposed Files
- Explain how the starting mode and the umask combine into a new file's permissions
- Read and set the umask, and predict the modes it produces
- Make one user's umask persistent and test it from a real interactive login
- Find files a loose umask exposed and fix them with symbolic chmod without breaking directories
The mental model: a starting mode minus a mask
Understand how a new file's permissions are calculated before you change anything.
Every file and directory you create gets permission bits immediately, and you never typed them. They come from two numbers working together.
- The program asks the kernel for a starting mode. Tools like
touch, editors and shell redirection ask for 666 (rw-rw-rw-) for regular files.mkdirasks for 777 (rwxrwxrwx) for directories. - The kernel then removes every bit that is set in the process's umask (user file-creation mask). Whatever survives is the new file's mode.
So the umask is not a mode. It's a list of permissions to take away. A umask of 022 takes write away from group and other: files become 644 and directories 755. A umask of 027 takes write from group and everything from other: files become 640 and directories 750.
Notice that new regular files never get the execute bit from the default mode, whatever the umask is. That's deliberate: a freshly written file shouldn't become a runnable program by accident. You grant execute explicitly with
chmod +xwhen you mean it.The arithmetic is a bitwise AND with the inverse of the mask, not a subtraction. With a mask of 027, the file calculation is 666 AND NOT 027 = 640. For most masks plain subtraction gives the same answer, but not always (try 666 with a mask of 033), so think of it as "remove these bits".
Check yourself
A process with umask 077 runs
mkdir private. What mode does the directory get?- The program asks the kernel for a starting mode. Tools like
Reading and setting the umask
Read the current mask, change it for a shell, and predict the result.
umaskis a shell builtin, because the mask belongs to the shell process and is inherited by every program it starts. Run it alone to print the mask in octal. The leading zero is just the special-bits digit (setuid, setgid, sticky), which you'll almost never mask. Add-Sto see the permissions that are left allowed, in symbolic form.umask; umask -S0022 u=rwx,g=rx,o=rx
- -S
- Print the mask symbolically as the permissions that remain allowed.
The octal value is the mask, the bits being removed. The symbolic form shows the opposite: what new directories are allowed to get. Most systems default to 0022 for ordinary accounts. mkdir -p /tmp/umask-lesson && cd /tmp/umask-lesson && rm -rf * && (umask 027; touch report.txt; mkdir archive; ls -ld report.txt archive)drwxr-x--- 2 root root 4096 Oct 6 16:26 archive -rw-r----- 1 root root 0 Oct 6 16:26 report.txt
- ( ... )
- Run the commands in a subshell, so settings like umask don't leak into your shell.
Inside the parentheses the commands run in a subshell, so the umask 027only applies there and your own shell keeps its mask. The file comes out rw-r----- (640) and the directory rwxr-x--- (750), exactly what the arithmetic predicted.cd /tmp/umask-lesson && (umask 077; touch secret.key; ls -l secret.key)-rw------- 1 root root 0 Oct 6 16:26 secret.key
077 is the private mask: nothing for group or other. It's the right choice for a shell that creates key material or credentials. It's usually the wrong choice for a whole login, because files you meant to share with your team come out unreadable to them. Check yourself
Your umask is 0002. What mode does a new file from
touchget?Making a user's default persistent
Set one account's umask so every new session gets it, and test it honestly.
Typing
umask 027lasts until the shell exits. To make it the account's default, the line has to run at the start of every session, and that means a shell startup file. Which file depends on what kind of shell starts.- A login shell (console login, SSH,
su -) reads/etc/profile, the scripts in/etc/profile.d/, and then the user's~/.bash_profileor, if that doesn't exist,~/.profile. - An interactive non-login shell (a new terminal tab inside a session) reads
~/.bashrc.
On RHEL, and on Ubuntu, the stock login file also sources
~/.bashrc, so a line in~/.bashrcends up in both kinds of interactive shell. That's why it's the usual per-user answer.id analyst >/dev/null 2>&1 || useradd -m -s /bin/bash analyst; echo 'umask 027' >> /home/analyst/.bashrc; tail -1 /home/analyst/.bashrcumask 027
- >>
- Append to the file instead of overwriting it.
This creates a demo account if it doesn't exist and appends the umask to its ~/.bashrc. Only analyst is affected: other users have their own startup files.su - analyst -c 'umask'; su - analyst -c 'bash -ic umask' 2>/dev/null0002 0027
- su - USER -c CMD
- Run CMD in a non-interactive login shell as USER.
- bash -ic CMD
- Run CMD in an interactive shell, which reads ~/.bashrc.
Two answers, and the difference is the most common trap in this objective. su - analyst -cstarts a login shell that runs one command non-interactively. Ubuntu's~/.bashrcstops early for non-interactive shells, so the first line still shows the old mask. The second runs an interactive shell, which is what a person who logs in actually gets, and shows 0027.Check yourself
Which file sets a single user's umask for their interactive shells on a stock RHEL system?
- A login shell (console login, SSH,
Diagnosing and fixing permissions that are already wrong
Find files a loose umask exposed and fix them without breaking directories.
Changing the umask protects files created from now on. Everything a loose mask already created stays exposed until you fix it. Find them first, then fix them with symbolic chmod, which changes only the bits you name and leaves the rest alone.
mkdir -p /tmp/perm-lesson /tmp/perm-lesson/2026/q3 && cd /tmp/perm-lesson && touch 2026/q3/sales.csv 2026/summary.csv && chmod -R a+rwX . && find . -perm '/o=w'. ./2026 ./2026/summary.csv ./2026/q3 ./2026/q3/sales.csv
- -perm /MODE
- Match if ANY of the given permission bits are set.
- -perm -MODE
- Match only if ALL of the given bits are set.
This builds a small tree the way a umask of 000 would have, world-writable everywhere, then asks find for everything that other users can write. -perm /o=wmeans "any of these bits is set", so it lists every file and directory with other-write.cd /tmp/perm-lesson && chmod -R o-rwx . && find . -perm '/o=rwx' | wc -l && ls -ld 2026 2026/summary.csv0 drwxrwx--- 3 root root 4096 Oct 6 16:26 2026 -rw-rw---- 1 root root 0 Oct 6 16:26 2026/summary.csv
- -R
- Apply recursively to the whole tree.
- o-rwx
- Remove read, write and execute for other users only.
o-rwxremoves every permission for other and touches nothing else, so directories keep their execute bits and the owner and group keep their access. Zero items still match, and the listing shows directories at 770 and files at 660.Check yourself
Which command removes all access for other users from every file and directory under /srv/reports, while leaving directories enterable for the owner and group?
Now do it — in your live terminal
Set a user's default permissions and verify them on the sandbox to your right.
Put it together on the sandbox. Before you press Enter on each command, write down the two modes you expect the new file and the new directory to get, then compare with what
statprints. If a result surprises you, work the arithmetic again: start from 666 or 777 and remove the bits in the mask.Checking a user that should not change is as important as checking the one that should. A change that leaks to every account is a different, and often worse, problem than the one you were asked to fix. That before-and-after check on two accounts is exactly how the lab is graded.
useradd -m -s /bin/bash auditor; su - auditor -c 'bash -ic "touch f; mkdir d; stat -c %a f d"' 2>/dev/nullNote auditor's defaults before you change anything. echo 'umask 077' >> /home/auditor/.bashrc; su - auditor -c 'bash -ic "rm -rf f d; touch f; mkdir d; stat -c %a f d"' 2>/dev/nullThe file should now come out 600 and the directory 700. su - analyst -c 'bash -ic "rm -rf g; touch g; stat -c %a g"' 2>/dev/nullanalyst has its own startup file, so it's unaffected by auditor's change.
- New files start from 666 and directories from 777, and the kernel removes every bit set in the umask. 022 gives 644/755, 027 gives 640/750 and 077 gives 600/700.
- umask is a per-process shell setting inherited by children.
umaskprints it andumask -Sshows what remains allowed. - A single user's default belongs in their own ~/.bashrc (or ~/.bash_profile). /etc/profile, /etc/profile.d and the UMASK line in /etc/login.defs change it for everyone.
- Test from an interactive login (
su - user -c 'bash -ic umask'), because a non-interactivesu - user -cmay skip ~/.bashrc. - The umask never touches existing files. Fix those with symbolic chmod (
chmod -R o-rwx), not an octal mode that strips execute from directories.
| umask | New file / new directory |
|---|---|
0022 | 644 / 755 (common default) |
0002 | 664 / 775 (user-private-group default) |
0027 | 640 / 750 (group can read, others nothing) |
0077 | 600 / 700 (private) |
find DIR -perm /o=rwx | List anything other users can access |
chmod -R o-rwx DIR | Remove other's access, keep everything else |
