当应用于文件时,粘滞位最初是做什么的?

Jde*_*eBP 66 permissions history sticky-bit

在很多地方,人们可以看到如今被指责为完全用词不当的“粘滞位”,因为它现在的功能是影响目录的写入权限并充当受限删除标志。

在 AskUbuntu 的回答中,回答者写道“粘性位通常适用于目录”。我观察到确实现代系统在实践中似乎从未将它应用于文件,但很久以前通常的情况是将它应用于(可执行程序映像)文件而不是目录。(当谈到现代文件很少使用时,在当前文件系统是否未使用粘性位中有一个相关问题。)

这引发了一个问题:

什么应用到可执行文件做了粘滞位?是不是像 setuid 那样?

注意过去时。这不是粘性位如何工作?现在。这就是它过去的工作方式。

Jde*_*eBP 91

不,粘滞位不像 set-UID 或 set-GID 标志。它不会影响处理凭据的任何更改。

粘性位所做的是使程序文本“粘性”。原来,这不是用词不当。

背景:程序图像部分和共享文本

从本质上讲,没有深入了解可执行文件格式的细节(可以并且有填充书籍):为了运行程序而直接加载到内存中的程序映像文件部分包括机器代码、常量、启动(非零初始化)变量的值,以及(以一种或另一种形式)零初始化和未初始化变量的空格。

这些被分组到称为“部分”的集合中,并且它们具有常规名称。机器代码和(有时)常量构成了程序映像的“文本”部分。类似地,非零初始化变量是“数据”部分;零初始化和未初始化的变量是“bss”(这个名字背后有完整的民俗历史)。

当一个进程加载了一个可执行的程序映像文件时,各个部分——文本、数据和 bss——都从映像文件的内容中初始化。

“文本”部分的特别之处在于机器代码(和常量)几乎总是不被写入。它有可能在所有加载了可执行映像文件的执行进程的虚拟内存映像之间共享。可以共享程序文本的确切场景超出了此答案的范围,并且涉及诸如加载程序修复幂等性和地址空间布局标识之类的事情。人们也可以并且已经写了关于这个主题的书。☺

共享文本是内核采用的优化。它消除了单个正在运行的程序映像的每个实例都拥有自己的内存映像的需要,使用完全相同的机器代码(和常量)的多个副本消耗宝贵的物理内存。

粘性文本

但是,人们仍然可以比共享文本做得更好。显然,如果总是至少有一个进程在运行,并且使用特定的共享文本程序映像,那么当程序的新实例运行时,内核可以简单地将新进程的虚拟内存空间附加到现有的共享文本段。有几乎总是(说)的实例/bin/login/bin/sh运行某个中型系统上,login程序或默认的外壳可以简单地附加到内核已经加载到内存中的文本段的加载拷贝这样的新实例。

粘性文本将此想法扩展到当前没有进程正在运行的程序图像。如果一个可执行图像文件被标记为粘性文本,那么内核会在最后一个使用它的进程退出后保留它的文本段;希望程序的另一个实例很快执行,并且可以附加回该段。

在早期的 Unices 中,当没有进程附加到它们时,加载的粘性文本段将被换出到交换存储。(后来 Unices 停止为此使用交换。)您可能也听说过这个名称save text

当然,在程序图像上设置粘性文本位是必须小心的。哪些程序从中受益取决于机器通常用于什么。目前未附加的文本段占用内核资源,这意味着在任何系统中可以有多少个文本段是有实际限制的。所以一般都是需要超级用户权限的操作。

废止

粘性文本的操作背后有很多假设,但这些假设不再正确。从交换存储中读取预制段不一定比从实际可执行映像文件中简单的按需分页更快。文件系统格式变得更适合随机(而不是顺序)读取模式。需求分页本身的出现改变了事情,就像统一缓存、共享库搜索差异导致的非幂等外部修复以及地址空间布局随机化等事情一样。

用于可执行程序图像的粘性文本位的日子早已一去不复返了。例如,在 1980 年代中期,4.3BSD 的作者认为用于可执行程序图像的显式粘性文本标记标志已过时。

进一步阅读

  • 莫里斯 J. 巴赫 (1986)。 UNIX 操作系统的设计。普伦蒂斯霍尔。ISBN 9780132017992。

  • @JdeBP:问题“粘性有点像 setuid?” 是相当广泛和不精确的。我认为答案是“嗯,有点;它很复杂”,因为低阶九位过去并且是相似的:它们影响***某些用户是否可以对文件执行某些操作。并且 set-UID、set-GID 和粘滞位的相似之处在于它们与*是否*允许操作无关,而是调节了***如何***它的某些方面(特别是执行操作) 进行。 (3认同)