3.2.8 Token Access Rights
Tokens are securable objects: each has its own security descriptor, and reaching a token means passing an AccessCheck against it.
3.2.8.1 Obtaining a token file descriptor #
Opening directly. A syscall takes a pidfd — not a raw PID — and a
desired access mask. The kernel finds the target's
primary token, evaluates the caller's token against that token's
descriptor, and returns a token fd with the granted mask cached on it.
A separate variant opens a thread's impersonation token. Opening
another process's token additionally requires
PROCESS_QUERY_INFORMATION on the target process's descriptor.
kacs_open_peer_token is the exception: it takes no desired-access
mask, and the fd it returns always carries the fixed rights
TOKEN_QUERY | TOKEN_IMPERSONATE.
Receiving over IPC. A token fd can be passed over a Unix socket
with SCM_RIGHTS. What the recipient may do is bounded by the mask
cached on the fd when it was originally opened, not by the recipient's
own identity.
Implicit self-access. A thread has implicit access to its own
effective token for query operations, but this is not a kernel bypass.
It follows from the default token descriptor, which grants
TOKEN_QUERY and the adjustment rights to the token's own user SID.
The AccessCheck still runs; it simply succeeds while the descriptor
continues to grant the right. Explicitly mutating a token's own
descriptor later can revoke self-query by removing that grant.
3.2.8.2 Token-specific rights #
| Right | Value | Grants |
|---|---|---|
TOKEN_ASSIGN_PRIMARY | 0x0001 | Install as a process's primary token. Also requires SeAssignPrimaryTokenPrivilege on the caller's token. |
TOKEN_DUPLICATE | 0x0002 | Duplicate the token, or create a restricted copy with FilterToken. |
TOKEN_IMPERSONATE | 0x0004 | Install as a thread's impersonation token. |
TOKEN_QUERY | 0x0008 | Read token information: SIDs, groups, privileges, integrity, claims, source, statistics, elevation type. |
TOKEN_ADJUST_PRIVILEGES | 0x0020 | Enable, disable, or permanently remove privileges. |
TOKEN_ADJUST_GROUPS | 0x0040 | Enable or disable groups. |
TOKEN_ADJUST_DEFAULT | 0x0080 | Change the default DACL, owner SID, and primary group SID. |
TOKEN_ADJUST_INTERACTIVITY_SCOPE | 0x0100 | Change the interactivity scope. Also requires SeTcbPrivilege. |
Bit 0x0010, TOKEN_QUERY_SOURCE, is subsumed by TOKEN_QUERY: a
holder of 0x0008 can query source information too. The bit is not
reused for anything else, for format compatibility with MS-DTYP.
TOKEN_ALL_ACCESS is 0x000F01FF — the union of the token-specific
rights with STANDARD_RIGHTS_REQUIRED
(DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER, 0x000F0000). The
named rights alone OR to 0x01EF; the reserved TOKEN_QUERY_SOURCE bit
adds 0x0010 to reach 0x01FF.
3.2.8.3 Generic mapping #
| Generic right | Maps to |
|---|---|
GENERIC_READ | TOKEN_QUERY | READ_CONTROL |
GENERIC_WRITE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | WRITE_DAC |
GENERIC_EXECUTE | TOKEN_IMPERSONATE |
GENERIC_ALL | TOKEN_ALL_ACCESS (0x000F01FF) |
3.2.8.4 Standard rights #
READ_CONTROL reads the token's own descriptor, WRITE_DAC modifies
its DACL, and WRITE_OWNER changes its owner. DELETE has no
practical effect on a token and is present only for uniformity across
standard rights.
3.2.8.5 The default token descriptor #
A newly created token receives a descriptor owned by the creating process's user SID, with a DACL granting:
- the token's own user SID
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT; - the creator
TOKEN_ALL_ACCESS; - SYSTEM (
S-1-5-18)TOKEN_ALL_ACCESS.
Self-access is deliberately limited to the adjustment operations that
cannot escalate. TOKEN_DUPLICATE, TOKEN_IMPERSONATE, and
WRITE_DAC are not granted to the token's own subject.
That limit needs protecting in the case where the creator and the
token's own user SID are the same, which would otherwise hand the
subject TOKEN_ALL_ACCESS through the creator ACE. When the two SIDs
are identical the creator ACE is omitted — and the descriptor also
gains a non-inherit-only OWNER RIGHTS ACE suppressing the owner's
implicit READ_CONTROL | WRITE_DAC grant while preserving
READ_CONTROL. Without it, owner-implicit WRITE_DAC would let the
subject rewrite its own DACL and reintroduce exactly the escalation
that omitting the creator ACE was meant to close.
3.2.8.6 Check-at-open #
The check-at-open model applies to tokens exactly as it does to files, for the token-specific rights. AccessCheck runs once, when the token fd is obtained; the granted mask is cached on the fd; and each of the token ioctls verifies against that cached mask with no re-evaluation.
The standard rights are the exception. Reading and writing a token's
own descriptor passes no cached mask at all and runs a live
AccessCheck on every call, so READ_CONTROL, WRITE_DAC and
WRITE_OWNER are re-evaluated per operation rather than snapshotted
at open. A descriptor change therefore takes effect immediately for
those three rights, while already-opened handles keep their cached
token-specific rights.