linux文件权限
linux文件权限分为普通权限和特殊权限,普通权限就是指文件所有者、文件所有者群组、其他用户的读、写、执行权限。特殊权限是指setuid、setgid以及stricky bits。
文件权限的查看
linux下,查看文件权限的方法最常用的就是ls -l file:
vboxuser@ubuntu20:~/Desktop/misc$ ls -lh
total 0
-rw-rw-r-- 1 vboxuser vboxuser 0 Jul 4 18:35 file
也可以用stat file:
vboxuser@ubuntu20:~/Desktop/misc$ stat file
File: file
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: 805h/2053d Inode: 2141686 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1000/vboxuser) Gid: ( 1000/vboxuser)
Access: 2025-07-04 18:35:45.391610700 +0800
Modify: 2025-07-04 18:35:45.391610700 +0800
Change: 2025-07-04 18:35:45.391610700 +0800
Birth: -
还可以用getfacl file:
vboxuser@ubuntu20:~/Desktop/misc$ getfacl file
# file: file
# owner: vboxuser
# group: vboxuser
user::rw-
group::rw-
other::r--
普通权限
得到的权限分为3个部分,三个部分为:
--- --- ---
| | |_____ 其他用户权限
| |_________ 文件所有者所属群组权限
|_____________ 文件所有者权限
每个部分又分为3种权限,依次为rwx,即读、写、执行权限。
rwx rwx rwx
其中ls -l输出的权限符号表示法的第一个符号表示文件类型:
prw-rw-r-- 1 vboxuser vboxuser 0 Jul 5 14:16 fifo
-rw-rw-r-- 1 vboxuser vboxuser 4 Jul 5 10:13 file
lrwxrwxrwx 1 vboxuser vboxuser 4 Jul 5 14:15 symbollink -> file
linux下常见的文件类型标识符为:
| 标识符 | 文件类型 | 说明 | 常见示例 |
|---|---|---|---|
- |
普通文件 (Regular file) | 文本、二进制、图像、压缩包等常规数据文件 | .txt, .sh, .jpg |
d |
目录 (Directory) | 包含其他文件和子目录的容器 | /home/, /etc/ |
l |
符号链接 (Symbolic link) | 指向另一个文件或目录的快捷方式(软链接) | link → target_file |
c |
字符设备文件 (Character device) | 按字符流式传输数据的设备文件 | /dev/tty1, /dev/random |
b |
块设备文件 (Block device) | 按数据块随机访问的设备文件 | /dev/sda, /dev/nvme0n1 |
p |
命名管道 (Named pipe) | 进程间通信的 FIFO 管道文件 (先进先出) | (由 mkfifo 命令创建) |
s |
套接字文件 (Socket) | 用于网络或进程间通信的特殊文件 | /run/systemd/private |
特殊权限
对应于普通权限的3个部分:所有者权限,所有者群组权限,其他用户权限。每个部分都有一个特殊权限,分别是:suid,sgid,sticky。
--s --s --t
--S --S --T
| | |______其他用户
| |__________所有者群组
|______________所有者
如果用数字形式表示权限,那么特殊权限就是原来八进制数字的普通权限前面的一个数值,此时需要再在前面补充一个0:
00755
01755
02755
04755
06755
ss-nnn-nnn-nnn
ss bit2:表示是否启用了suid。
ss bit1:表示是否启用了sgid。
ss bit0:表是否启用了sticky。
他们也可以按位或操作,使得同时打开几个bit位。小写表示对应部分的权限除了该特殊权限外,还同时拥有可执行权限,大写则表示仅有特殊权限,无可执行权限。
suid
suid (Set owner User ID upon execution) :执行时设置所有者uid。什么意思呢?首先要知道linux里面一个程序运行时有真实用户ID(Real uid/RUID/uid)和有效用户ID(Effective UID/EUID/euid)这两个概念,uid可以通过getuid()获得,表示谁启动了这个程序。euid通过geteuid()获取,表示进程权限从谁的角度获取。正常情况下uid == euid,而特殊权限suid就是来打破这种常规的手段。下面以例子来演示:
首先是存在一个叫thammer的用户,以及都有的root用户。有如下应用程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
printf("uid:%u euid:%u\n", getuid(), geteuid());
#if 0
int fd = open("./rootdir/filebelongroot", O_RDWR);
if ( fd < 0 )
{
perror("open filebelongroot");
exit(1);
}
printf("open success\n");
close(fd);
#endif
return 0;
}
在root账号下进行编译得到:
-rwxrwxr-x 1 root root 19K 7月 5 16:29 ctest
可以看到任何账号都对ctest有执行权限,在root账号下运行得到:
uid:0 euid:0
切换到thammer账号,运行得到:
uid:1000 euid:1000
这两id分别表示root用户和thammer用户。在root用户下给该文件加上suid权限:
chmod u+s ctest
ls -l ctest
-rwsrwxr-x 1 root root 18624 7月 5 16:52 ctest
#或者8进制格式的原权限的最高位数字设置为4
chmod 4775 ctest #原权限是0775
再次分别在root和thammer下执行,得到输出:
#root
uid:0 euid:0
#thamer
uid:1000 euid:0
根据前面uid和euid的概念,从输出来判断,可以看到启动程序的分别是root和thammer,但是程序启动后的有效权限都是继承的root(id == 0)的权限。
注意,thammer要能运行ctest,首先是对于ctest来说thammer属于other类型用户,要先有执行权限,执行起来后,通过suid机制,获得有效权限为root权限,此时root能干啥,它就能干啥。
打开屏蔽的代码,并且去掉suid权限(chmod 0775 ctest)并且以root用户创建rootdir/filebelongroot。再分别以root、thammer用户运行ctest,分别得到输出:
#root
uid:0 euid:0
open success
#thammer
uid:1000 euid:1000
open filebelongroot: Permission denied
文件rootdir/filebelongroot权限为:
-rw-r--r-- 1 root root 0 7月 5 17:13 rootdir/filebelongroot
thammer属于的other部分无写权限,open时要求读写权限(O_RDWR),所以失败了。再重新设置上suid权限,在thammer下运行:
#thammer
uid:1000 euid:0
open success
此时,正常打开,因为程序启动后,它权限是继承自root了。root对文件rootdir/filebelongroot是有读写权限的。
suid作用
sudo
一个典型的使用场景就是ubuntu,debian下的sudo。sudo运行的大致过程就是:
- 1.启动后进行鉴权(机制很多,你可以简单粗暴的认为就是检查密码)。
- 2.fork子进程,通过seteuid设置子进程euid,由于
/usr/bin/sudo权限带suid,所以子进程获得root权限。 - 3.sudo后面的参数就作为子进程运行。
passwd
passwd执行过程中会读写/etc/shadow,/etc/passwd等配置文件,而这些文件的权限通常是:
-rw-r--r-- 1 root root 2914 Jul 5 15:05 /etc/passwd
-rw-r----- 1 root shadow 1748 Jul 5 15:05 /etc/shadow
特别是shadow文件,它的other部分权限是读都不让别人读。它里面包含了用户加密后的密码,passwd修改用户自己密码过程:
-
- 访问
/etc/shadow解密得到用户密码。
- 访问
-
- 对比用户输入的原密码。
-
- 验证通过,读入新密码,更新
/etc/shadow。
- 验证通过,读入新密码,更新
而实际使用时,如果我们是修改自己账号的密码,直接执行passwd就行了,无需借助sudo,而且passwd判断被修改账号和运行账号是否为同一个,如果不是,会提示你,你不能修改别人的代码,除非你用sudo提权。如果是,则仅验证该账号原密码。
因此,实现用户修改自身账号,无需知道sudo或者root密码,即保证了灵活,又保证了安全。
实现这些也是因为/usr/bin/passwd具有suid权限。
类似的拥有suid权限的命令还有su, mount, umount, fusermount, gpasswd, pkexec等等。
sgid
和suid类似,sgid表示执行时(文件和目录对执行权限有不同的解释)设置进程权限为其组权限。sgid权限通常的应用场景是作用在目录上。
补充对可执行权限的解释:对于普通文件,可执行权限不必多说。但是对目录来说,可执行权限不再被解释为可执行,而是对目录的Access权限:
- 可进入目录。
- 访问目录内文件元数据(如文件大小,权限,时间戳,inode信息等)
- 对目录内文件进行操作(如创建,删除,重命名文件(依赖目录的w + x权限), 读取文件内容(依赖目录的r + x权限))
sgid作用
共享文件夹
假设公司有台linux服务器,大家要共享一些资料。一个很自然的想法就是创建一个共享目录,任何人都可以Access这个目录,这样的做法固然可行,但是如果我想仅团队内成员可以访问呢?
那就让其他用户对此目录无x权限吧(不能Access这个目录了)。
# ① 创建一个组,作为共享用的组
sudo groupadd devteams
# ② 创建目录,作为团队共享用
mkdir teamshare
# ③ 修改所属组以便团对成员访问
sudo chgrp devteams teamshare
# 目录的默认权限是所有者、所属组拥有全部权限,但是其他人只能看(目录的所有者是vboxuser, 可以认为他是管理员)
drwxrwxr-x 2 vboxuser devteams 4.0K Jul 7 10:36 teamshare
# ④ 让其他用户看也不能看
chmod 0770 teamshare
# 修改后的权限
drwxrwx--- 2 vboxuser devteams 4096 Jul 7 11:14 teamshare
# ⑤ 创建thomas和wendy两个用户,把devteams组加入到他们的附属组(-G)
sudo useradd thomas -m -s /bin/bash -G devteams
sudo useradd wendy -m -s /bin/bash -G devteams
# ⑥ 分别以thoma和wendy创建文件
sudo su - thomas -c "echo 'file of thomas' > /home/vboxuser/workplace/teamshare/thomas_file.txt"
sudo su - wendy -c "echo 'file of wendy' > /home/vboxuser/workplace/teamshare/wendy_file.txt"
# ⑦ 查看文件权限
-rw-rw-r-- 1 thomas thomas 15 Jul 7 15:58 thomas_file.txt
-rw-rw-r-- 1 wendy wendy 14 Jul 7 15:58 wendy_file.txt
# ⑧ 此时2个用户组属于各自的主组,互相视对方为other,只有读权限。
# 删除文件,给teamshare目录加上sgid,再创建:
sudo chmod g+s teamshare
sudo su - thomas -c "echo 'file of thomas' > /home/vboxuser/workplace/teamshare/thomas_file.txt"
sudo su - wendy -c "echo 'file of wendy' > /home/vboxuser/workplace/teamshare/wendy_file.txt"
# 共享目录获得sgid位,这里需要注意,我发现由于vboxuser的附属组里面没有devteams,所以不通过sudo执行`chmod g+s teamshare`虽然不报失败,但是修改无效果。修改成功后的权限:
drwxrwsr-x 2 vboxuser devteams 4096 Jul 7 16:05 teamshare/
# 生成的文件权限,此时文件所属组被强制修改为目录一样的所属组了,也就是sgid:set group id的意思了。两个文件主组都是devteams,均可以互相读写了。
-rw-rw-r-- 1 thomas devteams 15 Jul 7 16:14 thomas_file.txt
-rw-rw-r-- 1 wendy devteams 14 Jul 7 16:14 wendy_file.txt
上面的例子中有一个关键的地方,就是定义的共享组devteams要作为用户的附属组(-G),而不是主组(-g),如果作为主组,就完全不需要sgid机制了,因为文件创建时,它的主组就是devteams,而不需要sudo chmod g+s teamshare了。
sticky
sticky叫粘滞位,主要作用于目录。它的作用是限制目录里面的文件/目录只能被其所有者删除或者重命名等操作,即便其他用户有权限,也不让它去这么做。使得目录里面只能操作自己的文件。
sticky作用
linux系统的tmp目录
linux的tmp目录是属于一个内存文件系统(tmpfs),一些临时文件在此目录产生,用于交换一些信息。通常tmp目录的读写执行权限是777的,这样任何人都可以全权限的操作这个目录,这么设计是因为
该目录原本属于root,但是任何一个用户都有可能使用该目录做一些信息交换,这样就会带来一个问题,恶意程序可能把tmp目录删除干净,让依赖tmp目录工作的其他程序工作异常,此时引入sticky这个机制,
就使得你可以随便在这个目录产生文件,但是对于已产生的文件,你就只能老老实时的操作属于自己的,别人的你动不了。
ftp的上传目录
ftp上传目录一样可能是任意用户可以上传的,因为你限定用户或者组会导致不灵活。但是呢,又不想用户之间互相乱删文件,于是可以设置sticky位给到ftp上传目录。

浙公网安备 33010602011771号