为什么在某些系统上最大 uid/gid 是 65534 而不是 65535?

use*_*763 2 uid

我知道 uid(或 gid)没有共享的最大值:一些系统使用 99(Slackware,...),其他系统使用 65534(Debian,...)。
我问是否有特定的动机使用 65534 而不是 65535 (0xFFFF)。谢谢你。

Dav*_*rtz 6

如果最大 UID 是 65535,那么如果 UID 存储在一个无符号的 16 位值中,则没有指示错误或未知 UID 的值。


Jde*_*eBP 6

为什么是99?

这是不是其实是一个最大。这是一个阈值,“系统”帐户的 ID 停止,“真人”帐户的 ID 开始。它也是相当随意和可变的。除了 100 是一个方便的整数之外,没有真正的理由将它设为 99。

这是一个方便的整数,由平台的各种密码和组数据库管理工具商定。例如,在 Debian 版本 7 上,useraddgroupadd工具查找/etc/login.defs算作“系统”和“用户”的 UID 和 GID 的范围,对于 UID 和 GID,后者的范围是 1000 到 60000。

为什么是 65534?

首先是因为在 POSIX 系统调用中有两个广泛的约定:

  • 返回值-1(强制转换为返回类型)指示错误,错误号可从errno宏中获得。
  • 的输入值-1表示“不改变”。

这些不是通用的约定。请注意,geteuid()例如,系统调用不可能返回错误。(进程总是有有效的 UID。)所以static_cast<uid_t>(-1)不用担心。但至少其中之一适用于 UID 和 GID。在setreuid()andsetregid()系统调用中,参数的-1意思是“没有变化”。因此static_cast<uid_t>(-1)static_cast<gid_t>(-1)不能正确用作实际 ID。

其次,因为 Linux 上的 UID 和 GID 曾经是 16 位的。

这在世纪之交变成了 32 位,但它的回声仍然存在,而且实际上比最初看起来更微妙。 -1浇铸到一个16位无符号整数,它是什么uid_t以及gid_t(在系统调用接口)以前是,当然是65535,你观察。所以这不是一个可用的 UID 或 GID。

但是,为了在已切换到 32 位uid_t和32 位内核的程序上使用 16 位 API 的程序的好处gid_t,Linux 定义了“溢出 UID”和“溢出 GID”。这是因为在 16 位和 32 位之间进行了转换,因此在不同的点上存在一些相当讨厌的交互。当内核没有时,16 位程序将 UID 65536 视为超级用户。当应用程序代码没有时,较旧的内核将 UID 131072 视为超级用户。

“溢出 UID”和“溢出 GID”本质上将所有 32 位 UID 和大于 65535 的 GID 映射到 16 位代码的 65534。这意味着第二个值 0xFFFE 现在不能用作真正的 UID 或 GID 值。

而且,当然,-1强制转换为 32 位 UID 和 GID 类型也是不可用的。