可执行权限模式S有什么用途吗?

AJJ*_*AJJ 5 permissions command-line bash execute-command

如果您为具有执行权限的文件权限添加 setuid 位,它会将 更改为 an xs这意味着如果您执行该文件,它将作为该文件的所有者而不是实际执行该文件的人执行。

但我还注意到,如果您添加s权限但删除权限,它会在权限列表中x更改为。S不知何故,这意味着它无法执行,但如果可以执行,它会同时作为所有者执行?是对的吗?

我是否误解了这个权限?它是干什么用的?这是什么意思?

Eli*_*gan 2

所有四种组合都存在并且都是有意义的。

\n\n

“这个文件的实际所有者可以运行它吗?” “系统会假装谁正在运行这个文件?” 是两个独立的问题。所有四种组合都是可能的且有意义的。

\n\n

在所有者执行位置(即代替in )显示ls -l或显示的权限字符串四个不同的字符,每个组合一个:stat -c %A?---?------

\n\n
    \n
  1. -意味着所有者无法运行该文件,如果非所有者运行该文件,则该文件将以其他用户的身份运行。
  2. \n
  3. x意味着所有者可以运行该文件,如果非所有者运行该文件,则该文件将以其他用户的身份运行。
  4. \n
  5. S意味着所有者无法运行该文件,如果非所有者运行该文件,则该文件将以所有者身份运行。
  6. \n
  7. s意味着所有者可以运行该文件,如果非所有者运行该文件,则该文件将以所有者身份运行。
  8. \n
\n\n

setuid 位和执行位是单独的位,模式字符串实际上只是查看权限位(包括这些位)的便捷方式。另一种思考方式是:

\n\n
    \n
  • xs表示执行位已设置。-S表示不是。
  • \n
  • sS表示 setuid 位已设置。-x表示不是。
  • \n
\n\n

类似地,一个组可能有也可能没有文件的执行权限,并且如果执行的话,它可能会或可能不会使用与运行它的用户不同的组身份来运行。要使文件以其组所有者的组身份而不是运行该文件的用户的组身份运行,您可以设置setgid 位------s---------S---)。

\n\n

S不代表单独的模式位。它只是表示 setuid(或 setgid)位已设置但相应的可执行位未设置的一种方式。

\n\n
$ touch foo\n$ chmod u+S foo\nchmod: invalid mode: \xe2\x80\x98u+S\xe2\x80\x99\nTry \'chmod --help\' for more information.\n
Run Code Online (Sandbox Code Playgroud)\n\n

您可以检查这些位本身。

\n\n

要查看这些是单独的位,请使用%a格式说明符 forstat而不是%A。为了简化事情,我取消了所有其他模式位。

\n\n
$ touch a b c d\n$ chmod u=,g=,o= a\n$ chmod u=x,g=,o= b\n$ chmod u=s,g=,o= c\n$ chmod u=xs,g=,o= d\n$ stat -c \'%A %n\' a b c d\n---------- a\n---x------ b\n---S------ c\n---s------ d\n$ stat -c \'%04a %n\' a b c d\n0000 a\n0100 b\n4000 c\n4100 d\n
Run Code Online (Sandbox Code Playgroud)\n\n

这很清楚......如果您对八进制感到满意。如果您想以二进制形式查看它(毕竟它们 ),您可以转换表示形式:

\n\n
$ stat -c \'%a %n\' a b c d | perl -pe \'s/\\d+/sprintf("%012b", oct($&))/e\'\n000000000000 a\n000001000000 b\n100000000000 c\n100001000000 d\n
Run Code Online (Sandbox Code Playgroud)\n\n

setuid 设置的是有效用户 ID,而不是真实用户 ID。

\n\n

执行位控制尝试运行文件是否可以成功,而 setuid/setgid 位控制新进程在允许创建的情况下以其身份运行。S因此,权限组合代表 ( )并没有什么不一致或令人惊讶的地方-x,+s。即使一个可执行文件作为其所有者运行,因为它的所有者确实运行了,它的工作方式也与作为其所有者运行的可执行文件完全相同,因为有人运行了它,但它是 setuid。但事实并非如此。

\n\n

内核使用多个数字来跟踪正在运行的进程的用户身份。其中一个数字是 UID,另一个数字是 EUID。有关详细信息,请参阅这篇文章。setuid 位会导致 EUID(有效用户 ID)发生更改,但 UID(真实用户 ID)保持不变。它的一个用途是允许共享 UID 但具有不同 EUID 的进程之间交换信号,但另一个用途是它允许设计为设置其 setuid 位的程序检查谁运行了它

\n\n

例如,passwd必须是 setuid,因为只有 root 可以更改密码数据库中的条目:

\n\n
$ ls -l "$(command -v passwd)"\n-rwsr-xr-x 1 root root 54256 May 16 19:37 /usr/bin/passwd\n
Run Code Online (Sandbox Code Playgroud)\n\n

-rwsr-xr-x已经r-x到了最后,为别人。由于x,即使不是 root 用户或 root 组中的用户也可以运行passwd. 对于主人来说,它已经rws接近开始了。由于,程序以 root 身份运行,即使非所有者运行它也是如此。但是当你自己运行时,它会重置你的密码,而不是 root 的密码。spasswd

\n\n

passwd能够用户和密码数据库执行任何更改,因为它使用 root 的有效用户 ID 运行。但它的设计目的是拒绝更改除运行它的用户之外的任何人的密码(除非该用户是 root),因为它会检查其真实用户 ID。

\n\n

这是 setuid 可执行文件的典型用例:创建一个接口,允许一个用户以由 setuid 可执行文件的代码检查的有限方式使另一个用户执行操作。因此,只有在设计为具有这些权限的程序上设置 setuid 位(或 setgid 位)才是安全的。

\n\n

这是理解为什么权限S表示的谜题的另一部分:setuid 位赋予的权力并不能实现与作为其所有者实际运行程序相同的效果,即使程序已被允许运行。

\n\n

使用副本检查 UID 和 EUIDid显示了 setuid 的工作原理。

\n\n

好吧,我将在一个并非为此设计的可执行文件上设置 setuid 位,以显示真实有效的用户 ID 受到的影响。

\n\n
    \n
  • 可执行文件将是程序的副本id,除其他外,它报告其真实有效的用户 ID。虽然这个程序不是为了 setuid 而设计的,但它也根本不是为了改变任何东西而设计的——除了产生输出——所以这是相当安全的。但事后您仍应将其删除。(您的副本。不是原件。)
  • \n
  • 我们使用的是副本,而不是更改原始文件的权限。您无需sudoroot 身份使用或执行任何操作。
  • \n
  • 要以其他用户身份运行它,您需要第二个用户帐户,但您可以使用该帐户以su用户身份执行操作。(默认情况下,该帐户不允许您使用密码登录,因此,如果您犯了错误并在没有提供要切换到的用户名的情况下运行,您不会最终意外地成为root ,除非您还启用了 root 登录。不过,如果您确实想使用而不是,那么您可以。)rootsusudo -u usersu user -c
  • \n
\n\n

我的主用户帐户名为ek,我的第二个帐户是ek2。如果你的不同也没关系。首先,ek我复制id到当前目录(位于我的主目录中的某个位置):

\n\n
$ type -a id\nid is /usr/bin/id\n$ cp /usr/bin/id .\n
Run Code Online (Sandbox Code Playgroud)\n\n

副本拥有复制它的非root用户的所有权,但原始权限:

\n\n
$ ls -l id /usr/bin/id\n-rwxr-xr-x 1 ek   ek   39760 Oct  5 11:23 id\n-rwxr-xr-x 1 root root 39760 Mar  2  2017 /usr/bin/id\n
Run Code Online (Sandbox Code Playgroud)\n\n

传递-ntoid显示名称而不是 ID 号、-u显示用户(而不是组等其他信息),并-r导致显示真实的用户 ID。不带 时-r-u显示有效用户 ID。这种行为完全适用于我刚刚制作的副本id

\n\n

当我以替代用户身份运行它时,真实用户 ID 和有效用户 ID 都发生了变化。这是su和 的sudo编写方式的一部分,并且不仅仅是su其本身成为 setuid root 的结果,尽管它确实如此。(这就是为什么我使用passwd典型的 setuid 可执行文件作为示例,而不是susudo。)这是我们的基线,以查看id当前目录中是否按预期工作:

\n\n
$ ./id -nu                # ek runs id, displaying the effective user\nek\n$ ./id -nur               # ek runs id, displaying the real user\nek\n$ su ek2 -c \'./id -nu\'    # ek2 runs id, displaying the effective user\nPassword:\nek2\n$ su ek2 -c \'./id -nur\'   # ek2 runs id, displaying the real user\nPassword:\nek2\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在我制作 setuid 的本地副本id

\n\n
$ chmod u+s id\n$ ls -l id\n-rwsr-xr-x 1 ek ek 39760 Oct  5 11:42 id\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在,当我运行它时,它的真实用户ID仍然是运行它的用户的ID,而它的有效用户ID是ek即使ek2运行它时的用户ID:

\n\n
$ ./id -nu                # ek runs id, displaying the effective user\nek\n$ ./id -nur               # ek runs id, displaying the real user\nek\n$ su ek2 -c \'./id -nu\'    # ek2 runs id, displaying the effective user\nPassword:\nek\n$ su ek2 -c \'./id -nur\'   # ek2 runs id, displaying the real user\nPassword:\nek2\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在我从所有者那里拿走了可执行权限,但将它们留给其他人:

\n\n
$ chmod u-x id\n$ ls -l id\n-rwSr-xr-x 1 ek ek 39760 Oct  5 11:42 id\n
Run Code Online (Sandbox Code Playgroud)\n\n

ek2仍然可以像ek使用有效用户 ID 一样运行它,即使ek无法运行它:

\n\n
$ ./id -nu                # ek runs id, displaying the effective user\n-bash: ./id: Permission denied\n$ ./id -nur               # ek runs id, displaying the real user\n-bash: ./id: Permission denied\n$ su ek2 -c \'./id -nu\'    # ek2 runs id, displaying the effective user\nPassword:\nek\n$ su ek2 -c \'./id -nur\'   # ek2 runs id, displaying the real user\nPassword:\nek2\n
Run Code Online (Sandbox Code Playgroud)\n\n

但是,如图所示,这并没有产生与ek实际运行相同的结果。ek2除非程序允许,否则无法真正执行允许运行该程序时ek可以执行的操作。ek

\n\n

(之后,我跑去rm id删除该文件,这样我的主目录中就不会有不必要的 setuid 可执行文件。或者您可以使用 取消设置 setuid 位chmod -s id。)

\n