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

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

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

答案1

为什么是 99?

这是不是实际上是最大值。这是一个阈值,系统帐户的 ID 以此为界,“真人”帐户的 ID 以此为界。这个阈值也是相当随意和可变的。没有理由将它设为 99,除非 100 是一个方便的整数。

这是各种密码和组数据库管理工具针对平台商定的方便的整数。例如,在 Debian 版本 7 中,和useradd工具groupadd会查找/etc/login.defs算作“系统”和“用户”的 UID 和 GID 范围,后者的范围是 1000 到 60000(UID 和 GID 均如此)。

为什么是 65534?

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

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

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

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

大约在世纪之交,它变为了 32 位,但它的影响仍然存在,而且实际上比乍一看更微妙。 -1转换为 16 位无符号整数,也就是(在系统调用接口)以前的uid_tgid_t,当然是 65535,正如您所观察到的。所以这不是可用的 UID 或 GID。

uid_t但是,为了使在已切换到 32 位和 的内核上使用 16 位 API 的程序受益gid_t,Linux 定义了“溢出 UID”和“溢出 GID”。这是因为在各个点上,由于在 16 位和 32 位之间进行转换,存在一些相当讨厌的交互。16 位程序将 UID 65536 视为超级用户,而内核却不这样做。较旧的内核将 UID 131072 视为超级用户,而应用程序代码则不这样做。

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

当然,-1转换为 32 位 UID 和 GID 类型也是无法使用的。

答案2

如果最大 UID 为 65535,则当 UID 以无符号的 16 位值存储时,没有任何值可以指示错误或未知的 UID。

答案3

系统通常保留最高无符号整数值 0xffff(如果该值被解释为有符号整数,则为 -1)以表示“无效”或“未使用”。
(0xffff 当然是 16 位。 有些系统使用 32 位 0xffffffff。)

零不能用于此目的,因为它是为 root 保留的。
(如果我没记错的话,为 root 保留 0 是 POSIX 惯例,出于兼容性原因,几乎所有其他操作系统也都遵守该惯例。)

相关内容