Я знаю, что не существует общего максимального значения для uid (или gid): некоторые системы используют 99 (Slackware, ...), другие 65534 (Debian, ...).
Я спрашиваю, есть ли конкретная мотивация для использования 65534, а не 65535 (0xFFFF).
Спасибо.
3 ответа
Если максимальный UID равен 65535, то нет значения, указывающего на ошибку или неизвестный UID, если UID хранится в 16-разрядном значении без знака.
Почему 99?
Это на самом деле не максимум. Это порог, при котором идентификаторы для "системных" учетных записей останавливаются, а идентификаторы для "реальных" учетных записей запускаются. Это довольно произвольно и переменно тоже. Нет никакой реальной причины, чтобы это было 99, за исключением того, что 100 - удобное круглое число.
Это удобное круглое число, согласованное различными инструментами управления паролями и группами баз данных для платформы. Например, в Debian версии 7 инструменты useradd
и groupadd
ищут в /etc/login.defs
диапазоны UID и GID, которые считаются "системными" и "пользовательскими", а последний диапазон составляет от 1000 до 60000 для обоих UID. и GID.
Почему 65534?
Во-первых, потому что в системных вызовах POSIX есть два распространенных соглашения:
- Возвращаемое значение
-1
(приведенное к типу возвращаемого значения) указывает на ошибку с номером ошибки, доступным из макросаerrno
. - Входное значение
-1
указывает «не изменять».
Это не универсальные соглашения. Обратите внимание, что нет возможности возврата ошибки, например, из системного вызова geteuid()
. (Процессы всегда имеют эффективные идентификаторы.) Так что нет никаких static_cast<uid_t>(-1)
. Но по крайней мере один из них относится к UID и GID. В setreuid()
и setregid()
аргумент -1
означает "без изменений". Таким образом, static_cast<uid_t>(-1)
и static_cast<gid_t>(-1)
неправильно используются в качестве реальных идентификаторов.
Во-вторых, потому что UID и GID в Linux раньше были 16-битными.
Это изменилось на 32-битный на рубеже веков, но его эхо живет, и это на самом деле более тонкое, чем кажется на первый взгляд. -1
приведено к 16-битному целому числу без знака, которое, как вы уже заметили, равняется uid_t
и gid_t
(в интерфейсе системного вызова). Так что это не был пригодный для использования UID или GID.
Однако для преимуществ программ, которые использовали 16-битный API в ядрах, которые переключились на 32-битные uid_t
и gid_t
, Linux определил "UID переполнения" и "GID переполнения". Это произошло потому, что в разные моменты происходили довольно неприятные взаимодействия из-за преобразования между 16-битным и 32-битным. 16-битные программы видели UID 65536 в качестве суперпользователя, а ядро - нет. Старые ядра видели UID 131072 в качестве суперпользователя, когда код приложения этого не делал.
"UID переполнения" и "GID переполнения" по существу отображают все 32-разрядные идентификаторы UID и GID, превышающие 65535–553434 для 16-разрядного кода. Это означает, что второе значение, 0xFFFE, теперь не может использоваться как реальное значение UID или GID.
И, конечно же, приведение -1
к 32-битному типу UID и GID также невозможно.
Системы обычно резервируют самое высокое целое число без знака 0xffff (или -1, если значение интерпретируется как целое число со знаком), чтобы указать "недействительно" или "не используется".
(0xffff 16-битный конечно. Некоторые системы используют 32-битный 0xffffffff.)
Ноль не может быть использован для этого, потому что он зарезервирован для корневого использования.
(Резервирование 0 для root - это, если я правильно помню, соглашение POSIX, которое соблюдается практически любой другой ОС по соображениям совместимости.)