Skip to content

Fix http_logout() no-op from a CGI (GRT/WSA credential-store context)#115

Merged
mgrossmann merged 1 commit into
mainfrom
issue-113-logout-cgi-grt
Jul 6, 2026
Merged

Fix http_logout() no-op from a CGI (GRT/WSA credential-store context)#115
mgrossmann merged 1 commit into
mainfrom
issue-113-logout-cgi-grt

Conversation

@mgrossmann

Copy link
Copy Markdown
Contributor

Fixes #113

Problem

http_logout() (HTTPX export) invalidated nothing when called from a CGI: after a "successful" logout the session token kept resolving. It reached the store via credtok_logout()cred_array(), which reads the credential array out of the current GRT's WSA. A CGI reached through the HTTPX vector runs under its own GRT, where that slot is empty — so the token scan found nothing, the CRED stayed in httpd's real store, and the deterministic CREDTOK kept resolving. Same GRT/WSA class as #109 (userid) and #111 (password); the logout path was just never corrected.

Fix (issue's Option 2 — the #111 pattern)

  • Cache httpd's credential array pointer in the HTTPD control block (httpd->credarr = cred_array()) at cred_init() time, in httpd's own GRT where it is valid.
  • Split credtok_logout(token) into an array-explicit credtok_logout_arr(array, token); the wrapper keeps using cred_array() for httpd-core callers (httpcred.c form logout), while http_logout() passes httpc->httpd->credarr so it operates on httpd's real store from any GRT.
  • The array lock is an address-keyed ENQ (LOCK.%08X) → address-space-wide, so locking httpd's real array address from the CGI coordinates with the core.

Option 1 (make cred_array() AS-wide via the OURKEY high-byte pattern) is not viable#111 already established that pattern is still per-GRT.

Why cross-GRT free() is safe (this is the crux, and it's proven, not assumed)

cred_free() runs from the CGI's runtime but frees a CRED that httpd's runtime malloc'd. That is safe here:

  1. No per-runtime free-list exists. The sysroot libc.a is built without USE_MEMMGR (zero memmgr symbols in the built archive; getmain is what's linked). @@getm.asm stores the block length in an 8-byte prefix on the block itself; @@freem.asm reads it back from the block and FREEMAINs. So free() is a pure function of (block, subpool) — any runtime can free any block.
  2. Storage is subpool 0 (AS-shared across the jobstep), and a CGI reached via LINK SVC runs synchronously on the worker's TCB — same task, same shared subpool.
  3. Empirical backstop: httpd already frees CREDs across TCB boundaries — the reaper frees CREDs that cred_login allocated on worker threads, and HTTPC is alloc'd/freed across threads. This change introduces no new cross-TCB free pattern.

Note on cred_free rc

Inherited behavior: if cred_free hits its trylock==4 path it returns 4 and the CRED is unlinked-but-not-freed (a transient leak reclaimed later). array_del runs before the free, so the token stops resolving regardless — logout still succeeds even in that edge; a reviewer shouldn't read rc=4 as "logout failed".

Verification

  • make test-mvs: 114 assertions PASS, 0 FAIL (batch + TSO) across TSTLOUT + TSTGPWD/TSTGUID/TSTCRED — no regression from the credtok_logout split or the new HTTPD field.
  • New TSTLOUT guards the refactor: given an explicit array, credtok_logout_arr() finds, unlinks and frees the matching CRED so the token stops resolving; the wrapper still works; NULL/absent cases are no-ops.
  • Honest boundary: TSTLOUT runs single-GRT, so like TSTGPWD it cannot reproduce the cross-GRT bug. The discriminating proof is the issue's own curl repro (login → GET 200 → DELETE → GET): mvsMF build f12ff9b already calls http_logout (it just ignores the rc), so with this httpd deployed the final GET flips 200 → 401 with no mvsMF change. That's runnable on live MVS (mvsMF: implement /zosmf/services/authenticate (Authentication Service) mvsmf#162 / PR #168) once deployed.

No httpcgi.h change

http_logout's signature is unchanged and HTTPD is opaque in the public httpcgi.h (CGIs only rely on httpx at offset 0x08, which the appended credarr field does not disturb) — so, like credkey from #111, the new field is not mirrored there.

…s GRT

http_logout() invalidated nothing when called from a CGI: the session
token kept resolving after a "successful" logout. It reached the store
via credtok_logout() -> cred_array(), which reads the credential array
out of the current GRT's WSA. A CGI reached through the HTTPX vector runs
under its own GRT, where that slot is empty, so the token scan found
nothing, the CRED stayed in httpd's real store, and the deterministic
CREDTOK kept resolving. Same GRT/WSA class as #109 (userid) and #111
(password), but the logout path was never corrected.

Cache httpd's credential array pointer in the HTTPD control block
(httpd->credarr = cred_array()) at cred_init() time, in httpd's own GRT
where it is valid -- the same GRT-independent pattern http_get_password()
uses for the blowfish key. Split credtok_logout() into an array-explicit
credtok_logout_arr(array, token); the token/wrapper keeps using
cred_array() for httpd-core callers, while http_logout() passes
httpc->httpd->credarr so it operates on httpd's real store from any GRT.

Cross-GRT free is safe here: the sysroot libc is built without USE_MEMMGR
(no per-runtime free-list -- @@getm/@@freem keep the length in a prefix on
the block itself), so free() is a pure function of (block, subpool). httpd
already frees CREDs across TCB boundaries (the reaper frees CREDs that
cred_login allocated on worker threads); this adds no new cross-TCB free
pattern. The array lock is an address-keyed ENQ (address-space-wide), so
locking httpd's real array address from the CGI coordinates with the core.

Adds TSTLOUT covering the array-explicit logout and the wrapper.

Fixes #113
@mgrossmann
mgrossmann merged commit 9888d25 into main Jul 6, 2026
1 check passed
@mgrossmann
mgrossmann deleted the issue-113-logout-cgi-grt branch July 6, 2026 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

http_logout() is a no-op from a CGI: credtok_logout() -> cred_array() reads the CGI's GRT WSA, not httpd's credential store

1 participant