5

I know that there is not a shared maximum value for uid (or gid): some systems use 99 (Slackware, ...), others 65534 (Debian, ...).
I ask if there is a specific motivation to use 65534 and not 65535 (0xFFFF). Thank you.

0

3 Answers 3

8

Why 99?

This is not actually a maximum. It's a threshold, where the IDs for "system" accounts stop and the IDs for "real person" accounts start. It's fairly arbitrary and variable, too. There's no real reason for it to be 99 except that 100 is a handy round number.

It's a handy round number agreed upon by the various password and group database management tools for a platform. On Debian version 7, for example, the useradd and groupadd tools look in /etc/login.defs for the ranges of UIDs and GIDs that count as "system" and "user", and the latter range is 1000 to 60000 for both UIDs and GIDs.

Why 65534?

Firstly because there are two widespread conventions in POSIX system calls:

  • A return value of -1 (cast to the return type) indicates an error, with the error number available from the errno macro.
  • An input value of -1 indicates "don't change".

These aren't universal conventions. Notice that there's no possibility of an error return from the geteuid() system call, for example. (Processes always have effective UIDs.) So there's no static_cast<uid_t>(-1) to worry about there. But at least one of them applies to UIDs and GIDs. In the setreuid() and setregid() system calls an argument of -1 means "no change". So static_cast<uid_t>(-1) and static_cast<gid_t>(-1) aren't properly usable as actual IDs.

Secondly because UIDs and GIDs on Linux used to be 16-bit.

This changed to 32-bit around the turn of the century, but its echoes live on, and it is actually more subtle than it at first appears. -1 cast to a 16-bit unsigned integer, which is what uid_t and gid_t (at the system call interface) used to be, is of course 65535 as you observed. So this wasn't a usable UID or GID.

However, for the benefits of programs that used the 16-bit API on kernels that had switched to 32-bit uid_t and gid_t, Linux defined a "overflow UID" and an "overflow GID". This was because at various points there were some fairly nasty interactions due to the casting done between 16-bit and 32-bit. 16-bit programs saw UID 65536 as the superuser when the kernel didn't. Older kernels saw UID 131072 as the superuser when applications code didn't.

The "overflow UID" and "overflow GID" essentially mapped all 32-bit UIDs and GIDs greater than 65535 to 65534 for 16-bit code. This means that a second value, 0xFFFE, was now unusable as a real UID or GID value.

And, of course, -1 cast to the the 32-bit UID and GID type is also unusable.

7

If the max UID is 65535, then there is no value to indicate an error or unknown UID if the UID is stored in an unsigned 16-bit value.

4
  • So (uint16_t) -1 is used to indicate an error? Commented Jan 24, 2014 at 13:21
  • @grawity At least it can be. Whether it actually is, well, not that I know of. But that's likely the thinking. Commented Jan 24, 2014 at 19:09
  • When last I checked, (uid_t)-1 == cdrom
    – Joshua
    Commented Nov 21, 2016 at 16:21
  • And for syscalls like setreuid/setresuid, passing -1 as an argument means to make that ID unchanged
    – Steve Lau
    Commented Aug 29, 2022 at 23:18
0

Systems typically reserve the highest unsigned integer value 0xffff (or -1 if the value is interpreted as a signed integer) to indicate "invalid" or "unused".
(0xffff is 16-bit of course. Some systems use 32-bit 0xffffffff.)

Zero can not be used for that, because it is reserved for root use.
(Reserving 0 for root is, if i recall correctly, a POSIX convention that is observed by just about every other OS too, for compatibility reasons.)

4
  • 3
    User ID 0 is reserved for root, not the kernel. (Did you mean process ID 0?) Commented Jan 24, 2014 at 13:25
  • OK, but I still don't understand the utility of this value: why should I create a new user with an 'invalid' (0xffff) uid? Or it's used to mean 'let it unchanged' when calling setreuid()? 'man setreuid' says that I have to put -1 as argument if I don't want uid or gid to change, but uid_t is unsigned. So I have to put 65535? Commented Jan 24, 2014 at 16:45
  • @grawity You are correct of course. I meant root. Too little sleep, I'm not running on all cylinders. Will edit the post.
    – Tonny
    Commented Jan 24, 2014 at 21:32
  • 1
    @user2431763 You will not put -1 there but the OS might do it. Example: Some Unix flavors set the UID of a deleted user to -1, but they don't actually remove the user from passwd. (This has the benefit that you can still look up information about the user, like full name, home-dir, what shell he/she used, later on.) It also prevents re-using the username, which often is forbidden by company policy.
    – Tonny
    Commented Jan 24, 2014 at 21:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .