Linux chmod Command Deep Dive: A Complete Guide from Permission Bits to Symbolic Mode
Linux chmod Command Deep Dive: A Complete Guide from Permission Bits to Symbolic Mode#
As a Linux system administrator, chmod is a command I use daily. The seemingly simple permission management actually has a rigorous design logic behind it. Today let’s talk about the implementation principles of chmod and some easily overlooked details.
The Essence of Permissions: Three Groups of Three Bits#
Linux file permissions are represented by 9 bits, divided into three groups:
Owner Group Other
rwx rwx rwx
111 101 100
7 5 4
- Owner: File creator
- Group: Members of the file’s group
- Other: All other users
Each group has three bits representing:
r(read): Read permission, value 4w(write): Write permission, value 2x(execute): Execute permission, value 1
This is why we commonly use commands like chmod 755 file — 7=4+2+1 (rwx), 5=4+1 (r-x), 5=4+1 (r-x).
Implementation of Numeric Mode#
The essence of permission calculation is bit operations. Assuming current permission is 755 (binary 111101101), we want to remove owner’s write permission:
# Current permission: 111101101 (755)
# Target permission: 101101101 (555)
# Operation: AND operation
chmod 555 file
At the kernel level, the permission check pseudo-code:
// fs/namei.c - Linux kernel permission check
int inode_permission(struct inode *inode, int mask)
{
umode_t mode = inode->i_mode;
int retval;
// Check permission bits
if (mask & MAY_READ) {
if (!(mode & S_IRUGO)) // No read permission
return -EACCES;
}
if (mask & MAY_WRITE) {
if (!(mode & S_IWUGO)) // No write permission
return -EACCES;
}
if (mask & MAY_EXEC) {
if (!(mode & S_IXUGO)) // No execute permission
return -EACCES;
}
return 0; // Permission check passed
}
Symbolic Mode: More Intuitive Permission Modification#
While numeric mode is concise, it’s not intuitive. Symbolic mode allows precise control of permission changes:
# Add execute permission for owner
chmod u+x script.sh
# Remove write permission for group
chmod g-w config.txt
# Set read-only permission for others
chmod o=r file.txt
# Add read permission for everyone
chmod a+r README.md
The advantage of symbolic mode: only modify needed permission bits, without affecting other bits.
Symbolic mode implementation logic:
def apply_symbolic_permission(current_mode, who, operator, permission):
"""
who: u/g/o/a
operator: +/-
permission: r/w/x
"""
# Permission bit mapping
perm_bits = {'r': 4, 'w': 2, 'x': 1}
# User group offset
who_shift = {'u': 6, 'g': 3, 'o': 0}
# Calculate target bits
target_bits = perm_bits[permission] << who_shift[who]
if operator == '+':
# Add permission: OR operation
return current_mode | target_bits
elif operator == '-':
# Remove permission: AND + NOT operation
return current_mode & ~target_bits
elif operator == '=':
# Set permission: clear first, then set
mask = 7 << who_shift[who] # Clear all bits of target group
cleared = current_mode & ~mask
return cleared | (perm_bits[permission] << who_shift[who])
# Example: current permission 644, add write permission for group
current = 0o644 # 110100100
new_mode = apply_symbolic_permission(current, 'g', '+', 'w')
# Result: 0o664 = 110110100
Special Permission Bits: SUID/SGID/Sticky Bit#
Besides the 9 regular permission bits, there are 3 special permission bits:
SUID (Set User ID, value 4)#
chmod u+s /usr/bin/passwd
- When executing the file, the process’s effective user ID becomes the file owner
- Typical use:
passwdcommand (normal users need to write/etc/shadowto change passwords) - Security risk: SUID program vulnerabilities may lead to privilege escalation
SGID (Set Group ID, value 2)#
chmod g+s /shared/project/
For directories: newly created files inherit the directory’s group For files: when executed, process’s effective group ID becomes the file’s group
Sticky Bit (value 1)#
chmod +t /tmp
- Used for directories: only file owners can delete their own files
- Typical use:
/tmpdirectory (prevents users from deleting others’ temporary files)
Complete special permission settings:
# SUID + regular permission 755
chmod 4755 file
# SGID + regular permission 775
chmod 2775 directory
# Sticky Bit + regular permission 777
chmod 1777 /tmp
Common Pitfalls and Best Practices#
Pitfall 1: Recursive Permission Modification#
# Wrong: modifies both files and directories
chmod -R 755 /var/www
# Correct: handle files and directories separately
find /var/www -type d -exec chmod 755 {} \;
find /var/www -type f -exec chmod 644 {} \;
Files typically don’t need execute permission. Recursively setting 755 makes all files executable, creating security risks.
Pitfall 2: Symbolic Link Permissions#
# Symbolic link permissions are always 777
# chmod modifies target file's permissions, not the link itself
ln -s target.txt link.txt
chmod 600 link.txt # Actually modifies target.txt's permissions
Pitfall 3: umask Impact#
# Current umask is 022
# Default permission for files: 666 - 022 = 644
# Default permission for directories: 777 - 022 = 755
umask 077 # Stricter permission setting
touch newfile.txt # Permission becomes 600
Web Implementation: Permission Calculator#
In JsonKit’s Chmod Calculator tool, we implemented a visual permission calculator:
interface PermissionState {
owner: { read: boolean; write: boolean; execute: boolean };
group: { read: boolean; write: boolean; execute: boolean };
other: { read: boolean; write: boolean; execute: boolean };
suid: boolean;
sgid: boolean;
sticky: boolean;
}
function calculatePermission(perm: PermissionState): number {
let mode = 0;
// Owner permissions (bits 6-8)
if (perm.owner.read) mode |= 0o400;
if (perm.owner.write) mode |= 0o200;
if (perm.owner.execute) mode |= 0o100;
// Group permissions (bits 3-5)
if (perm.group.read) mode |= 0o040;
if (perm.group.write) mode |= 0o020;
if (perm.group.execute) mode |= 0o010;
// Other permissions (bits 0-2)
if (perm.other.read) mode |= 0o004;
if (perm.other.write) mode |= 0o002;
if (perm.other.execute) mode |= 0o001;
// Special permissions (bits 9-11)
if (perm.suid) mode |= 0o4000;
if (perm.sgid) mode |= 0o2000;
if (perm.sticky) mode |= 0o1000;
return mode;
}
// Example: calculate 755 permission
const result = calculatePermission({
owner: { read: true, write: true, execute: true },
group: { read: true, write: false, execute: true },
other: { read: true, write: false, execute: true },
suid: false,
sgid: false,
sticky: false
});
console.log(result.toString(8)); // "755"
Summary#
While the chmod command is simple, the permission management mechanism behind it involves the core of Linux security model. Understanding the binary representation of permission bits, the operation logic of symbolic mode, and the application scenarios of special permissions can help us better manage system security.
Next time using chmod, think one step further: what is the current permission state? Which bits need precise modification? Are special permissions needed? This can avoid many security risks.
Related Tools#
- Chmod Calculator - Visual permission calculator
- Linux Command Reference - 150+ Linux command reference
- Permission Analyzer - File permission analysis tool