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修改用户自己密码过程:

    1. 访问/etc/shadow解密得到用户密码。
    1. 对比用户输入的原密码。
    1. 验证通过,读入新密码,更新/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上传目录。

posted @ 2025-07-05 18:01  thammer  阅读(22)  评论(0)    收藏  举报