Почему в некоторых системах max uid/gid составляет 65534, а не 65535?
Я знаю, что не существует общего максимального значения для 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()
системный вызов, например. (Процессы всегда имеют эффективные UID.) Так что нет 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
(в интерфейсе системного вызова) раньше было, конечно, 65535, как вы заметили. Так что это не был пригодный для использования 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, которое соблюдается практически любой другой ОС по соображениям совместимости.)