# linux的文件权限及符号

# 普通权限

r-读 w-写 x-执行。 注意:x权限对于目录来说是进入目录的权限。比如用root创建一个目录,去掉x权限,普通用户即使有r权限,也无法进入该目录。

# 特殊权限

有三个:SUIDSGIDSticky,其中SUIDSGIDls命令中显示为s或大写SSUID显示为t或大写T

# SUID

内核在确定进程的访问权限时,会看进程的euid和egid(effective id,有效id)。一个文件如果设置了SUID,它的euid等于该文件所属用户的uid,如果未设置,则等于当前用户的uid,gid同理。

比如用户bob的uid是1003,gid是1003,文件myfile的权限如下:

-rw-rw-r-- 1 bob bob 3 Jan 23 07:32 myfile

此时myfile的所属用户是bob,未设置SUID,则euid=bob的uid=1003。

如果给myfile设置了SUID位,当另一个用户tom(uid为1005)来运行myfile时,原本uid应为tom的1005,但由于设置了SUID,myfile的所属用户是bob,所以此时euid=bob的uid=1003

root@ubuntu01:/tmp# chmod u+s myfile 
root@ubuntu01:/tmp# ls -al myfile
-rwSrw-r-- 1 bob bob 3 Jan 23 07:32 myfile

最常见的一个例子:用户的密码保存在/etc/shadow,但此文件只有root才能写,普通用户要修改密码时就通过SUID位临时获取root权限,写入密码。

root@ubuntu01:/tmp# ls -al /usr/bin/passwd 
-rwsr-xr-x 1 root root 54256 May 16  2017 /usr/bin/passwd
# 用户位设置了SUID

除了passwd命令外,pingcrontabmount等命令都有设置,可通过find / -perm /4000 来查看系统内设置了SUID的文件

需注意的是SUID只对二进制文件有效,且是临时获取一下权限,进程结束时就释放了。

做个小实验验证下:

编辑文件setuid.c,添加如下代码:

#include <stdio.h>
#include <unistd.h>
#include <time.h> 
int main () {
  int real = getuid();
  int euid = geteuid();
  FILE *fp = NULL;
  char buff[20];
  time_t now = time(NULL);

  // 打印用户的uid
  printf("The REAL UID =: %d\n", real);
  // 打印运行时的uid
  printf("The EFFECTIVE UID =: %d\n", euid);

  // 格式化一下当前时间 
  strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(&now));  

  // 将时间写入只有root权限的文件中
  fp = fopen("/root/test.txt", "a");
  fputs(("%s",buff), fp);
  fputs("\n", fp);
  fclose(fp);

  // 打印下结果
  printf("%s fputs current time to test.txt\n",buff);
}

这段代码很简单:打印下用户的uid和运行时的uid(即内核认可的euid),并将当前的时间写到root目录的test.txt文件中。

首先编译下:

root@ubuntu01:/tmp# gcc -o setuid setuid.c

查看下权限:

root@ubuntu01:/tmp# ls -al setuid
-rwxr-xr-x 1 root root 9120 Jan 23 08:00 setuid

直接运行,可以看到root目录下增加了test.txt,uid是0,euid也是0,且/root/下有一个test.txt,里面写入了当前时间:

root@ubuntu01:/tmp# ./setuid 
The REAL UID =: 0
The EFFECTIVE UID =: 0
2019-01-23 08:04:40 fputs current time to test.txt
root@ubuntu01:/tmp# cat /root/test.txt 
2019-01-23 08:04:40

切换到bob用户来测试下:

root@ubuntu01:/tmp# su bob
bob@ubuntu01:/tmp$ ./setuid 
The REAL UID =: 1003
The EFFECTIVE UID =: 1003
Segmentation fault (core dumped)

可以看到,uid和euid都是1003,由于普通用户无权限写入/root/test.txt,所以报错Segmentation fault了。

此时设置setuid的SUID,再用bob用户来运行试试:

# 设置SUID
root@ubuntu01:/tmp# chmod u+s setuid
root@ubuntu01:/tmp# ls -al setuid
-rwsr-xr-x 1 root root 9120 Jan 23 08:00 setuid

# 切换到bob来运行
root@ubuntu01:/tmp# su bob
bob@ubuntu01:/tmp$ ./setuid 
The REAL UID =: 1003
The EFFECTIVE UID =: 0
2019-01-23 08:10:14 fputs current time to test.txt
bob@ubuntu01:/tmp$ exit
exit

# 看下是否写入到了/root/test.txt 
root@ubuntu01:/tmp# cat /root/test.txt 
2019-01-23 08:04:40
2019-01-23 08:10:14

可以看到当前的uid是1003,但运行时的uid变成0了,且将时间写到了/root/test.txt 中。

# SGID

sgid对文件设置时和suid的用途一致,对目录设置时,其作用是:在该目录下创建的文件将继承该目录属组的权限,而非创建者本身。 可做个列子验证下:

1.在tmp目录下创建一个sgid目录,且设置SGID:

root@ubuntu01:/tmp# mkdir sgid
root@ubuntu01:/tmp# chmod o+w sgid
root@ubuntu01:/tmp# chmod g+s sgid
root@ubuntu01:/tmp# ls -al | grep sgid
drwxr-srwx   2 root root 4096 Jan 23 08:39 sgid

2.切换到bob用户,在sgid目录下创建一个文件

root@ubuntu01:/tmp# su bob
bob@ubuntu01:/tmp$ cd sgid
bob@ubuntu01:/tmp/sgid$ touch test

3.查看下权限

bob@ubuntu01:/tmp/sgid$ ls -al test
-rw-rw-r-- 1 bob root 0 Jan 23 08:41 test

可以看到该文件的属组是root

# Sticky

Sticky又称SBIT,其作用是:在该目录创建的文件或目录只有创建者才有权限删除

最常见的例子就是/tmp目录了,所有用户都可以在该目录下创建文件或文件夹,其他用户可以查看,但无法删除。

可以做如下实验:

使用普通用户bob在/tmp目录下创建一个文件test,且权限为777。
切换到另一个普通用户scboy,可以对test进行读写,但无法删除,提示:
rm: cannot remove 'test': Operation not permitted

# 设置SUID,SGID,Sticky

SUID权限位是4,SGID权限位是2,Sticky权限位是1,同时设置SUID和SGID,则为6。

例子: 1.设置myfile的SGID位,用户权限是rwx,组权限是r,其他权限r

# 设置
root@ubuntu01:/tmp# chmod 2744 myfile
# 查看下
root@ubuntu01:/tmp# ls -al myfile 
-rwxr-Sr-- 1 bob bob 3 Jan 23 07:32 myfile

2.设置test目录的Sticky为,用户权限是rwx,组权限是rwx,其他权限rwx

root@ubuntu01:/tmp# mkdir test
root@ubuntu01:/tmp# chmod 1777 test
root@ubuntu01:/tmp# ls -al /tmp | grep test
drwxrwxrwt   2 root  root  4096 Jan 23 08:53 test

# ACL

如果某个目录配置了ACL权限,通过ls命令查看时,在权限部分会看到有个+号。

# 安装acl

# CentOS/Fedora/RHEL 中:
yum install acl

# Ubuntu/Debian 中:
apt install acl

查看文件系统是否支持 ACL

root@ubuntu01:/tmp# dumpe2fs -h /dev/md126p2 | grep acl
dumpe2fs 1.42.13 (17-May-2015)
Default mount options:    user_xattr acl

加载 ACL 功能

如果 UNIX LIKE 支持 ACL 但是文件系统并不是默认加载此功能,可自己进行添加

root@ubuntu01:/tmp# mount -o remount,acl /

同样也可以将acl加到/etc/fstab中,默认开机加载。

LABEL=/                 /                       ext3    defaults,acl        1 1

# 测试下

1.用root在/tmp下创建一个acldir目录,给普通用户添加访问权限

mkdir acldir
setfacl -m u:bob:x ./acldir/ 

这时bob就可以进入acldir了

2.查看下该目录的acl信息

root@ubuntu01:/tmp# getfacl ./acldir/
# file: acldir/
# owner: root
# group: root
user::rwx
user:bob:--x
group::r-x
mask::r-x
other::r-x

3.添加组acl权限

setfacl -m g:test:rx ./acldir/

4.删除acl权限

setfacl -x u:bob ./acldir
setfacl -x g:test ./acldir

# 其他特殊符号

  1. 有时候用ls命令看某个目录或文件时,在权限部分的末尾有个.点号,这是开启了selinux时会有的,表示带有SELinux的安全上下文https://blog.csdn.net/xinlongabc/article/details/46801641
  2. 一个文件如果有多种访问措施,用+标记;如果同时用了selinux和acl,用+标记;如果只有acl,用+标记。
  3. 在mac系统中用ls查看时,可能会看到含有@符号,这个符号是osx特有的,表示某个文件或目录的一种特有属性,可用xattr命令来查看。