Complete Guide to Linux File Ownership and Permission Design
Section titled “Complete Guide to Linux File Ownership and Permission Design”In Linux, every file and directory has an owner, an owning group, and a set of permissions. Designing secure access rights requires more than understanding the numeric values used with chmod. You also need to understand how rwx differs between files and directories, along with umask, setuid, setgid, and the sticky bit.
In this article, we will create test users and files on a RHEL-compatible Linux system to verify ownership, standard permissions, special bits, shared directory design, and methods for troubleshooting access-denied errors. Run these procedures in a disposable test environment so that existing users and production data are not affected.
Permission basics
Section titled “Permission basics”Linux has three basic access permissions: r, w, and x.
| Permission | Numeric value | File | Directory |
|---|---|---|---|
r | 4 | Read contents | List the names of entries inside |
w | 2 | Modify contents | Create and delete files inside |
x | 1 | Execute | Traverse the directory and access entries inside |
Permissions are divided into three classes.
u: ownerg: owning groupo: other users
For example, 640 means the owner has rw-, the owning group has r--, and other users have ---.
When a resource is accessed, owner permissions apply if the executing user is the owner. If the user belongs to the owning group or a matching supplementary group, group permissions apply. Otherwise, permissions for other users are used.
Step 1: Prepare test users and a group
Section titled “Step 1: Prepare test users and a group”Prepare an owner, a user who belongs to the same group, and a user outside the group so that their behavior can be compared.
sudo groupadd -f examplegrpsudo id exampleowner >/dev/null 2>&1 || sudo useradd -m exampleownersudo id examplemember >/dev/null 2>&1 || sudo useradd -m examplemembersudo id exampleother >/dev/null 2>&1 || sudo useradd -m exampleothersudo usermod -aG examplegrp exampleownersudo usermod -aG examplegrp examplemember
sudo mkdir -p /srv/example-permissionssudo touch /srv/example-permissions/file.txtsudo chown -R exampleowner:examplegrp /srv/example-permissions
test "$(sudo stat -c '%U:%G' /srv/example-permissions)" = "exampleowner:examplegrp"test "$(sudo stat -c '%U:%G' /srv/example-permissions/file.txt)" = "exampleowner:examplegrp"exampleowner and examplemember belong to examplegrp, while exampleother is not added to that group. With chown, you can set file and directory ownership in the form owner:owning group.
Step 2: Set basic permissions using symbolic and numeric notation
Section titled “Step 2: Set basic permissions using symbolic and numeric notation”chmod supports both symbolic notation such as u=rw,g=r,o= and numeric notation such as 640.
In the following example, rw-r----- is first set using symbolic notation, and then the same permissions are applied using numeric notation.
sudo chown exampleowner:examplegrp /srv/example-permissions/file.txtsudo chmod u=rw,g=r,o= /srv/example-permissions/file.txttest "$(sudo stat -c '%a' /srv/example-permissions/file.txt)" = "640"sudo stat -c '%U %G %A %a %n' /srv/example-permissions/file.txt
sudo chmod 640 /srv/example-permissions/file.txttest "$(sudo stat -c '%U:%G:%a' /srv/example-permissions/file.txt)" = "exampleowner:examplegrp:640"In numeric notation, the values r=4, w=2, and x=1 are added together.
7:rwx6:rw-5:r-x4:r--
Using stat, you can check the owner, owning group, symbolic notation, and octal notation together.
Step 3: Verify file read and write access
Section titled “Step 3: Verify file read and write access”For a file with permissions 640, the owner can read and write. Members of the owning group can only read. Other users have no permissions.
sudo -u exampleowner sh -c 'echo owner-write >> /srv/example-permissions/file.txt'sudo -u examplemember cat /srv/example-permissions/file.txt >/dev/null
if sudo -u examplemember sh -c 'echo member-write >> /srv/example-permissions/file.txt'; then echo 'unexpected: group write succeeded' >&2 exit 1else echo 'group write is correctly denied'fi
if sudo -u exampleother cat /srv/example-permissions/file.txt >/dev/null; then echo 'unexpected: other read succeeded' >&2 exit 1else echo 'other read is correctly denied'fiWith this configuration, users in the same group can read the contents but cannot modify them. The basic principle is to allow only the operations that are actually required.
Step 4: Verify the differences between r, w, and x on directories
Section titled “Step 4: Verify the differences between r, w, and x on directories”For directories, the same rwx permissions have different meanings than they do for files.
r: list the names of entries in the directoryw: create and delete files or directories inside itx: traverse the path and access entries inside it
The x permission is especially important. Even if the file itself has read permission, it cannot be accessed unless its parent directory can be traversed.
sudo mkdir -p /srv/example-dir/read-only /srv/example-dir/search-only /srv/example-dir/write-searchsudo touch /srv/example-dir/read-only/item.txt /srv/example-dir/search-only/item.txtsudo chown -R exampleowner:examplegrp /srv/example-dirsudo chmod 740 /srv/example-dir/read-onlysudo chmod 710 /srv/example-dir/search-onlysudo chmod 730 /srv/example-dir/write-search
sudo -u examplemember ls /srv/example-dir/read-only >/dev/nullif sudo -u examplemember cat /srv/example-dir/read-only/item.txt >/dev/null; then echo 'unexpected: read without directory execute succeeded' >&2 exit 1else echo 'directory execute is required for path traversal'fi
sudo -u examplemember cat /srv/example-dir/search-only/item.txt >/dev/nullif sudo -u examplemember ls /srv/example-dir/search-only >/dev/null 2>&1; then echo 'unexpected: listing without directory read succeeded' >&2 exit 1else echo 'directory read is required for listing'fi
sudo -u examplemember touch /srv/example-dir/write-search/new.txtsudo -u examplemember rm /srv/example-dir/write-search/new.txtIf a directory has both w and x, files can be created and deleted inside it. Therefore, when investigating whether a file can be deleted, you need to check not only the target file but also the permissions on the parent directory.
Step 5: Control initial permissions for new files with umask
Section titled “Step 5: Control initial permissions for new files with umask”umask specifies which permissions are not granted to newly created files and directories.
Common base values are:
- regular file:
666 - directory:
777
For example, with umask 027, a regular file receives 640 and a directory receives 750.
sudo rm -f /tmp/example-umask-filesudo rm -rf /tmp/example-umask-dirsudo -u exampleowner sh -c 'umask 027; touch /tmp/example-umask-file; mkdir -p /tmp/example-umask-dir'test "$(sudo stat -c '%a' /tmp/example-umask-file)" = "640"test "$(sudo stat -c '%a' /tmp/example-umask-dir)" = "750"sudo stat -c '%A %a %n' /tmp/example-umask-file /tmp/example-umask-dirThe base value for regular files is 666 so that newly created regular files do not automatically receive execute permission.
For shared directories, it is not enough to consider only the directory’s chmod setting. You should also verify whether users’ umask values remove group write permission from newly created files.
Step 6: Verify setuid and setgid
Section titled “Step 6: Verify setuid and setgid”In addition to standard rwx permissions, Linux provides special bits.
| Special bit | Numeric value | Main purpose |
|---|---|---|
| setuid | 4000 | Behavior related to the effective user ID of an executable file |
| setgid | 2000 | Effective group ID of an executable file, or group inheritance on directories |
| sticky bit | 1000 | Restrict deletion and renaming in shared directories |
In the following example, setuid and setgid are applied to a test executable, verified with stat, and then removed.
sudo cp /usr/bin/true /srv/example-permissions/setid-demosudo chown root:examplegrp /srv/example-permissions/setid-demo
sudo chmod 4750 /srv/example-permissions/setid-demosudo stat -c '%A %a %n' /srv/example-permissions/setid-demotest "$(sudo stat -c '%a' /srv/example-permissions/setid-demo)" = "4750"
sudo chmod 2750 /srv/example-permissions/setid-demosudo stat -c '%A %a %n' /srv/example-permissions/setid-demotest "$(sudo stat -c '%a' /srv/example-permissions/setid-demo)" = "2750"
sudo chmod 0750 /srv/example-permissions/setid-demotest "$(sudo stat -c '%a' /srv/example-permissions/setid-demo)" = "750"Special bits have a greater impact than ordinary access permissions and should only be set when there is a clear need. Executables with setuid are especially relevant to privilege elevation and should not be added casually.
Step 7: Design a shared directory with setgid
Section titled “Step 7: Design a shared directory with setgid”When multiple users share the same directory, setting setgid on the directory helps keep group ownership consistent.
When setgid is set on a directory, new files and subdirectories created inside it inherit the group of the parent directory.
In the following example, we create a shared directory that members of examplegrp can use.
sudo mkdir -p /srv/example-sharesudo chown root:examplegrp /srv/example-sharesudo chmod 2770 /srv/example-share
sudo -u exampleowner sh -c 'umask 007; echo shared-data > /srv/example-share/owner.txt'sudo -u examplemember sh -c 'umask 007; echo member-data > /srv/example-share/member.txt'
test "$(sudo stat -c '%G' /srv/example-share/owner.txt)" = "examplegrp"test "$(sudo stat -c '%G' /srv/example-share/member.txt)" = "examplegrp"test "$(sudo stat -c '%a' /srv/example-share/owner.txt)" = "660"test "$(sudo stat -c '%a' /srv/example-share/member.txt)" = "660"sudo stat -c '%A %a %U %G %n' /srv/example-share /srv/example-share/owner.txt /srv/example-share/member.txtThe leading 2 in 2770 represents setgid.
In this configuration, examplegrp is fixed as the owning group of the directory, and umask 007 causes new files to receive permissions equivalent to 660. Users outside the group receive no access rights.
When collaborative editing is required, combining a dedicated group, setgid, and an appropriate umask is safer than simply broadening permissions with chmod 777.
Step 8: Restrict deletion in shared directories with the sticky bit
Section titled “Step 8: Restrict deletion in shared directories with the sticky bit”If a directory writable by all users is simply set to 777, users may be able to delete files created by other users.
Setting the sticky bit restricts users from deleting or renaming files owned by other users, even in a writable shared directory.
sudo mkdir -p /srv/example-stickysudo chmod 1777 /srv/example-stickysudo -u exampleowner sh -c 'echo owner-data > /srv/example-sticky/owner.txt'
if sudo -u exampleother rm /srv/example-sticky/owner.txt; then echo 'unexpected: non-owner removed another user file' >&2 exit 1else echo 'sticky bit prevented non-owner deletion'fi
sudo -u exampleowner rm /srv/example-sticky/owner.txttest ! -e /srv/example-sticky/owner.txtThe leading 1 in 1777 represents the sticky bit. A typical example is /tmp.
The sticky bit does not control reading or writing file contents. It mainly controls deletion and renaming inside shared directories.
Step 9: Troubleshoot Permission denied
Section titled “Step 9: Troubleshoot Permission denied”When access is denied, changing only the target file’s chmod is risky. First, check the following in order:
- the file owner and owning group
- the file’s
rwxpermissions xpermissions along the entire path, including parent directoriesumaskif the issue involves a newly created file- special bits such as setuid, setgid, and sticky bit
The following example reproduces a situation where the file’s group read permission is correct, but the group does not have execute permission on the parent directory. It then adds only the permission that is actually required.
sudo mkdir -p /srv/example-troubleshootsudo sh -c 'echo diagnostic-data > /srv/example-troubleshoot/data.txt'sudo chown root:examplegrp /srv/example-troubleshoot /srv/example-troubleshoot/data.txtsudo chmod 740 /srv/example-troubleshootsudo chmod 640 /srv/example-troubleshoot/data.txt
if sudo -u examplemember cat /srv/example-troubleshoot/data.txt >/dev/null; then echo 'unexpected: access succeeded before repair' >&2 exit 1else echo 'access denial reproduced'fi
sudo stat -c '%A %a %U %G %n' /srv /srv/example-troubleshoot /srv/example-troubleshoot/data.txtsudo -u examplemember sh -c 'umask'sudo stat -c '%A %a %n' /srv/example-troubleshoot /srv/example-troubleshoot/data.txt
sudo chmod 750 /srv/example-troubleshootsudo -u examplemember cat /srv/example-troubleshoot/data.txt >/dev/nullecho 'access restored with group execute on the parent directory'In this example, the file with permissions 640 is readable by the group, but the parent directory with permissions 740 does not grant x to the group. Changing it to 750 adds only the group traversal permission that is needed. This restores access without expanding permissions for other users.
If standard ownership and permissions are correct, other access-control mechanisms such as POSIX ACLs or SELinux may also be involved. When diagnosing the cause, it is important not to mix these control layers, but to check them separately and in order.
Key points for secure access-right design
Section titled “Key points for secure access-right design”Do not broaden access rights until something works. Instead, allow only the operations required by the users or groups that actually need them.
- Grant personal files only the permissions required by the owner
- Use dedicated groups for collaboration
- Use setgid on shared directories to keep group inheritance consistent
- Include
umaskwhen designing permissions for newly created files - Consider the sticky bit for shared writable areas used by unrestricted users
- Do not casually use
777or666as a quick fix for permission problems - Limit executables with setuid or setgid to the minimum necessary
Summary
Section titled “Summary”When designing Linux access rights, you need to consider the owner, owning group, the different meanings of rwx for files and directories, umask, and special bits together.
For shared directories in particular, combining a dedicated group, setgid, and an appropriate umask makes collaboration easier without granting excessive permissions.
When troubleshooting permission problems, do not look only at the affected file. Check the entire path, including parent directories, and keep changes to the minimum required.