Linux File Permissions, ACLs, and SELinux/AppArmor Basics

File permissions and access control are fundamental to Linux security. Understanding how to properly configure permissions, extend them with Access Control Lists (ACLs), and leverage mandatory access control systems like SELinux and AppArmor is essential for maintaining secure, well-organized systems. This guide provides comprehensive coverage of Linux access control mechanisms from basic permissions to advanced security frameworks.

Understanding Traditional Unix Permissions

Permission Model Basics

Linux implements a simple yet effective permission model with three permission types and three user categories.

Permission types:

  • Read (r): View file contents or list directory contents
  • Write (w): Modify file contents or create/delete files in directory
  • Execute (x): Run file as program or enter directory

User categories:

  • User (u): File owner
  • Group (g): File’s group
  • Others (o): Everyone else

Viewing Permissions

Use ls -l to view permissions:

ls -l /etc/passwd
-rw-r--r-- 1 root root 2847 Nov 10 10:00 /etc/passwd

Breaking down the permission string -rw-r--r--:

  • First character: File type (- = regular file, d = directory, l = symlink)
  • Next three: Owner permissions (rw-)
  • Next three: Group permissions (r–)
  • Last three: Other permissions (r–)

Numeric representation:

Permissions can be represented as octal numbers:

  • Read = 4
  • Write = 2
  • Execute = 1

So rw-r--r-- = 644:

  • Owner: 4+2+0 = 6 (rw-)
  • Group: 4+0+0 = 4 (r–)
  • Others: 4+0+0 = 4 (r–)

Changing Permissions with chmod

Symbolic mode:

# Add execute permission for user
chmod u+x file.sh

## Remove write permission for group
chmod g-w document.txt

## Set specific permissions for others
chmod o=r file.txt

## Multiple changes
chmod u+x,g-w,o-rwx script.sh

## Add read permission for all
chmod a+r file.txt

Numeric mode:

## Set permissions to rw-r--r--
chmod 644 file.txt

## Set permissions to rwxr-xr-x
chmod 755 script.sh

## Set permissions to rw-------
chmod 600 private.key

## Set permissions to rwxrwxrwx
chmod 777 file.txt  # Generally not recommended!

Recursive changes:

## Change permissions recursively
chmod -R 755 /var/www/html

## Change only directories
find /var/www -type d -exec chmod 755 {} \;

## Change only files
find /var/www -type f -exec chmod 644 {} \;

Changing Ownership

Change owner:

## Change owner
sudo chown newuser file.txt

## Change owner and group
sudo chown newuser:newgroup file.txt

## Change only group
sudo chown :newgroup file.txt
## or
sudo chgrp newgroup file.txt

## Recursive ownership change
sudo chown -R www-data:www-data /var/www/html

Special Permissions

Setuid (SUID) - 4000:

When set on executable files, runs with owner’s privileges instead of executor’s.

## Set SUID
chmod u+s /usr/bin/passwd
## or
chmod 4755 /usr/bin/passwd

## View SUID files
find / -perm -4000 -type f 2>/dev/null

Example: /usr/bin/passwd has SUID so users can change their passwords (modifying /etc/shadow, which only root can write).

Setgid (SGID) - 2000:

On files: Runs with group’s privileges. On directories: New files inherit directory’s group.

## Set SGID on directory
chmod g+s /shared/directory
## or
chmod 2775 /shared/directory

Sticky Bit - 1000:

On directories: Only owner can delete their files (useful for /tmp).

## Set sticky bit
chmod +t /tmp/shared
## or
chmod 1777 /tmp/shared

## View sticky bit directories
ls -ld /tmp
drwxrwxrwt 20 root root 4096 Nov 11 10:00 /tmp

Default Permissions with umask

umask sets default permissions for newly created files and directories.

View current umask:

umask
## Output: 0022

How umask works:

  • Default file permissions: 666 (rw-rw-rw-)
  • Default directory permissions: 777 (rwxrwxrwx)
  • umask subtracts from these defaults

With umask 022:

  • Files: 666 - 022 = 644 (rw-r–r–)
  • Directories: 777 - 022 = 755 (rwxr-xr-x)

Set umask:

## Temporary (current session)
umask 027

## Permanent (add to ~/.bashrc or /etc/profile)
echo "umask 027" >> ~/.bashrc

Common umask values:

  • 022: Default, group/others can read but not write
  • 027: Group can read, others have no access
  • 077: Only owner has any access

Access Control Lists (ACLs)

ACLs extend traditional Unix permissions, allowing fine-grained per-user and per-group access control.

Why Use ACLs?

Traditional permissions limit you to one owner, one group, and everyone else. ACLs allow:

  • Multiple users with different permissions
  • Multiple groups with different permissions
  • Default permissions for new files in directories

Viewing ACLs

## View ACLs
getfacl file.txt

## Output:
## file: file.txt
## owner: user1
## group: group1
## user::rw-
## group::r--
## other::r--

Setting ACLs

Grant user permissions:

## Give user2 read/write access
setfacl -m u:user2:rw file.txt

## Give user3 read-only access
setfacl -m u:user3:r file.txt

Grant group permissions:

## Give developers group read/write access
setfacl -m g:developers:rw file.txt

Multiple ACL entries:

setfacl -m u:alice:rwx,u:bob:rx,g:staff:r file.txt

Recursive ACLs:

## Apply ACLs recursively
setfacl -R -m u:user2:rw /path/to/directory

Default ACLs (for directories):

Default ACLs are inherited by new files created in the directory.

## Set default ACL
setfacl -d -m u:user2:rw /shared/directory

## New files in /shared/directory will give user2 rw access

Remove ACLs:

## Remove specific ACL entry
setfacl -x u:user2 file.txt

## Remove all ACLs
setfacl -b file.txt

ACL Mask

The ACL mask defines maximum permissions for named users, group owner, and named groups.

## Set mask
setfacl -m m::rx file.txt

## Even if user2 has rwx, mask limits to rx

Practical ACL Examples

Shared project directory:

## Create directory
mkdir /projects/webapp
sudo chown :developers /projects/webapp

## Set base permissions
chmod 770 /projects/webapp

## Give manager read-only access
setfacl -m u:manager:rx /projects/webapp

## Set default ACLs for new files
setfacl -d -m g:developers:rwx /projects/webapp
setfacl -d -m u:manager:rx /projects/webapp

Web server content with multiple maintainers:

## Give multiple users write access
setfacl -R -m u:alice:rwx,u:bob:rwx /var/www/html
setfacl -R -d -m u:alice:rwx,u:bob:rwx /var/www/html

## Maintain web server group access
setfacl -R -m g:www-data:rx /var/www/html

Backing Up and Restoring ACLs

## Backup ACLs
getfacl -R /path > acls-backup.txt

## Restore ACLs
setfacl --restore=acls-backup.txt

SELinux: Security-Enhanced Linux

SELinux implements Mandatory Access Control (MAC), adding an additional security layer beyond traditional permissions.

SELinux Concepts

SELinux provides:

  • Process isolation
  • Least privilege access
  • Protection against zero-day exploits
  • Role-based access control

SELinux modes:

  • Enforcing: SELinux policy is enforced
  • Permissive: Violations logged but not blocked
  • Disabled: SELinux is turned off

SELinux context:

Every file, process, and port has a security context:

user:role:type:level

Example: system_u:object_r:httpd_sys_content_t:s0

  • user: SELinux user
  • role: SELinux role
  • type: Most important, determines access
  • level: MLS/MCS level

Checking SELinux Status

## Check SELinux status
sestatus

## Check current mode
getenforce

## View security contexts
ls -Z /var/www/html
ps -eZ | grep httpd

Changing SELinux Modes

Temporary change:

## Set to permissive
sudo setenforce 0

## Set to enforcing
sudo setenforce 1

Permanent change:

Edit /etc/selinux/config:

SELINUX=enforcing
SELINUXTYPE=targeted

Options:

  • SELINUX=enforcing: Enforce SELinux policy
  • SELINUX=permissive: Log violations only
  • SELINUX=disabled: Turn off SELinux

Reboot required for changes to take effect.

Managing SELinux Contexts

View file contexts:

ls -Z /var/www/html/index.html

Change file context:

## Change type
sudo chcon -t httpd_sys_content_t /var/www/html/file.html

## Change complete context
sudo chcon -u system_u -r object_r -t httpd_sys_content_t file.html

## Recursive change
sudo chcon -R -t httpd_sys_content_t /var/www/html

Restore default contexts:

## Restore file to default context
sudo restorecon /var/www/html/file.html

## Recursive restore
sudo restorecon -R /var/www/html

## Restore with verbose output
sudo restorecon -Rv /var/www/html

SELinux Booleans

Booleans enable/disable specific SELinux features.

## List booleans
getsebool -a

## Check specific boolean
getsebool httpd_can_network_connect

## Set boolean temporarily
sudo setsebool httpd_can_network_connect on

## Set boolean permanently
sudo setsebool -P httpd_can_network_connect on

Common booleans:

  • httpd_can_network_connect: Allow httpd to connect to network
  • httpd_enable_homedirs: Allow httpd to access home directories
  • ftpd_anon_write: Allow anonymous FTP uploads

Managing SELinux Policies

View policies:

## List policy modules
semodule -l

## View policy details
seinfo
sesearch --allow -s httpd_t -t httpd_sys_content_t

Troubleshooting SELinux:

## View denials
sudo ausearch -m avc -ts recent

## Generate policy from denials
sudo audit2allow -a

## Create and install custom policy
sudo audit2allow -a -M mypolicy
sudo semodule -i mypolicy.pp

Practical SELinux Examples

Allow web server to serve files:

## Set correct context
sudo semanage fcontext -a -t httpd_sys_content_t "/web/html(/.*)?"
sudo restorecon -Rv /web/html

Allow application to bind to non-standard port:

## Allow httpd to bind to port 8080
sudo semanage port -a -t http_port_t -p tcp 8080

Troubleshoot SELinux denials:

## Check for denials
sudo ausearch -m AVC -ts recent

## View human-readable explanations
sudo sealert -a /var/log/audit/audit.log

AppArmor: Application Armor

AppArmor is an alternative MAC system, primarily used in Ubuntu and SUSE.

AppArmor vs SELinux

AppArmor:

  • Simpler to use
  • Path-based access control
  • Easier profile creation
  • Default on Ubuntu/Debian

SELinux:

  • More comprehensive
  • Label-based access control
  • Finer-grained control
  • Default on RHEL/Fedora/CentOS

AppArmor Modes

Enforce mode: Policy violations are blocked Complain mode: Violations logged but allowed

Checking AppArmor Status

## Check status
sudo aa-status

## View loaded profiles
sudo apparmor_status

Managing AppArmor Profiles

Profile locations:

  • /etc/apparmor.d/: Profile definitions
  • /etc/apparmor.d/disable/: Disabled profiles

Enable profile:

## Enforce mode
sudo aa-enforce /etc/apparmor.d/usr.bin.firefox

## Complain mode
sudo aa-complain /etc/apparmor.d/usr.bin.firefox

Disable profile:

sudo ln -s /etc/apparmor.d/usr.bin.firefox /etc/apparmor.d/disable/
sudo apparmor_parser -R /etc/apparmor.d/usr.bin.firefox

Reload profiles:

sudo systemctl reload apparmor

Creating AppArmor Profiles

Generate profile:

## Generate profile interactively
sudo aa-genprof /usr/bin/myapp

## Run application, exercise all functions
## aa-genprof monitors and builds profile

## Finalize profile

Manually create profile:

Example profile /etc/apparmor.d/usr.bin.myapp:

#include <tunables/global>

/usr/bin/myapp {
  #include <abstractions/base>
  #include <abstractions/nameservice>

  # Allow reading configuration
  /etc/myapp/** r,
  
  # Allow reading and writing data
  /var/lib/myapp/** rw,
  
  # Allow network access
  network inet stream,
  
  # Allow executing helper programs
  /usr/bin/helper rix,
  
  # Deny everything else by default
}

Load profile:

sudo apparmor_parser -r /etc/apparmor.d/usr.bin.myapp

Troubleshooting AppArmor

View denials:

sudo dmesg | grep apparmor
sudo journalctl | grep apparmor

Audit log:

sudo aa-logprof

This tool helps update profiles based on denied actions.

Practical AppArmor Examples

Confine web browser:

## Put Firefox in complain mode
sudo aa-complain firefox

## Run Firefox, observe behavior
## Use aa-logprof to update profile

## Switch to enforce mode
sudo aa-enforce firefox

Restrict custom application:

## Create basic profile
sudo aa-autodep myapp

## Fine-tune with genprof
sudo aa-genprof /usr/local/bin/myapp

## Enforce the profile
sudo aa-enforce /usr/local/bin/myapp

Best Practices

Permission Best Practices

  1. Principle of least privilege: Grant minimum necessary permissions
  2. Regular audits: Periodically review file permissions
  3. Avoid 777: Never use unless absolutely necessary
  4. Secure sensitive files: 600 for private keys, passwords
  5. Proper directory permissions: 755 for most, 750 for restricted
  6. Web server content: 644 for files, 755 for directories
  7. Use groups effectively: Organize users into groups for easier management

ACL Best Practices

  1. Document ACLs: Keep records of ACL configurations
  2. Use default ACLs: Set defaults for shared directories
  3. Backup ACLs: Include in backup procedures
  4. Avoid ACL sprawl: Don’t overcomplicate with too many ACL entries
  5. Monitor ACL changes: Track modifications to sensitive files

SELinux/AppArmor Best Practices

  1. Don’t disable: Keep enforcing mode enabled
  2. Fix issues properly: Don’t blindly accept policy changes
  3. Use audit2allow carefully: Review suggested changes
  4. Test in permissive: Test policy changes before enforcing
  5. Keep updated: Update policies with system updates
  6. Document exceptions: Record any custom policies or booleans
  7. Regular audits: Review logs for violations

Security Checklists

File Permission Security Checklist

## Find world-writable files
find / -type f -perm -002 2>/dev/null

## Find files with no owner
find / -nouser -o -nogroup 2>/dev/null

## Find SUID/SGID files
find / -perm -4000 -o -perm -2000 2>/dev/null

## Check sensitive files
ls -l /etc/passwd /etc/shadow /etc/sudoers

## [Secure SSH](https://terabyte.systems/posts/how-to-secure-ssh-access-linux-servers/) keys
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
chmod 700 ~/.ssh

## Secure web server files
find /var/www -type f -exec chmod 644 {} \;
find /var/www -type d -exec chmod 755 {} \;

MAC System Security Checklist

## Verify SELinux/AppArmor is running
sestatus  # or aa-status

## Check for violations
ausearch -m AVC -ts today  # SELinux
dmesg | grep apparmor      # AppArmor

## Verify critical services are confined
ps -eZ | grep httpd        # SELinux
aa-status                  # AppArmor

## Review custom policies
semodule -l                # SELinux
ls /etc/apparmor.d/        # AppArmor

Conclusion

Linux provides multiple layers of access control, from traditional Unix permissions to advanced MAC systems. Understanding how to properly configure permissions, leverage ACLs for fine-grained control, and utilize SELinux or AppArmor for mandatory access control is essential for maintaining secure systems.

Traditional permissions form the foundation, ACLs extend flexibility for complex sharing scenarios, and MAC systems provide defense-in-depth protection against compromised applications. Used together, these mechanisms create robust, secure Linux environments resistant to unauthorized access and privilege escalation attacks.

Security is not a one-time configuration but an ongoing process. Regular audits, appropriate permission settings, and proper use of MAC systems significantly reduce security risks and protect valuable data and resources.


References

Thank you for reading! If you have any feedback or comments, please send them to [email protected].