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.
Opening through /proc. /proc/<pid>/token and
/proc/<pid>/task/<tid>/token open a process's primary token and a
thread's effective token as a query-only handle: the fd always carries
TOKEN_QUERY and nothing else. Opening another process's file makes
both of the syscall's checks — PROCESS_QUERY_INFORMATION on the
process's descriptor, with PIP dominance, and TOKEN_QUERY on the
token's own descriptor — so the path reads nothing the syscall would
refuse. A process opens its own without either check.
The peer-token socket option (getsockopt(SOL_KACS, KACS_SO_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 | TOKEN_DUPLICATE. A token delivered
in a KACS_SCM_TOKEN control message carries the same three.
TOKEN_DUPLICATE is what lets a server turn a client's identity into a
primary token for a process it launches on the client's behalf
(§3.2.4); it is safe to hand out because the level ratchet means the
copy can never act above the level the client chose (§3.5.1).
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 #
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; - Administrators (
S-1-5-32-544)TOKEN_QUERY.
The Administrators grant is read-only: it lets an administrator see who any process runs as, its groups and privileges, and which logon session it belongs to, which is what a machine-wide process listing needs. Duplicating, impersonating, adjusting or rewriting the token still needs the token's own grants.
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.