Skip to content

File Permissions and ACLs

Applies to CentOS Stream 9 & 10 / AlmaLinux 9.x & 10.x / Rocky Linux 9.x & 10.x

Linux file permissions are the cornerstone of system security. Every file and directory has a set of permission rules that control who can read, write, and execute them. When basic permissions are insufficient, ACLs (Access Control Lists) provide finer-grained control.

  • Understand the rwx permission model
  • Use chmod to modify permissions (symbolic and octal modes)
  • Use chown and chgrp to change ownership and group
  • SUID, SGID, and Sticky Bit special permissions
  • Use ACLs for fine-grained permission control
  • Understand and configure umask
  • A system with EL 9.x installed
  • A user account with sudo privileges
  • Familiarity with the basics of User and Group Management
View file permission details
$ ls -l /etc/nginx/nginx.conf
-rw-r--r--. 1 root root 2488 Mar 24 10:00 /etc/nginx/nginx.conf

Breakdown of the output:

-rw-r--r--. 1 root root 2488 Mar 24 10:00 nginx.conf
│├──┤├──┤├──┤ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ └─ Filename
│ │ │ │ │ │ │ │ └─ Modification time
│ │ │ │ │ │ │ └─ File size
│ │ │ │ │ │ └─ Group
│ │ │ │ │ └─ Owner
│ │ │ │ └─ Hard link count
│ │ │ └─ Other users' permissions (other)
│ │ └─ Group permissions (group)
│ └─ Owner permissions (owner)
└─ File type (- regular file, d directory, l symbolic link)
PermissionCharacterMeaning for FilesMeaning for Directories
ReadrRead file contentsList directory contents
WritewModify file contentsCreate/delete files in the directory
ExecutexExecute the file (script/program)Enter the directory (cd)

Symbolic mode uses u (owner), g (group), o (other), a (all) combined with + (add), - (remove), = (set) to modify permissions.

Add execute permission for the owner
$ chmod u+x script.sh
Remove write permission for others
$ chmod o-w file.txt
Add read and write permissions for the group
$ chmod g+rw shared.doc
Set owner to rwx, group and others to read-only
$ chmod u=rwx,g=r,o=r script.sh
Add execute permission for all users
$ chmod a+x script.sh

Each permission bit corresponds to a numeric value:

PermissionValue
r4
w2
x1
-0

Add up the permission values for owner, group, and others respectively:

NumberPermissionDescription
7rwxRead + write + execute
6rw-Read + write
5r-xRead + execute
4r--Read-only
3-wxWrite + execute
2-w-Write-only
1--xExecute-only
0---No permissions
Set permissions to 755 (owner rwx, group r-x, others r-x)
$ chmod 755 script.sh
Set permissions to 644 (owner rw-, group r--, others r--)
$ chmod 644 config.conf
Set permissions to 700 (owner rwx, no permissions for others)
$ chmod 700 private-dir/
Recursively change permissions on a directory and its contents
$ chmod -R 755 /var/www/html/
Set directories to 755 and files to 644 (recommended approach)
$ find /var/www/html/ -type d -exec chmod 755 {} +
$ find /var/www/html/ -type f -exec chmod 644 {} +

chown and chgrp: Changing Ownership and Group

Section titled “chown and chgrp: Changing Ownership and Group”
Change the owner of a file
$ sudo chown webuser /var/www/html/index.html
Change both owner and group simultaneously
$ sudo chown webuser:webgroup /var/www/html/index.html
Recursively change the owner and group of a directory
$ sudo chown -R webuser:webgroup /var/www/html/
Change the group of a file
$ sudo chgrp developers project-file.txt
Recursively change the group of a directory
$ sudo chgrp -R developers /opt/project/

In addition to the basic rwx permissions, Linux has three special permission bits.

When an executable file has the SUID bit set, any user who runs the file will execute it as the file’s owner (rather than as themselves).

A classic SUID example: the passwd command
$ ls -l /usr/bin/passwd
-rwsr-xr-x. 1 root root 32648 ... /usr/bin/passwd

The s in the owner permission is the SUID flag. When a regular user runs passwd, the process runs as root, allowing it to modify /etc/shadow.

Set SUID (octal prefix 4)
$ sudo chmod u+s /path/to/program
$ sudo chmod 4755 /path/to/program
Find all files with SUID set on the system
$ sudo find / -perm -4000 -type f 2>/dev/null

For files: The process runs with the file’s group identity.

For directories: New files and subdirectories created within the directory automatically inherit the directory’s group instead of the creator’s primary group. This is very useful for team collaboration directories.

Set SGID (octal prefix 2)
$ sudo chmod g+s /opt/shared-project/
$ sudo chmod 2775 /opt/shared-project/
Verify the SGID effect
$ ls -ld /opt/shared-project/
drwxrwsr-x. 2 root developers 4096 ... /opt/shared-project/

The s in the group permission is the SGID flag.

When the Sticky Bit is set on a directory, files within it can only be deleted by the file’s owner or root, even if other users have write permission on the directory. The most common example is /tmp.

View the Sticky Bit on /tmp
$ ls -ld /tmp
drwxrwxrwt. 15 root root 4096 ... /tmp

The t in the other users’ permission is the Sticky Bit flag.

Set the Sticky Bit (octal prefix 1)
$ sudo chmod +t /opt/shared-uploads/
$ sudo chmod 1777 /opt/shared-uploads/
PermissionOctalSymbolEffect on FilesEffect on Directories
SUID4u+sExecute as the owner(No special effect)
SGID2g+sExecute as the groupNew files inherit the directory’s group
Sticky1+t(No special effect)Only the owner can delete files

Practical Example: Creating a Team Shared Directory

Section titled “Practical Example: Creating a Team Shared Directory”
  1. Create the shared directory

    Create the directory
    $ sudo mkdir /opt/team-share
  2. Set the owner and group

    Set ownership to the developers group
    $ sudo chown root:developers /opt/team-share
  3. Set permissions and SGID

    Set SGID to ensure new files inherit the group
    $ sudo chmod 2775 /opt/team-share
  4. Verify

    Confirm permissions are set correctly
    $ ls -ld /opt/team-share
    drwxrwsr-x. 2 root developers 4096 ... /opt/team-share

    Now any member of the developers group who creates files in this directory will have those files automatically belong to the developers group.

  5. Test

    Create a file as a developers group member
    $ touch /opt/team-share/test.txt
    $ ls -l /opt/team-share/test.txt
    -rw-rw-r--. 1 zhangsan developers 0 ... test.txt

umask determines the default permissions for newly created files and directories. The permissions of a new file = base permissions - umask value.

  • Base permissions for files: 666 (no execute bit)
  • Base permissions for directories: 777
View the current umask
$ umask
0022
View in symbolic form
$ umask -S
u=rwx,g=rx,o=rx

Effect of umask 0022:

Base PermissionsumaskActual Permissions
File666022644 (rw-r—r—)
Directory777022755 (rwxr-xr-x)
Temporarily change umask (current session only)
$ umask 027

Effect of umask 027:

Base PermissionsumaskActual Permissions
File666027640 (rw-r-----)
Directory777027750 (rwxr-x---)
Permanently change a user's umask
$ echo "umask 027" >> ~/.bashrc

When the basic owner/group/other permission model is insufficient, ACLs allow you to set independent permissions for specific users or groups.

View a file's ACL
$ getfacl /opt/team-share/config.txt

Example output (no additional ACL):

opt/team-share/config.txt
# owner: zhangsan
# group: developers
user::rw-
group::rw-
other::r--
Grant read-write permission to a specific user
$ sudo setfacl -m u:lisi:rw /opt/team-share/config.txt
Grant read-only permission to a specific group
$ sudo setfacl -m g:qa:r /opt/team-share/config.txt
View the ACL after changes
$ getfacl /opt/team-share/config.txt

Example output:

opt/team-share/config.txt
# owner: zhangsan
# group: developers
user::rw-
user:lisi:rw-
group::rw-
group:qa:r--
mask::rw-
other::r--
Set a user ACL
$ sudo setfacl -m u:username:permissions filepath
Set a group ACL
$ sudo setfacl -m g:groupname:permissions filepath
Remove a specific user's ACL
$ sudo setfacl -x u:lisi /opt/team-share/config.txt
Remove a specific group's ACL
$ sudo setfacl -x g:qa /opt/team-share/config.txt
Remove all ACLs from a file
$ sudo setfacl -b /opt/team-share/config.txt
Recursively set ACLs on a directory
$ sudo setfacl -R -m u:lisi:rwx /opt/team-share/

Default ACLs cause newly created files within a directory to automatically inherit ACL rules:

Set default ACLs
$ sudo setfacl -d -m u:lisi:rw /opt/team-share/
$ sudo setfacl -d -m g:qa:r /opt/team-share/
View default ACLs
$ getfacl /opt/team-share/

Example output:

# file: opt/team-share/
# owner: root
# group: developers
# flags: -s-
user::rwx
group::rwx
other::r-x
default:user::rwx
default:user:lisi:rw-
default:group::rwx
default:group:qa:r--
default:mask::rwx
default:other::r-x

Now new files created in this directory will automatically include ACL rules for lisi and the qa group.

The mask defines the maximum permissions that users and groups can have in the ACL. Even if you set a user’s permissions to rwx, if the mask is r--, the user’s effective permissions will only be r--.

Set the mask
$ sudo setfacl -m m::rx /opt/team-share/config.txt

Practical Example: Fine-Grained Project Permission Control

Section titled “Practical Example: Fine-Grained Project Permission Control”

Suppose you have the following requirements:

  • The project directory /opt/webapp belongs to the webdev group
  • Members of the webdev group have full read-write access
  • The qa group can only read, not modify
  • User deployer has full access for deployments
  • Newly created files automatically inherit these rules
  1. Create the directory and groups

    Create the directory and groups
    $ sudo mkdir -p /opt/webapp
    $ sudo groupadd webdev
    $ sudo groupadd qa
  2. Set basic permissions

    Set owner, group, and SGID
    $ sudo chown root:webdev /opt/webapp
    $ sudo chmod 2770 /opt/webapp
  3. Set ACLs

    Read-only permissions for the qa group
    $ sudo setfacl -m g:qa:rx /opt/webapp
    Full permissions for the deployer user
    $ sudo setfacl -m u:deployer:rwx /opt/webapp
  4. Set default ACLs (applied to newly created files)

    Set default ACLs
    $ sudo setfacl -d -m g:webdev:rwx /opt/webapp
    $ sudo setfacl -d -m g:qa:rx /opt/webapp
    $ sudo setfacl -d -m u:deployer:rwx /opt/webapp
  5. Verify

    View the complete ACL settings
    $ getfacl /opt/webapp

ACLs are an extension of basic permissions. When both exist:

  • The file owner’s permissions are still controlled by user::
  • Other users’ permissions are jointly affected by ACL rules and the mask
  • chmod on group permissions modifies the mask value when ACLs are present

The File Owner is root, but Regular Users Can Still Read It

Section titled “The File Owner is root, but Regular Users Can Still Read It”

Because the other (other users) permission allows reading. For example, permissions of 644 mean all users can read the file.

How to Determine Why a User Cannot Access a File

Section titled “How to Determine Why a User Cannot Access a File”
Check file permissions and ACL
$ ls -la /path/to/file
$ getfacl /path/to/file
Check permissions at every level of the directory path
$ namei -l /path/to/file

namei -l displays the permissions of each directory level in the path, helping you identify which level is blocking access.

Back up ACLs to a file
$ getfacl -R /opt/webapp > acl-backup.txt
Restore ACLs from a backup
$ sudo setfacl --restore=acl-backup.txt