Fedora Account System
Red Hat Associate
Red Hat Customer
AI_ONLY_REPORT package: sssd-2.12.0-1.el10 ------ Summary: Unbounded `open_request_table` growth in IdP PREAUTH can cause local DoS (memory exhaustion): repeated successful PREAUTH flows can retain stale per-request state in a process-lifetime hash table without a size bound, timeout, or proactive cleanup, allowing local memory exhaustion when AUTHENTICATE is never completed. Requirements to exploit: A local attacker must be able to reach a PAM authentication surface handled by `sssd-2.12.0-1.el10` with IdP authentication enabled, repeatedly drive PREAUTH to a successful device-authorization reply, and stop before completing the matching AUTHENTICATE step for each returned `user_code`. Component affected: `sssd-2.12.0-1.el10`, IdP authentication backend in `src/providers/idp/idp_auth_eval.c` (`eval_device_auth_buf()`), `src/providers/idp/idp_auth.c` (`get_stored_request_data()`), and `src/providers/idp/idp_init.c` (`sssm_idp_auth_init()`). Version affected: `sssd-2.12.0-1.el10` when IdP authentication is enabled and the PREAUTH device-authorization flow is reachable. Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not notified. CVSS: CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - 6.2 (MEDIUM) AV:L - The attack requires local access to a PAM authentication surface on the affected host. AC:L - Once IdP authentication is enabled, repeatedly driving PREAUTH and withholding AUTHENTICATE is straightforward. PR:N - No prior privileges are required before attempting authentication. UI:N - No separate victim interaction is required. S:U - The impact remains within the same security scope. C:N - No confidentiality impact was established. I:N - No integrity impact was established. A:H - Persistent growth of stored request state can exhaust backend memory and disrupt authentication services. Impact: Moderate. This is a real availability issue on affected deployments, but it is local and configuration-dependent rather than a remote or default-path compromise. Based on Red Hat severity guidance, that fits Moderate better than Important or Critical. Embargo: no Reason: The demonstrated impact is local and availability-only, depends on IdP-enabled deployments, and has straightforward operational mitigation while a code fix is prepared. Acknowledgement: Aisle Research Vulnerability Details: In the IdP PREAUTH path, successful device-authorization replies allocate and store per-request state in `open_request_table` with no size limit, timeout, or eviction in the shown path: ```c /* src/providers/idp/idp_auth_eval.c */ open_req = talloc_zero(idp_auth_ctx, struct idp_open_req_data); open_req->device_code_data = talloc_strdup(open_req, (char *) buf); ret = sss_ptr_hash_add(idp_auth_ctx->open_request_table, user_data->user_code, open_req, struct idp_open_req_data); ``` The corresponding cleanup occurs only later in `get_stored_request_data()` during `SSS_PAM_AUTHENTICATE`, where the entry is looked up by `user_code` and then freed. The table itself is created under `auth_ctx` in `sssm_idp_auth_init()`, so it persists for backend lifetime. As a result, PREAUTH requests that successfully reach `eval_device_auth_buf()` but never complete AUTHENTICATE can leave stale entries behind. Repeated successful PREAUTH flows that produce fresh `user_code` values can therefore grow the table over time, increasing backend RSS and potentially degrading or terminating the affected SSSD backend under memory pressure. The available evidence supports availability impact only; no confidentiality, integrity, or privilege-escalation impact was established. Steps to reproduce: 1. Configure a test domain with IdP auth enabled (`idp_*` options set; IdP provider active). 2. Start SSSD and identify the IdP backend PID. 3. Trigger many PREAUTH attempts that reach `eval_device_auth_buf()` success, but never submit the matching OAuth2 `user_code` in AUTHENTICATE. 4. Observe growth during the run with `while true; do ps -o pid,rss,cmd -p <pid>; sleep 2; done`. Optional debug logs should show repeated successful PREAUTH handling with no matching AUTHENTICATE cleanup path. 5. Confirm memory is not reclaimed over time unless matching AUTHENTICATE happens. Prolonged runs can degrade or terminate the backend under memory pressure. Mitigation: Deployments that do not enable IdP authentication are not exposed to this path. Until a fix is available, disable the affected IdP authentication configuration where possible, restrict who can reach PAM services that exercise this flow, and restart the affected SSSD backend or service if memory growth is observed to reclaim accumulated entries. Proposed Fix: A minimal fix is to record request age, reject overly old stored requests, and bound the number of pending requests. ```diff diff --git a/src/providers/idp/idp_private.h b/src/providers/idp/idp_private.h index 3a2b0b7..e19f2d2 100644 — a/src/providers/idp/idp_private.h +++ b/src/providers/idp/idp_private.h @@ -51,6 +51,7 @@ requests. */ struct idp_open_req_data { + time_t created_at; char *device_code_data; }; diff --git a/src/providers/idp/idp_auth_eval.c b/src/providers/idp/idp_auth_eval.c index 7f6a9e2..3f0d8bc 100644 — a/src/providers/idp/idp_auth_eval.c +++ b/src/providers/idp/idp_auth_eval.c @@ -22,6 +22,7 @@ #include <errno.h> +#include <time.h> #include <jansson.h> @@ -41,6 +42,8 @@ errno_t eval_device_auth_buf(struct idp_auth_ctx *idp_auth_ctx, struct sss_idp_oauth2 *user_data = NULL; int ret; struct idp_open_req_data *open_req = NULL; + const size_t max_open_requests = 1024; + time_t now; @@ -76,6 +79,13 @@ errno_t eval_device_auth_buf(struct idp_auth_ctx *idp_auth_ctx, goto done; } + if (hash_count(idp_auth_ctx->open_request_table) >= max_open_requests) { + DEBUG(SSSDBG_OP_FAILURE, "Too many pending IdP auth requests.\n"); + ret = ENOSPC; + goto done; + } + + now = time(NULL); open_req = talloc_zero(idp_auth_ctx, struct idp_open_req_data); if (open_req == NULL) { @@ -83,6 +93,7 @@ errno_t eval_device_auth_buf(struct idp_auth_ctx *idp_auth_ctx, ret = ENOMEM; goto done; } + open_req->created_at = now; diff --git a/src/providers/idp/idp_auth.c b/src/providers/idp/idp_auth.c index 28baf1c..2d1a644 100644 — a/src/providers/idp/idp_auth.c +++ b/src/providers/idp/idp_auth.c @@ -23,6 +23,7 @@ #include <security/pam_modules.h> +#include <time.h> @@ -152,6 +153,7 @@ static const char *get_stored_request_data(TALLOC_CTX *mem_ctx, const char *user_code; size_t user_code_len; + const time_t max_age = 300; @@ -176,6 +178,12 @@ static const char *get_stored_request_data(TALLOC_CTX *mem_ctx, DEBUG(SSSDBG_OP_FAILURE, "Missing device code data.\n"); goto done; } + if (time(NULL) - open_req->created_at > max_age) { + DEBUG(SSSDBG_OP_FAILURE, "Stored device auth request expired.\n"); + send_data = NULL; + goto done; + } + ``` This is intentionally minimal; a stronger fix would also proactively prune expired entries from the full table. ------ This report was generated using AI technology. Always review AI-generated content prior to use