4.1 > Linux 文件/目录权限管理【理论】
概览
在上一节中我们对 Linux 和 Bash 进行了快速上手,那么本章主题就是文件、目录的权限管理。本小节主题:全方位了解 Linux 的文件属性、权限、ACL等知识。
本节目录
- 概览
- 文件类型与属性
- 文件类型
- 文件属性
- 常规属性
- 隐藏属性
- 扩展属性
- 软链接 & 硬链接
- 权限控制
- 基本权限(POSIX 模型)
- 特殊权限
- 默认权限
- ACL
- LSM
- 权限检查顺序
- 附加
文件类型与属性
在 Linux 和其他类 Unix 操作系统中,“一切皆文件” 是一种核心且非常强大的设计哲学。它意味着操作系统中几乎所有的资源和设备,从硬件到进程间通信,都被抽象和表示为一个文件。这种设计原则带来了极大的简洁性、一致性和灵活性,同样也是 Linux 能够高效运行的关键因素之一。
Linux 文件和目录架构图:(基于 Rocky 9 发行版)
[test@server1 ~]$ tree -L 1 /
/ # 根目录
├── afs # 分布式文件系统(AFS,Andrew File System)挂载点
├── bin -> usr/bin # 存放常用的基本命令
├── boot # 存放启动相关文件,例如内核(vmlinuz)、引导加载器(grub2)
├── dev # 存放设备文件(如磁盘、终端、USB)
├── etc # 存放系统配置文件(系统的灵魂目录)
├── home # 普通用户的家目录,每个用户在此下有一个子目录
├── lib -> usr/lib # 系统运行所需的共享库文件(相当于 Windows 的 DLL)
├── lib64 -> usr/lib64 # 同 lib 链接
├── mnt # 用于临时挂载外部设备(如 USB、光盘)
├── opt # 存放第三方软件或手动安装的软件包
├── proc # 虚拟文件系统,提供内核和进程的实时信息(非真实文件)
├── root # 超级用户家目录
├── run # 存放系统运行时数据(PID 文件、socket、锁文件等),系统重启后会清空
├── sbin -> usr/sbin # 存放系统管理员使用的命令
├── srv # 存放服务器提供的服务数据(如 Web、FTP 等)
├── sys # 虚拟文件系统,提供与内核对象、设备和驱动的交互接口
├── tmp # 存放临时文件,系统重启后会清空
├── usr # 用户级程序和文件,包括系统命令、库、文档等(相当于 Windows 的 Program Files 目录)
└── var # 存放经常变化的文件,如日志、缓存、邮件、数据库等# 此目录结构定义遵循 FHS (Filesystem Hierarchy Standard) 标准(由 Linux 基金会维护,规范了每个目录的用途,确保所有发行版结构一致)
那么,究竟如何理解 “一切皆文件” 这句话,我是这么解释的:
- 统一的抽象层: 无论是普通文件、目录、硬件设备、套接字,还是正在运行的进程信息,内核都能通过一个统一的接口 —— 文件描述符 (FD) 来管理和操作它们。
- 统一的系统调用: 用户程序可以使用一套标准化的系统调用(如 open(),read(),write(),close() 等)来处理几乎所有这些资源,而无需了解底层资源的具体细节。
- 简化设备访问: 硬件设备(如键盘、终端、磁盘、打印机)在文件系统中被表示为特殊文件(如设备文件),通常位于 /dev 目录下。通过读写这些“文件”,程序就能与硬件进行通信。
既然已经知道了什么是 “一切皆文件”了,那么该如何实现,或者说该如何来定义这些各种各样的文件呢,这就引出了下面的 Linux 文件类型。
文件类型
类型 | 符号 | 描述 | 可执行 | 存储数据 | 用于通信 | 示例 |
---|---|---|---|---|---|---|
普通文件 | - | 包含数据、文本或程序代码,是最常见的文件类型 | ✅ | ✅ | ❌ | /etc/passwd |
目录 | d | 包含其他文件和目录的列表,是文件系统的结构 | ✅ | ✅ | ❌ | /etc;/usr/local |
符号链接 | l | 类似于 Windows 的快捷方式,指向另一个文件或目录 | ❌ | ✅ | ❌ | tmp -> /var/tmp |
块设备 | b | 用于像磁盘、CD-ROM 等以块为单位进行输入/输出的设备 | ❌ | ✅ | ✅ | /dev/nvme0n1 |
字符设备 | c | 用于像终端、键盘、打印机等以字节流为单位进行输入/输出的设备 | ❌ | ✅ | ✅ | /dev/tty;/dev/null |
命名管道 | p | 用于不同进程之间进行单向通信的特殊文件 | ❌ | ❌ | ✅ | /tmp/testfifo |
套接字 | s | 用于网络通信(如 TCP/IP)或本地进程间通信 | ❌ | ❌ | ✅ | /var/run/docker.sock |
文件属性
文件属性,或者叫文件元数据,它是用来描述和管理文件的一系列信息,这些信息与文件的实际数据(文件的内容)是分开存储的。举个例子,你可以把文件属性想象成图书馆里卡片目录上的信息:卡片上告诉了你书名、作者、出版日期、借阅状态和位置,但卡片本身并不包含书中的文字。
在 Linux 中,这些属性通常存储在一个叫做 i-node(索引节点)的数据结构中。每个文件都有一个唯一的 i-node,它包含了文件的所有属性。
常规属性
-
文件类型和权限:最直接可见的属性,用于控制谁可以访问文件以及如何访问
属性 描述 文件类型 文件的类别(文件类型表中的各种类型) 访问权限 决定了文件的所有者、所属组和其他用户对文件能执行的操作 特殊权限 SUID、SGID、Sticky Bit,它们用于控制程序执行和目录行为 -
所有权:定义了谁拥有该文件以及哪些用户组与该文件相关联
属性 描述 所有者(owner) 创建或拥有该文件的用户 所属组(group) 与该文件相关联的用户组 -
时间戳:记录了文件相关的三个关键时间点,这对于备份、维护和安全审计至关重要
属性 描述 创建时间(birth time / crtime) 文件被创建的时间,仅部分文件系统(ext4、btrfs)支持,非 POSIX 标准。 访问时间(atime) 文件内容最后一次被读取的时间 修改时间(mtime) 文件内容最后一次被修改的时间(不包括权限或所有者变更) 变更时间(ctime) 文件的 i-node 元数据(如权限、所有权等)最后一次被修改的时间(文件内容修改也会同时更新 ctime) 注意事项:
- 读目录、执行程序也会更新 atime。
- Linux 有几种 atime 策略(relatime, noatime, strictatime)可能不会每次访问都更新,以提高性能。
-
存储信息和标识符:这些属性是系统用来追踪文件在文件系统中的实际位置和链接关系的关键信息
属性 描述 i-node 号 文件的唯一标识符,内核通过这个编号找到文件的元数据 硬链接数 有多少个目录条目(文件名)指向这个 i-node 文件大小 文件内容的字节数。对于目录,通常是一个固定的、较小的数字 块数 文件在磁盘上实际占用的数据块数量
隐藏属性
隐藏属性用于对文件的行为施加更严格或更专业的限制。它们通常用于系统安全和文件保护。这些属性存储在文件的 i-node 中,但并不通过 ls -l 显示。你需要使用特定的命令来查看和设置它们。
其属于 Ext 系列文件系统的专属特性(ext2/3/4),非 POSIX 标准
扩展属性
扩展属性是一组用于存储文件系统未定义的额外元数据(Metadata)的机制,它们是与文件数据和标准权限信息分开存储的键值对。允许应用程序或系统为文件添加任意的、自定义的信息。
下面是上述两种特殊属性的总结表:
特性 | 隐藏属性 | 扩展属性 |
---|---|---|
存储位置 | i-node 特定字段 | i-node 附加空间 / 文件系统特定区域 |
作用 | 文件行为控制(保护、追加、不可删除) | 存储任意元数据(ACL、SELinux context、用户自定义信息) |
是否用于访问控制 | 部分影响(只能保护文件不被改/删) | 可完全用作访问控制(ACL、SELinux、AppArmor 等) |
软链接 & 硬链接
软链接 (Symbolic Link) 和 硬链接 (Hard Link) 是 Linux 文件系统的重要概念。它们都允许你在不同的位置通过不同的名称访问同一个文件,但它们的工作原理和影响却大不相同。
每个文件都会有一个 i-node
元数据,它里面记录了此文件在系统中的唯一编号。而链接的本质就是:建立额外的“文件名”指向同一个或另一个 i-node
。
那么为什么会存在软连接和硬链接呢,当然是为了灵活性和方便管理考虑,下面的表格就展示了它们的区别:
对比项 | 硬连接 | 软链接 |
---|---|---|
定义 | 指向相同的 i-node,是同一个文件的不同名字 | 一个独立文件,保存着目标文件的路径 |
i-node情况 | 共享同一个 i-node | 拥有自己的 i-node |
链接目录 | 不可以(防止递归循环) | 可以 |
跨文件系统 | 不可以( i-node 在不同分区中不唯一) | 可以 |
原文件删除后的影响 | 内容仍在(其他硬链接仍可访问) | 链接失效,变为死链 |
存储方式 | 目录项直接指向同一个 i-node | 文件内容保存着目标路径字符串 |
空间占用情况 | 与原文件相同(共享内容,不额外占空间) | 仅占用极少空间(只存储了路径名) |
能否很好的识别 | 不能,无法区分哪个是原文件(文件类型 - ) | 可以,会显示 → 符号(文件类型 l ) |
用途 | 给文件取多个名字、备份引用 | 创建快捷方式、跨目录引用 |
注意事项:
- 符号链接本身的权限通常不生效,访问时读取的是目标文件权限。
权限控制
Linux 是多用户系统,多个用户可能同时操作系统。权限控制是用来限制谁可以对文件或目录做什么操作,以防止未经授权的访问或损坏。每个文件/目录在 Linux 中都带有权限和归属(所有者、所属组),系统在访问时会做权限检查。
知识连接:
- 什么是 POSIX:POSIX (Portable Operating System Interface) 是一个标准族,旨在确保不同操作系统的兼容性。这个权限模型就是该标准在文件访问控制方面的具体实现。
- POSIX 权限模型:这是 Linux 和其他类 Unix 操作系统(如 macOS、BSD)中最核心、最基础的访问控制机制。它是实现文件系统安全和管理的基础。其基于一个简单的三元组结构,用于决定 谁 可以对文件或目录执行 什么 操作。
基本权限(POSIX 模型)
每种用户实体(u, g, o)都可以拥有以下三种基本权限的任意组合:
权限 | 符号 | 值(掩码) | 文件上的含义 | 目录上的含义 |
---|---|---|---|---|
读 | r | 4 | 允许查看文件内容 | 允许查看目录内的文件列表(既允许对目录使用 ls) |
写 | w | 2 | 允许增删改文件内容 | 允许在目录内创建、重命名或删除文件/子目录 |
执行 | x | 1 | 允许将文件作为可执行程序运行 | 允许进入目录 (cd) 和访问目录内的文件属性 |
权限表示法:
# 由 ls -l 表示出来的方式(下图为了好看增加了空格)- r w x r - x r - - .|所有者权限| |所属组权限| |其他用户权限| 扩展特性# 上图的解释:
# 所有者权限:rwx,表示可读写执行,掩码表示为 4 + 2 + 1 = 7
# 所属组权限:r-x,表示可读可执行,不能写,掩码表示 4 + 0 + 1 = 5
# 其他用户权限: r--,表示只能读,掩码表示 4 + 0 + 0 = 4
# 特殊权限 . :表示启用了 ACL 或 SELinux(Redhat系发行版特有)权限,特殊文件系统中可能为 @(这项权限不属于 POSIX 权限模型)
# 若 x 位上出现 s/S 或 t/T,这表示此文件设置了特殊权限
特殊权限
除了标准的 POSIX 模型权限,Linux/Unix 文件系统还提供三组特殊的权限位。这些权限位影响程序的执行方式或目录下的文件创建行为,对于系统安全和功能实现至关重要。
下面是特殊权限的区别表格:
权限名称 | 符号 | 位置 | 值 | 目标对象 | 作用机制 |
---|---|---|---|---|---|
SUID | s | 所有者x 位上 | 4 | 可执行文件 | 允许执行该文件的用户暂时获得文件所有者的权限 |
SGID | s | 所属组x 位上 | 2 | 可执行文件或目录 | 对文件: 允许程序执行时暂时获得文件所属组的权限 对目录: 在该目录下创建的新文件/子目录将继承父目录的所属组(子文件/子目录继承该组) |
Sitcky Bit | t | 其他用户x 位上 | 1 | 目录 | 限制目录中文件的删除权限。只有文件所有者和目录所有者(通常是 root)可以删除或重命名文件,即使其他用户有写入权限 |
这三种特殊权限的八进制值(掩码)可以叠加在标准的权限值之前,形成一个四位数字的权限码。例如 2750,表示所属组用户在执行此文件时,暂时获得所属者的权限。
注意事项:
- 设置此权限,需要文件或目录上原本就存在执行权限(
x
),否则设置此权限无效。- 当存在执行权限的时候,设置此权限执行位上会显示
s 或 t
,否则显示S 或 T
。- SUID/SGID 对目录的作用仅限 SGID,SUID 对目录没有实际效果。
应用场景:
- SUID:常用于允许普通用户执行需要 root 权限的程序。
- SGID:常用于协作目录,使新建文件继承目录所属组。
- Sticky Bit:常见于 /tmp 目录,以防止用户删除他人的临时文件。
默认权限
当一个新文件或目录被创建时,并不是它可以拥有所有的权限。系统有一个
umask
(用户掩码),用来 禁止 某些默认权限。
- umask 是一个三位数字(有时候是四位,第一位表示特殊权限),代表 owner, group, others 应该禁止哪些权限。
- 创建新文件时,系统先给出一个默认权限(通常是
666
或777
),然后把 umask 的位从中去掉。
下面是 umask 的一个例子:
# 假设 umask = 022
# 则新文件权限 = 666 - 022 = 644
# 则新目录权限 = 777 - 022 = 755
umask 的值一般在 /etc/bashrc(系统级文件)、~/.bashrc(用户级文件)中规定。一般超级用户默认是 022,普通用户默认是 002。
ACL
当标准的 POSIX 权限无法满足细粒度的访问控制需求时,ACL(访问控制列表)就允许系统管理员为文件或目录设置额外的、特定的用户和组权限规则。
传统的三元权限组存在的问题:
- 限制三元组: 它只能为文件的所有者、所属组和其他用户定义权限。
- 缺乏细粒度控制: 如果您想让用户 A 拥有读写权限,而用户 B 拥有只读权限,但他们都属于文件的所属组,这是无法用标准权限实现的。您必须将他们移到不同的组或给“其他用户”开放权限(不安全)。
因为存在上述问题,所以 ACL 出现了,并解决了这些问题,它允许您为任意数量的单个用户或单个用户组定义精确的权限。
要想正确理解 ACL 权限,就需要正确理解 ACL Mask 的概念。它就像一个过滤器或“权限上限”,它决定了所有命名用户(user:xxx)、命名组(group:xxx)和文件所属组(group::)实际能够获得的最高有效权限。如下是 ACL 中的 mask 对照表:
条目类型 | 示例 | 受 mask 限制 | 实际权限(与运算) | 说明 |
---|---|---|---|---|
所有者(user::) | user::rw- | 否 | - | 文件所有者的权限独立,不受 mask 影响 |
命名用户(user:xxx) | user:tom:rw- | 是 | rwx && mask | 只有在 mask 允许的范围内才生效。例如 mask=r- -,则有效权限仅为 r- - |
所属组(group::) | group::rwx | 是 | rwx && mask | 所属组的权限会被 mask 限制 |
命名组(group:xxx) | group: test:rwx | 是 | rwx && mask | 与命名用户一样,受 mask 限制 |
其他用户(other::) | outer::r-- | 否 | - | 不属于任何组/用户条目的用户只受 other 限制 |
不理解没关系,下面是关于文件 ACL 的一个例子:
[test@server1 temp]$ getfacl file1 # getfacl 获取 file1 文件的 ACL 权限
user::rw- # 不受到 ACL 的影响
user:alice:rwx # 设置的 ACL 原始权限为 rwx,但要受到 mask(mask=r--) 影响,实际权限为 r--
group::r-x # 设置的 ACL 原始权限为 r-x,但要受到 mask(mask=r--)影响,实际权限为 r--
mask::r-- # 设定此文件的 mask 权限(自动设置为命名用户、命名组的最大有效权限)
other::--- # 不受 ACL 影响,没有权限# ls -l 显示 + 则表示存在 ACL 规则了
-rw-r-xr--+ 2 test test 82 10月 7 11:15 file1
上面的例子只是为了理解 ACL 权限是如何工作的,在实际用途中,mask 权限默认会随着用户的设置自动更改为最合适的新值,所以无需担心。当然,用户也可以自己控制 mask 权限的新值,不过这可能会造成文件最后的 ACL 权限超出意料之外。所以一般都不会手动设置。
ACL 的继承性:
ACL 不止可以对文件设置,也可以对目录设置。但是,对目录的设置我们一般会采用默认 ACL
来控制整个目录及下属文件和目录的 ACL 权限。
下面是两种 ACL 的对比表:
操作 影响对象 继承 说明 普通 ACL 当前文件或目录 不能 仅为当前对象 默认 ACL 目录 可以 新建的文件和目录都会继承
LSM
LSM(Linux Security Modules,Linux 安全模块)是一套内核框架,用于实现强制访问控制(MAC, Mandatory Access Control),对文件、进程、网络等资源的访问进行更严格的安全策略控制。
机制特点:
- 内核级别,在系统调用层面拦截访问请求。
- 策略可配置,不同模块有不同配置方式。
- 模块可替换,如 SELinux、AppArmor 等。
各发行版内置的安全模块介绍:
模块 | 特点 | 主流发行版 |
---|---|---|
SELinux | 基于策略(policy)的强制访问控制,控制文件、进程、网络、IPC 等 | RHEL/CentOS/Fedora 默认启用 |
AppArmor | 基于路径的访问控制,配置简单,易于维护 | Ubuntu/Debian 默认启用,SUSE 默认启用 |
TOMOYO Linux | 基于程序行为的 MAC,策略灵活 | Debian 可选 |
Smack | 简化 MAC 系统,适合嵌入式系统 | Yocto/Buildroot 等嵌入式 Linux |
LSM-sandbox / MINIMAL LSM | 内核实验模块,主要用于教学或轻量安全 | Arch/Gentoo 可选 |
SELinux 会在后续章节详细涉及,其他了解即可。
权限检查顺序
权限检查优先级如下表:
优先级 | 机制 | 作用域 |
---|---|---|
1——最高限制 | 隐藏属性控制 | 文件行为限制 |
2——强制控制 | LSM控制 | 全局安全策略 |
3——身份忽略 | root 用户控制 | 允许绕过 DAC 权限 |
4——精细DAC | ACL 权限控制 | 定制权限 |
5——基础DAC | 传统三元组控制 | 基础权限 |
权限检查流程图如下所示:
附加
文件锁(flock / fcntl)是操作系统提供的一种机制,用于控制多个进程对同一个文件的并发访问,避免数据竞争或数据损坏。属于程序级别的访问控制,不会改变文件本身的权限,但用户可通过程序接口使用。
挂载权限(mount options)是文件系统级别的安全控制,用于在挂载文件系统时对其行为进行限制,如 nosuid 禁止 SUID/SGID 生效,noexec 禁止可执行文件运行,nodev 禁止解析设备文件。它属于系统/文件系统级别的策略,普通用户无法轻易绕过。
控制手段 | 作用 | 影响范围 | 改变文件权限 |
---|---|---|---|
文件锁 | 控制并发访问,防止写冲突 | 单个文件或文件部分 | 不改变 |
挂载权限 | 限制文件系统行为,增强安全 | 整个挂载点下所有文件 | 不直接改变文件权限,但会覆盖部分行为 |
如果你觉得文章存在问题,可通过 irboxis@gamil.com 联系我,指出错误位置,我会进行核实更正,感谢各位大佬们