3.2.7 LogonSessions and Revocation
3.2.7.1 LogonSessions #
A LogonSession is a lightweight kernel object identified by a LUID,
carried on tokens as auth_id. Every token references one.
authd creates a LogonSession through a KACS syscall at authentication
time, before creating the token. The object holds the LogonSession ID,
the logon type (Interactive, Network, Service, and so on), the user
SID, the authentication package name such as Kerberos or
Negotiate, and a creation timestamp. The logon SID, S-1-5-5-X-Y,
is derived from the LogonSession ID. Several tokens may share one
session — linked pairs, and tokens derived by duplication.
When the last token referencing a session is freed, the kernel
destroys the session object and emits a kacs.session.destroyed
event through KMES. The last
token usually goes when a credential is freed, which happens in an RCU
callback where no record can be built, so the session is queued, still
referenced, and a kernel work item writes the event moments later and
then releases it. The session is gone at once — it no longer resolves —
but its event follows the teardown rather than coming from it, and its
header names the kernel worker that wrote it. The event is for whatever keeps per-session state
outside the kernel — an audit pipeline, an accounting tool, an authority
that caches credentials per session. authd keeps none and does not
subscribe.
The record describes the session under object.session: its LUID as
id (the subject.token.auth-id of every record made under it), the
user SID as user.sid, the logon type as logon-type, the
authentication package as auth-package, and the creation time as
logon-time. The logon type is written by name — interactive,
network, batch, service, network-cleartext, new-credentials
or remote-interactive — and the time in realtime nanoseconds, though
the kernel holds it to whole seconds.
There is one rollback path for the case where authd creates a session
but no token ever becomes live for it:
kacs_destroy_empty_logon_session, which requires SeTcbPrivilege
and succeeds only when the session exists, has zero live tokens, has
no linked-token state, and has no other in-flight kernel references.
On success it destroys the object and emits the same
kacs.session.destroyed event as normal cleanup. A nonexistent
session fails with -ENOENT; one with any live token, linked-token
state, or in-flight reference fails with -EBUSY.
A second enumeration surface exists alongside /proc:
/sys/kernel/security/kacs/sessions lists every live session, one
line each, giving the session ID, user SID, logon type, authentication
package, and creation time. Each
line reads
logon_session_id=<u64> user_sid=<hex> logon_type=<u32> auth_package=<hex> created_at=<u64>
with the user SID's binary form and the package name's bytes in
lowercase hexadecimal, and created_at in seconds since the Unix
epoch. securityfs itself is unclassified by FACS,
so its objects sit deny-missing until the mount is given a synthesising
policy (§3.9.5); only then can the file be opened at all. On Peios,
peinit gives it one at boot that lets Authenticated Users open and
traverse. Reading it is access-checked against a
synthetic descriptor granting read to SYSTEM and Administrators, and is
PIP-checked.
AccessCheck never consults auth_id, and the logon SID influences a
decision only because it is materialised as an ordinary group SID on
the token. Two enforcement decisions elsewhere in the kernel do read
session state, though. Installing a primary token denies a non-TCB
caller whose target token belongs to a different
LogonSession (§3.2.3). And the
CAP_SYS_BOOT mapping selects between SeShutdownPrivilege and
SeRemoteShutdownPrivilege by inspecting the session's logon type
(§3.10). interactivity_scope is metadata in the same way: the kernel
stores it and returns it on query, and no kernel security mechanism
evaluates it.
3.2.7.2 Expiration #
The expiration field carries a timestamp, and AccessCheck does not
enforce it. It is informational.
Token lifetime is governed by reference counting instead: a token exists as long as at least one reference — a process credential or an open file descriptor — exists.
3.2.7.3 Revocation #
KACS has no token revocation primitive. There is no "invalidate token
X" syscall, and no syscall destroys a LogonSession while tokens still
reference it. kacs_destroy_empty_logon_session is only authd's
rollback for a session that never acquired live tokens.
Terminating a LogonSession is therefore userspace coordination. On
Peios authd does it, when asked over /run/logon.sock (PGSS Logon
§2.22):
- A caller asks authd to end the session, and authd decides whether it may: its own session as a person, anyone else's by an access check against local policy. SYSTEM's session (999), Anonymous's (998) and every session of logon type Service are never ended this way; a service is stopped through peinit.
- authd enumerates processes whose primary token carries the
target
auth_id, by walking/proc, opening each process withpidfd_open, opening its primary token withkacs_open_process_tokenon that pidfd, and readingTokenStatistics, which includesauth_id. No dedicated enumeration syscall exists or is needed. A thread's impersonation token is not consulted, so a service impersonating a member of the session is not one of its processes. - authd sends each
SIGTERMwithpidfd_send_signal, waits up to a grace period (5 seconds) for them to exit, and sendsSIGKILLto the survivors. - It walks again, since a process may have forked meanwhile, for at most three rounds.
- The processes terminate, dropping their token references.
- The last reference drops and the session object is cleaned up.
Each token handle authd opens in the walk is itself a reference to the
session, and is closed as soon as auth_id has been read.
Token file descriptors can be passed between processes over IPC, so a reference held by a process outside the target session survives that session's process termination. The walk finds processes running under the session, not every process holding one of its tokens, so such a reference keeps the session alive after authd has ended every process in it, and authd reports nothing about it. A process that has exited but not been reaped likewise keeps its token, and the session, until it is reaped.
Kernel-side invalidation — a dead flag on the LogonSession object checked during AccessCheck, so that access checks against its tokens fail immediately — is not implemented.