Fix stale session permissions after wh_Auth_UserSetPermissions - #481
Fix stale session permissions after wh_Auth_UserSetPermissions#481yosuke-wolfssl wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes an authorization correctness issue where wh_Auth_UserSetPermissions() updated the backend user record but did not refresh the calling session’s cached permissions, allowing revoked privileges to persist until logout. It also documents and tests the new “bind immediately” behavior and introduces a core-level guard preventing non-admin sessions from setting the admin flag.
Changes:
- Update
wh_Auth_UserSetPermissions()to refreshcontext->user.permissionswhen a logged-in user changes its own permissions successfully. - Add a core-enforced policy: non-admin sessions cannot set the admin flag via
wh_Auth_UserSetPermissions(), independent of backend policy. - Add unit + integration tests to verify immediate self-demotion effects and cache-sync behavior.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| wolfhsm/wh_auth.h | Documents session-cache refresh behavior and the new admin-flag refusal semantics for wh_Auth_UserSetPermissions(). |
| src/wh_auth.c | Implements admin-flag refusal for non-admin sessions and refreshes the live session permission cache on successful self-targeted updates. |
| test-refactor/client-server/wh_test_auth.c | Adds an end-to-end self-demotion test and a core-only mock-backend unit test for cache synchronization behavior. |
| test-refactor/wh_test_list.c | Registers the new whTest_AuthSetPermsCacheSync test. |
| test-refactor/README.md | Updates test inventory documentation to include the new auth cache-sync test. |
| docs/src/5-Features.md | Documents core vs backend responsibility for permission policy and explains live-session binding semantics and consequences. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
b0fbc8c to
99d30d3
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #481
Scan targets checked: wolfhsm-core-bugs, wolfhsm-crypto-bugs, wolfhsm-src
No new issues found in the changed files. ✅
Frauschi
left a comment
There was a problem hiding this comment.
🐺 Skoll Code Review
Overall recommendation: APPROVE
Findings: 2 total — 1 posted, 1 skipped
Posted findings
- [Info] Session permission cache mirrors caller-supplied values, not backend-persisted state —
src/wh_auth.c:483-491
Skipped findings
- [Low] Session cache mirrors supplied permissions verbatim; diverges if a custom backend transforms them
Review generated by Skoll via Claude/Codex
99d30d3 to
e82d8e5
Compare
Problem
wh_Auth_UserSetPermissionswrote the new permissions to the backend but neverrefreshed
context->user.permissions, the per-session cache thatwh_Auth_CheckRequestAuthorizationactually reads. A logged-in user thatlowered its own permissions kept the old, higher ones for the rest of the
session — revocation did not bind until the next login. Reachable from any
client through
wh_Client_AuthUserSetPermissions. Closes f-4239.Refreshing that cache opens a second hole on its own: the cache mirrors whatever
the caller supplied, so a non-admin session against a permissive backend could
cache itself as admin. Both are fixed together.
Fix (
src/wh_auth.c)user_idisthis context's logged-in user,
context->user.permissionsis updated, so thechange binds on the very next request.
carry the admin flag is refused with
WH_AUTH_PERMISSION_ERRORbefore thebackend is consulted. The check is absolute, not a promotion check: the core
is handed only the target's
whUserIdand cannot read the target's currentflag, so it refuses even a request that would merely preserve an existing
admin.
wolfhsm/wh_auth.hdocuments both on the API;docs/src/5-Features.mdadds a"Permission Changes and Live Sessions" section covering the immediate self-demote
(which can be self-locking) and the fact that other sessions keep their cached
permissions until they log in again.
Tests (
test-refactor/client-server/wh_test_auth.c)Both halves are now driven entirely through
wh_Client_*against the runningPOSIX server and the real
wh_Auth_Base*backend, appended to the existingwhTest_AuthSetPermissions. No new file, no new entry point, nowh_test_list.corREADME.mdchange.USER_ADDbit(keeping admin +
USER_SET_PERMISSIONSso it can restore), and its ownwh_Client_AuthUserAddmust now be denied. A change targeting a differentuser leaves the caller's session untouched.
USER_SET_PERMISSIONSlogs in and issues three calls. The two gates are toldapart by their return codes:
WH_ERROR_ACCESS— reached the backend, refused thereWH_AUTH_PERMISSION_ERROR— refused in the coreWH_AUTH_PERMISSION_ERROR— refusal is target-independentBoth cases capture their outcomes, restore the admin session and drop the users
they created before asserting, so a failing assert cannot leave the shared
POSIX server's admin baseline demoted or its 5-slot user table full.
The earlier mock
whAuthCb(263 lines) is dropped — the real backend isreachable, so it was testing the harness. Four of its cases have no client
equivalent and are not covered: backend-failure-leaves-cache-unchanged (the base
backend does not fail for a valid admin request), verbatim mirroring of an
unclamped
keyIdCount(only visible by readingctx.user.permissions), andadmin-grants-admin / admin-self-lockout (running those against the shared server
would permanently demote the admin baseline for every later test — documented in
5-Features.mdinstead).Note that against the base backend the admin-flag gate is defense in depth:
wh_Auth_BaseUserSetPermissionsis admin-only anyway, which is exactly what thecontrol case pins down. The gate binds for backends that permit non-admin
permission edits.
Verification
Merge base
237bfbc. Clean under-std=c90 -Werror -Wall -Wextra, zero warnings.test-refactor AUTH=1test-refactordefaulttest-refactor DMA=1test-refactor SHE=1Negative controls, each reverted and restored:
still adds users.
WH_ERROR_ACCESSwhereWH_AUTH_PERMISSION_ERRORis required.