Linux 是 UNIX like,UNIX 是一种可以由多个用户同时访问的多用户操作系统。Linux 也可以在不进行任何修改的情况下用于大型机和服务器。但这会引发安全问题,因为未经请求或恶意的用户可能会损坏、更改或删除关键数据。为了有效的安全性,Linux 将授权分为 2 个级别:权限(permission)和所有权(ownership)

Linux 文件权限

Linux 文件权限系统基于用户(user)、用户组(group)和其他用户(other)的访问级别来控制文件和目录的访问。权限(permission)包括读取(r)、写入(w)和执行(x)。

基本概念

文件类型:共 7 种类型,需要 3 bits 即可(实际分配了 4 bits)。

表示 描述 文件类型 宏定义 八进制值
s 套接字文件 socket file S_IFSOCK 0140000
l 符号链接(软链接) symbolic link S_IFLINK 0120000
- 普通文件 regular file S_IFREG 0100000
b 块设备文件 block device S_IFBLK 060000
d 目录 directory S_IFDIR 040000
c 字符设备文件 character device S_IFCHR 020000
p 命名管道 named FIFO pipe S_IFIFO 010000

宏定义定义在文件 #include <sys/stat.h> 中,低 12 bits 为权限位,文件类型只需关心高 4bits,故低 12 bits 填充为 0。

文件权限:共三类权限,每类权限独立控制,故需要 3 bits。

  • r = read permission
  • w = write permission
  • x = execute permission
  • = no permission

所有权:三类用户,每类用户对文件权限独立控制,故共需要 3 * 3 bits。

  • user:文件拥有者。默认情况下,创建文件的人成为其拥有者。
  • group:文件拥有者所在用户组(user-group)的其他成员。属于一个组的所有用户都将具有相同的组权限来访问该文件。
  • other:除拥有者和用户组成员以外的其他用户。
Linux/Unix 中的文件权限

每个“文件”有 9 bits 权限位:每 3 个权限位分为一组,分别代表文件所有者、文件所有者所属组、其他用户。同时,具有 4 bits 的“文件”类型,用于表示 7 种类型。其它 3 bits 为特殊权限位。Linux 文件类型和模式的组织结构如下:

Linux 文件类型和模式的组织结构

Linux 命令显示示例

1
2
3
4
$ ls -l
-rw-r--r-- 1 user group 1024 Apr 18 10:00 file.txt
prw-r--r-- 1 root root 10 Apr 18 10:02 tester
drwxr-xr-x 2 root root 4096 Apr 18 13:38 data

文件权限表示方式

数字模式

在此模式下,文件权限不表示为字符,而是 表示为三位八进制数。下表给出了所有权限类型的数字。

  • 每组权限位用数字表示,r=4,w=2,x=1,然后将三个权限相加得到相应的数字。
Number Permission Type Symbol
0 No Permission ---
1 Execute --x
2 Write -w-
3 Execute + Write -wx
4 Read r--
5 Read + Execute r-x
6 Read + Write rw-
7 Read + Write + Execute rwx

例如,一个文件权限的 数字表示法 764,其对应的 符号表示法 -rwxrw-r--。其中,第一个字符代表文件类型,后面三组分别代表文件所有者、组成员、其他用户的权限。在这个示例中:

  • owner can read, write and execute
  • group can read and write
  • other can only read

符号模式

在绝对(数字)模式下,你可以同时更改 3 个所有者的权限。但是,在符号模式下,你可以修改特定所有者的权限。它利用数学符号来修改 Unix 文件权限。

操作符 描述
+ 为文件或目录添加权限
删除权限
= 设置权限并覆盖之前设置的权限

不同的所有者的表示:

标记 含义
u 用户(所有者)
g 用户组
o 其他用户
a 所有用户

示例命令

ch-change, mod-mode, own-owner, grp-group

chmod:改变文件的权限模式

  • chmod u+x file.txt:给文件所有者添加执行权限
  • chmod g-w file.txt:删除用户组的写入权限
  • chmod o=rwx file.txt:设置其它用户的文件权限位 rwx
  • chmod 644 file.txt:设置文件权限为 -rw-r--r--
  • chmod u=rwx,go+x file.txt:设置文件所有者的权限,并给用户组、其它用户添加执行权限

chown:改变文件的所有者和所属组

  • chown user:group file.txt:将文件所有者修改为 user,所属组修改为 group
  • chown root file.txt:将文件所有者修改为 root

chgrp:改变文件的所属组

  • chgrp group file.txt:将文件所属组修改为 group

UNIX 接口

stat/fstat/lstat 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    #include <sys/stat.h>

int stat(const char *restrict pathname, struct stat *restrict statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *restrict pathname, struct stat *restrict statbuf);

DESCRIPTION
These functions return information about a file, in the buffer
pointed to by statbuf. No permissions are required on the file
itself, but—in the case of stat(), fstatat(), and lstat()—execute
(search) permission is required on all of the directories in
pathname that lead to the file.

RETURN VALUE
On success, zero is returned. On error, -1 is returned, and
errno is set to indicate the error.

这些 函数返回指定文件的状态信息,存储在 statbuf 指向的缓冲区中。文件本身不需要任何权限,但在 stat()、fstatat() 和 lstat() 的情况下,需要对通向该文件的路径名中的所有目录具有执行(搜索)权限。

  • fstat() 与 stat() 相同,只是要检索其信息的文件由文件描述符 fd 指定。
  • lstat() 与 stat() 相同,只不过如果路径名是符号链接(symbolic link),则它返回有关链接本身的信息,而不是链接引用的文件的信息。

struct stat 结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <sys/stat.h>

struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512 B blocks allocated */

/* Since POSIX.1-2008, this structure supports nanosecond
precision for the following timestamp fields.
For the details before POSIX.1-2008, see VERSIONS. */

struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */

#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};

该结构中 st_mode 字段就是上文中的“Linux 文件类型和模式的组织结构”那张图,只用了 16 bits 就可以得知文件的类型和权限设置,很节省空间!下面是与 st_mode 字段相关的一些宏定义。

判断文件类型的宏定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define S_IFMT (0xF000)
/* 判断原理就是拿 m 的高 4bits 与高 4bits 全 1 的 mask 值进行与运算后,与各个文件类型的定义进行比较 */
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) // 判断文件是否是一个 directory
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) // 判断文件是否是一个 named FIFO pipe
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) // 判断文件是否是一个 character device
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) // 判断文件是否是一个 block device
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) // 判断文件是否是一个 regular file

/* 使用示例 */
int ret_code;
struct stat st;

ret_code = stat(path, &st);
assert(ret_code, 0);
S_ISREG(st.st_mode); // 判断文件是否是一个 regular file

检查文件权限的宏定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define S_IRWXU  00700 // owner has read, write, and execute permission
#define S_IRUSR 00400 // owner has read permission
#define S_IWUSR 00200 // owner has write permission
#define S_IXUSR 00100 // owner has execute permission

#define S_IRWXG 00070 // group has read, write, and execute permission
#define S_IRGRP 00040 // group has read permission
#define S_IWGRP 00020 // group has write permission
#define S_IXGRP 00010 // group has execute permission

#define S_IRWXO 00007 // others (not in group) have read, write, and execute permission
#define S_IROTH 00004 // others have read permission
#define S_IWOTH 00002 // others have write permission
#define S_IXOTH 00001 // others have execute permission

/* 使用示例,判断是否具有执行权限 */
if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH)) { }

参考资料

  1. https://rgb-24bit.github.io/blog/2018/linux-file-permission.html
  2. https://www.guru99.com/file-permissions.html
  3. https://cloud.tencent.com/developer/article/1726535