Linux 文件相关操作

文件权限

在 Linux 系统中,普通的文件权限控制通过关联身份三元组 (user, group,other) 和权限三元组 (r, w, x) 来实现访问控制。

系统存在一个 umask 值(针对用户),umask 是一个权限掩码,它决定了新建的文件或者目录的默认权限,使用 umask 命令可以查看当前(用户) 的 umask

$ umask
0022

比如如上所示的 umask 值,决定了当前(用户)创建的文件和目录的默认权限

  • 目录 - 默认权限为 0755777-022),即 rwxr-xr-x
  • 文件 - 默认权限为 644 (666-022),即 rw-r--r--

因此要配置当前(用户)创建的文件或者目录的默认权限,只需要配置合适的 umask 值即可。配置 umask 值可以通过以下方法

  • 临时方法
    umask 027
  • 永久方法
    根据需求将 umask 027 配置添加到配置文件中,如 /etc/profile~/.bashrc~/.bash_profile

如果需要更进一步的权限控制,需要使用到 Sticky Bit 和 ACL,更细力度的控制还包括 SELinux. 相关扩展权限标志如下:

  • 文件/目录 权限最后会包含一个 . : 表示 SELinux (Security Enhanced Linux)扩展权限。可以使用命令 ls -l -Z 查看具体权限。
  • 文件/目录 权限最后会包含一个 + : 表示 文件/目录ACL(Access Control List) 扩展权限,相关操作及命令参考
  • 目录 权限最后会包含一个 t : 表示此 目录Sticky Bit 扩展权限,相关操作及命令参考
  • 可执行文件 权限中属主(Owner)的 x 位变为 s : 表示此 可执行文件 配置了 Set UID 扩展权限
  • 可执行文件/目录 权限中属组(Group)的 x 位变为 s : 表示此 目录 配置了 Set GID 扩展权限

Set UID

  • 只有 可执行的二进制程序和可执行的代码 才能设定 SUID 权限。
  • 命令执行者首先要对该程序拥有 x(执行)权限。
  • 命令执行者在执行该程序时获得该程序文件 属主(Owner) 的身份。
  • SetUID 权限只在该程序 执行过程中 有效,也就是说身份改变只在执行过程中有效。

设定 SUID 和 SGID 时,传统的 3 元组权限方式(如 rwxrwxrwx = 777) 变为 4 元组(Srwxrwxrwx),其中的 S 选项包括:

  • 4 代表 SUID,如 4777
  • 2 代表 GID,如 2777
  • 1 代表 Sticky BIT,如 1777
  • 7 代表全部设置, 如 7777

SUID 设定命令格式:

chmod 4777 可执行文件名

chmod u+s 可执行文件名

取消 SUID 设置:

chmod 777 可执行文件名

假如某个可执行文件的属主为 root,其设置了 SUID,普通用户运行此可执行文件时会暂时拥有 root 的权限,有一定的风险存在,因此要谨慎设置,为系统安全考虑,要定期查找系统上拥有 SUID 权限的可执行文件并核对其是否存在风险。

Set GID

可执行文件 来说,SGID 拥有和 SUID 同样的作用,只不过 **命令执行者在执行该程序时获得该程序文件 属组(Group) 的身份。

SGID 设定方法:

chmod 2777 可执行文件名

chmod g+s 可执行文件名

Sticky Bit

粘滞位 (Sticky Bit) 只能用于目录,并对其中的文件有特殊的权限控制。他的主要作用是确保只有文件的所有者才能够删除或者修改文件。要给某个目录配置 粘滞位 (Sticky Bit) ,使用以下命令

chmod +t directoryname

这将为目录 directoryname 配置粘滞位 (Sticky Bit),以下命令可以验证 粘滞位 (Sticky Bit)是否存在。如果目录的权限列表中有 t 标志,表示目录设置了 粘滞位 (Sticky Bit)

$ ls -l directoryname
drwxrwxrwt 2 owner group 4096 Jun 26 10:15 directoryname

设置粘滞位后,只有文件的所有者才能删除或修改该文件。其他用户即使有写权限(w),也无法删除其他用户的文件。

ACL

使用访问控制列表(ACL),可以为单个文件或目录添加更细粒度的权限控制。使用的命令为 setfaclgetfacl

相比普通权限控制,文件访问控制列表(ACL)权限的优先级更高,当存在 ACL 权限时,它将覆盖普通权限。需要注意的是 ACL 权限是基于文件系统的,而不是基于传统的文件权限,因此,如果将具有 ACL 权限的文件移动到另一个文件系统,ACL 权限会丢失

setfacl 命令常用选项

选项 说明 示例
-m, --modify 修改现有的 ACL 权限
-x, --remote 移除现有的 ACL 权限
-b, --remove-all 移除文件的所有 ACL 权限
-R, --recursive 递归的应用 ACL 权限到目录及其子目录及文件
-d, --default 设置默认 ACL 权限,只适用于目录,用于控制在该目录中创建的新文件的 ACL 权限,即权限继承
默认 ACL 只影响新建的文件或目录,对现有的文件或目录不影响
-n, --no-mask 忽略文件系统的默认掩码(umask),直接应用 ACL 规则

ACL 配置示例

以下示例配置单个用户的 ACL

setfacl -m u:username:rwx filename

setfacl -R -m o::r filename

配置多个目标权限

setfacl -m u:user:rwx,g:group:rwx,o::rx directoryname

设置默认 ACL 权限,以下命令将为目录配置指定的默认 ACL 权限,默认的 ACL 权限会被此目录下新建的文件和目录继承,即新创建的目录和文件拥有和默认 ACL 一样的权限设置

setfacl -m d:u:user:rwx,d:g:group:rwx,d:o::rx directoryname

查看默认 ACL

getfacl -d directoryname

修改默认 ACL

setfacl -m d:u:user:rwx,d:g:group:rw-,d:o::--- directoryname

ACL 中的 mask 需要格外关注, 通用权限(Regular Permissions)为 ACL 权限配置了一个 mask 值,这个 mask 值配置了 ACL 有效权限的最大范围

参考以下示例,通用权限(Regular Permissions)为 644, 即使在 ACL 中为其他用户和组分配了 rw 权限,最终其有效权限任然为 r--

[mary]$ ls -l /tmp/memo.txt
-rw-rw-r--+ 1 mary mary 0 Jan 21 09:27 /tmp/memo.txt

[mary]$ chmod 644 /tmp/memo.txt

[mary]$ getfacl /tmp/memo.txt
# file: tmp/memo.txt
# owner: mary
# group: mary
user::rw-
user:bill:rw- #effective:r--
group::rw- #effective:r--
group:sales:rw- #effective:r--
mask::r--
other::r--

查看系统中打开的文件

Linux 系统中打开的文件主要保存在 system-wide open-file tableper-process open-file table 中,要查看系统中打开的文件信息,可以参考以下方法。

lsof

lsof(list open files) 是一个非常强大的工具,用于列出系统中所有打开的文件,以及文件类型、文件路径、inode 等信息

如果你想查看特定的文件或进程的打开文件,可以使用以下参数:

  • 查看特定用户的打开文件
    lsof -u <username>
  • 查看特定进程的打开文件
    lsof -p <pid>
  • 查看特定目录下的打开文件
    # lsof +D /path/to/directory
    COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
    bash 10409 root cwd DIR 259,2 51 138417276 .
    nginx 10461 root 2w REG 259,2 0 138417279 ./error.log
    nginx 10461 root 4w REG 259,2 0 138417279 ./error.log
    nginx 10462 nginx 2w REG 259,2 0 138417279 ./error.log
    nginx 10462 nginx 4w REG 259,2 0 138417279 ./error.log
    nginx 10463 nginx 2w REG 259,2 0 138417279 ./error.log
    nginx 10463 nginx 4w REG 259,2 0 138417279 ./error.log
    nginx 10464 nginx 2w REG 259,2 0 138417279 ./error.log
    nginx 10464 nginx 4w REG 259,2 0 138417279 ./error.log
    nginx 10465 nginx 2w REG 259,2 0 138417279 ./error.log
    nginx 10465 nginx 4w REG 259,2 0 138417279 ./error.log
    lsof 10500 root cwd DIR 259,2 51 138417276 .
    lsof 10501 root cwd DIR 259,2 51 138417276 .

proc 文件系统

/proc/ 虚拟文件系统提供了进程和系统信息的接口,其中 /proc/<PID>/fd/ 包含了进程打开的文件信息

# ls /proc/10461/fd/ -l
total 0
lrwx------ 1 root root 64 Aug 7 11:48 0 -> /dev/null
lrwx------ 1 root root 64 Aug 7 11:48 1 -> /dev/null
lrwx------ 1 root root 64 Aug 7 11:48 10 -> socket:[603840]
lrwx------ 1 root root 64 Aug 7 11:48 11 -> socket:[603841]
lrwx------ 1 root root 64 Aug 7 11:48 12 -> socket:[603842]
lrwx------ 1 root root 64 Aug 7 11:48 13 -> socket:[603843]
lrwx------ 1 root root 64 Aug 7 11:48 14 -> socket:[603844]
l-wx------ 1 root root 64 Aug 7 11:48 2 -> /home/logs/nginx/error/error.log
lrwx------ 1 root root 64 Aug 7 11:48 3 -> socket:[603839]
l-wx------ 1 root root 64 Aug 7 11:48 4 -> /home/logs/nginx/error/error.log
l-wx------ 1 root root 64 Aug 7 11:48 5 -> /usr/local/nginx-1.24.0/logs/access.log
lrwx------ 1 root root 64 Aug 7 11:48 6 -> socket:[615172]
lrwx------ 1 root root 64 Aug 7 11:48 7 -> socket:[615173]
lrwx------ 1 root root 64 Aug 7 11:48 8 -> socket:[615174]
lrwx------ 1 root root 64 Aug 7 11:48 9 -> socket:[615175]

fuser 命令

fuser 命令可以显示哪些进程正在使用指定的文件、目录或套接字。

# fuser error.log
/home/logs/nginx/error/error.log: 10461 10462 10463 10464

# ps -elf | grep 10461
1 S root 10461 1 0 80 0 - 11589 sigsus 11:47 ? 00:00:00 nginx: master process /usr/local/nginx-1.24.0/sbin/nginx
5 S nginx 10462 10461 0 80 0 - 43639 ep_pol 11:47 ? 00:00:00 nginx: worker process
5 S nginx 10463 10461 0 80 0 - 43639 ep_pol 11:47 ? 00:00:00 nginx: worker process
5 S nginx 10464 10461 0 80 0 - 11589 ep_pol 11:47 ? 00:00:00 nginx: cache manager process
0 S root 14099 10409 0 80 0 - 28204 pipe_w 13:10 pts/0 00:00:00 grep --color=auto 10461