Contents

Linux中的高级文件权限

1. 概述

在 Linux 中,我们知道文件可以具有执行(rwx)权限标志 。 除了这些标准权限外,还有三个特殊权限可用。

在本教程中,让我们看一下特殊类型的权限,并学习如何使用 Linux 命令设置和删除这些标志。

2. setuid

**通常,当一个进程在类 Unix 操作系统中启动时,它会以启动它的用户的有效用户 ID 和组 ID 以及相应的权限运行。**但是,如果我们对可执行文件设置特殊权限,则可以更改此行为。

setuid表示“设置用户 ID”。如果我们在一个可执行文件上设置setuid位,该文件总是以文件所有者的权限运行,无论是谁启动它。

setuid位仅在设置在可执行文件上时才有意义。如果我们在非可执行文件或目录上设置setuid位,则没有实际意义。

passwd 命令是一个带有这个特殊位集的示例:

$ ls -l /bin/passwd
-rwsr-xr-x 1 root root 63624 Dec 15 21:06 /bin/passwd

我们注意到所有者的执行权限是小写的“s”而不是通常的“x”。**这个“s”表示文件设置了setuid位。passwd命令将始终以 root权限运行,无论是谁启动它,因为文件的所有者是root

我们可以使用chmod 命令来设置文件的 setuid位:

chmod u+s FILE

只有文件的所有者或root用户才能设置setuid位。

让我们看一个在文件上设置setuid位的示例:

$ ls -l file
-rwxr-xr-x 1 kent kent 0 Feb 2 12:22 file
$ chmod u+s file
$ ls -l file
-rwsr-xr-x 1 kent kent 0 Feb  2 12:22 file

或者,我们也可以通过在模式前面加上“4”来使用八进制表示法设置setuid位:

$ chmod 4755 file
-rwsr-xr-x 1 kent kent 0 Feb  2 12:22 file

要删除setuid位,我们将我们传递给chmod命令:

$ chmod u-s file
$ ls -l file
-rwxr-xr-x 1 kent kent 0 Feb  2 12:22 file

3. setgid

3.1. 文件上的setgid

setgid是“set group id”的缩写。如果我们在可执行文件上设置setgid位,那么无论谁启动该文件,它都会以所属组的权限运行。

locate 命令是设置了setgid位的文件示例:

$ ls -l /usr/bin/locate
-rwxr-sr-x 1 root locate 43048 Nov 13 18:09 /usr/bin/locate

setuid位类似,我们注意到ls输出中有一个小写的“s” ,除了它在组部分而不是所有者部分中。

我们可以通过将g+s传递给chmod命令来设置文件的setgid

$ ls -l file2 
-rwxr-xr-x 1 kent kent 0 Feb 2 22:35 file2
$ chmod g+s file2
$ ls -l file2 
-rwxr-sr-x 1 kent kent 0 Feb 2 22:35 file2

或者,我们可以通过在模式前面加上“2”来使用八进制表示法设置setgid位:

chmod 2755 file2

如果我们想删除文件上的setgid位,我们将gs传递给chmod命令

$ chmod g-s file2
$ ls -l file2
-rwxr-xr-x 1 kent kent 0 Feb  2 22:35 file2

3.2. 目录上的setgid

**如果我们在一个目录上设置setgid位,则该目录中所有新创建的文件和子目录都将继承该目录的组。**但是,现有文件和目录不会应用组更改。

让我们看一个例子来阐明这种行为。 首先,我们准备一个包含两个文件的parent目录:

$ ls -ld parent
drwxrwxrwx 2 root kent 4096 Feb  3 00:33 parent/
$ ls -l parent
total 2
-rwxr-xr-x 1 guest guest    0 Feb  3 00:30 existing_grp_guest1
-rwxr-xr-x 1 guest guest    0 Feb  3 00:30 existing_grp_guest2

parent 由用户root和组kent拥有。它包含两个文件,组guest拥有这两个文件。

接下来,让我们 使用chmodparent上设置setgid位:

root# chmod g+s parent
root# ls -ld parent
drwxrwsrwx 2 root kent 4096 Feb  3 00:33 parent/

现在,我们将使用rootparent目录下创建一个新文件和一个子目录:

root# touch parent/new_file_by_root
root# mkdir parent/new_dir_by_root

然后,我们将检查parent下所有文件和子目录的组所有者:

root# ls -l parent
total 4
-rwxr-xr-x 1 guest guest    0 Feb  3 00:30 existing_grp_guest1
-rwxr-xr-x 1 guest guest    0 Feb  3 00:30 existing_grp_guest2
drwxr-sr-x 2 root  kent  4096 Feb  3 00:54 new_dir_by_root/
-rw-r--r-- 1 root  kent     0 Feb  3 00:54 new_file_by_root

在上面的输出中,我们看到在parent上设置setuid位后,两个现有文件没有改变。

但是,新创建的文件和子目录由kent而不是root拥有,即使是root创建了它们。这是因为parent设置了setgid位,并且它下新创建的文件和目录继承了parent的组。

4. Sticky 位

4.1. Sticky 位

粘性位是保护目录中的文件。如果我们在一个目录上设置sticky位,那么这个目录下的文件只能通过以下方式之一删除:

  • 文件的所有者
  • 目录的所有者
  • root用户

换言之,此特殊权限可防止用户在公共目录中删除其他用户的文件。 /tmp目录是一个典型的真实世界Sticky位示例:

$ ls -ld /tmp
drwxrwxrwt 24 root root 980 Feb  3 21:41 /tmp/

由于“其他”权限部分中的“w”,我们知道任何用户都可以创建和删除*/tmp*目录下的任何文件。

但是如果我们仔细阅读上面的ls输出,我们会发现“other”部分中的执行权限位是小写的“t”,而不是通常的“x”。 这个小写字母*“t”表示 /tmp目录设置了Sticky位。使用Sticky位,任何用户仍然可以在/tmp*下创建文件。但是,用户只能删除自己拥有的文件。

4.2. 目录上的Sticky位

要在目录上设置Sticky位,我们仍然可以使用带有模式+tchmod*命令*:

chmod +t DIRECTORY

或者,我们也可以在目录模式前加上“1”来设置Sticky位:

chmod 1777 DIRECTORY

我们还可以使用-t*从目录中删除Sticky位*:

chmod -t DIRECTORY

和往常一样,让我们看一个例子来了解sticky位如何保护目录下的文件以及如何设置和删除目录上的sticky位。 让我们从准备一个名为public的公共目录开始,并允许所有用户写入它:

$ ls -ld public
drwxrwxrwx 2 root root 40 Feb  3 22:22 public/

接下来,我们将在不同用户的public下创建一些文件:

$ ls -l
-rw-r--r-- 1 guest guest 0 Feb  3 22:28 file1_by_guest
-rw-r--r-- 1 guest guest 0 Feb  3 22:28 file2_by_guest
-rw-r--r-- 1 kent  kent  0 Feb  3 22:28 file_by_kent

到目前为止,我们还没有在任何地方设置sticky位。让我们看看用户kent是否可以删除guest拥有的文件:

kent$ rm file1_by_guest 
rm: remove write-protected regular empty file 'file1_by_guest'? y
kent$ ls -l
-rw-r--r-- 1 guest guest 0 Feb  3 22:28 file2_by_guest
-rw-r--r-- 1 kent  kent  0 Feb  3 22:28 file_by_kent

因此,没有sticky位,我们可以删除其他用户拥有的文件。 现在,让我们设置sticky位,看看是否有任何变化:

root# chmod +t public
root# ls -ld public 
drwxrwxrwt 2 root root 80 Feb  3 22:33 public/
root# su kent
kent$ rm file2_by_guest 
rm: remove write-protected regular empty file 'file2_by_guest'? y
rm: cannot remove 'file2_by_guest': Operation not permitted
kent$ ls -l 
-rw-r--r-- 1 guest guest 0 Feb 3 22:28 file2_by_guest
-rw-r--r-- 1 kent kent 0 Feb 3 22:28 file_by_kent

设置sticky位后,public下的文件 只能被文件所有者删除。

5. 安全

setuid位在各种应用程序中可能非常方便。但是,当我们设置这些特殊权限时,我们必须谨慎,因为它会产生安全问题。

例如,典型用户可以通过执行将UID设置 为root的程序来获得超级用户权限。

5.1. 权限提升

**我们监控系统是否有任何可疑的setuid位使用以获得超级用户权限是一个很好的做法。**我们可以使用find 命令找到所有由root拥有并带有setuid位的文件:

root# find / -user root -perm -4000 -exec ls -ldb {} \;
...
-rwsr-xr-x 1 root root 30744 Dec 12 22:11 /usr/lib/virtualbox/VBoxNetAdpCtl
-rwsr-xr-x 1 root root 161720 Dec 12 22:11 /usr/lib/virtualbox/VBoxNetDHCP
-rwsr-xr-x 1 root root 71728 Dec 15 21:06 /usr/bin/chage
-rwsr-xr-x 1 root root 145176 Jan  1 13:17 /usr/bin/sudo
-rwsr-sr-x 1 root root 38664 Nov 13 18:49 /usr/bin/unix_chkpwd
-rwsr-xr-x 1 root root 12360 Dec 15  2013 /usr/bin/sflock
...

5.2. setuid和解释的可执行文件

解释的可执行文件通常是一个可执行文件,它通过shebang 声明解释器。例如,以“#!/bin/bash”开头的 Bash 文件或以“#!/usr/bin/env python”开头的可执行Python源文件。

出于安全原因, Linux 忽略所有解释的可执行文件上的 setuid 。如果我们希望我们的 shell 脚本拥有setuid权限,我们可以使用sudo 命令获得脚本文件所有者的权限。