From: Michal Privoznik <[email protected]> The usual flow of SASL is REMOTE_PROC_AUTH_SASL_INIT followed by REMOTE_PROC_AUTH_SASL_START which can either complete authentication or require further steps which are then done by calling REMOTE_PROC_AUTH_SASL_STEP (multiple times even).
But if a malicious client skips the SASL_START step and calls SASL_INIT followed by SASL_STEP then the 'sasl->conn' structure inside of virNetSASLSessionServerStep() is not fully allocated (most notably the list of auth mechanisms 'mech' is NULL). But then sasl_server_step() dereferences that pointer leading to a crash. Fix this by disallowing SASL_STEP until SASL_START completed successfully. Fixes: CVE-2026-119151 Resolves: https://gitlab.com/libvirt/libvirt/-/work_items/940 Signed-off-by: Michal Privoznik <[email protected]> --- src/libvirt_sasl.syms | 1 + src/remote/remote_daemon_dispatch.c | 8 +++++--- src/rpc/virnetsaslcontext.c | 25 +++++++++++++++++++++++++ src/rpc/virnetsaslcontext.h | 2 ++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/libvirt_sasl.syms b/src/libvirt_sasl.syms index 405ba1813e..c2a9144f0e 100644 --- a/src/libvirt_sasl.syms +++ b/src/libvirt_sasl.syms @@ -18,6 +18,7 @@ virNetSASLSessionExtKeySize; virNetSASLSessionGetIdentity; virNetSASLSessionGetKeySize; virNetSASLSessionGetMaxBufSize; +virNetSASLSessionIsStarted; virNetSASLSessionListMechanisms; virNetSASLSessionNewClient; virNetSASLSessionNewServer; diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c index e548438250..a813111c8d 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -3942,7 +3942,8 @@ remoteDispatchAuthSaslStart(virNetServer *server, VIR_DEBUG("Start SASL auth %d", virNetServerClientGetFD(client)); if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL || - priv->sasl == NULL) { + priv->sasl == NULL || + virNetSASLSessionIsStarted(priv->sasl)) { VIR_ERROR(_("client tried invalid SASL start request")); goto authfail; } @@ -4033,8 +4034,9 @@ remoteDispatchAuthSaslStep(virNetServer *server, VIR_DEBUG("Step SASL auth %d", virNetServerClientGetFD(client)); if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL || - priv->sasl == NULL) { - VIR_ERROR(_("client tried invalid SASL start request")); + priv->sasl == NULL || + !virNetSASLSessionIsStarted(priv->sasl)) { + VIR_ERROR(_("client tried invalid SASL step request")); goto authfail; } diff --git a/src/rpc/virnetsaslcontext.c b/src/rpc/virnetsaslcontext.c index 8692703117..e6b57b7b95 100644 --- a/src/rpc/virnetsaslcontext.c +++ b/src/rpc/virnetsaslcontext.c @@ -43,6 +43,7 @@ struct _virNetSASLSession { sasl_conn_t *conn; size_t maxbufsize; sasl_callback_t *callbacks; + bool started; }; @@ -529,6 +530,13 @@ int virNetSASLSessionServerStart(virNetSASLSession *sasl, int ret = -1; virObjectLock(sasl); + + if (sasl->started) { + virReportError(VIR_ERR_AUTH_FAILED, "%s", + _("unexpected state of SASL session")); + goto cleanup; + } + err = sasl_server_start(sasl->conn, mechname, clientin, @@ -542,13 +550,16 @@ int virNetSASLSessionServerStart(virNetSASLSession *sasl, case SASL_OK: if (virNetSASLSessionUpdateBufSize(sasl) < 0) goto cleanup; + sasl->started = true; ret = VIR_NET_SASL_COMPLETE; break; case SASL_CONTINUE: ret = VIR_NET_SASL_CONTINUE; + sasl->started = true; break; case SASL_INTERACT: ret = VIR_NET_SASL_INTERACT; + sasl->started = true; break; default: virReportError(VIR_ERR_AUTH_FAILED, @@ -575,6 +586,13 @@ int virNetSASLSessionServerStep(virNetSASLSession *sasl, int ret = -1; virObjectLock(sasl); + + if (sasl->started == false) { + virReportError(VIR_ERR_AUTH_FAILED, "%s", + _("unexpected state of SASL session")); + goto cleanup; + } + err = sasl_server_step(sasl->conn, clientin, inlen, @@ -707,6 +725,13 @@ void virNetSASLSessionDispose(void *obj) g_free(sasl->callbacks); } +bool virNetSASLSessionIsStarted(virNetSASLSession *sasl) +{ + VIR_LOCK_GUARD lock = virObjectLockGuard(sasl); + + return sasl->started; +} + #ifdef __APPLE__ VIR_WARNINGS_RESET #endif diff --git a/src/rpc/virnetsaslcontext.h b/src/rpc/virnetsaslcontext.h index 7202822e5b..5bfb273e67 100644 --- a/src/rpc/virnetsaslcontext.h +++ b/src/rpc/virnetsaslcontext.h @@ -109,3 +109,5 @@ ssize_t virNetSASLSessionDecode(virNetSASLSession *sasl, size_t inputLen, const char **output, size_t *outputlen); + +bool virNetSASLSessionIsStarted(virNetSASLSession *sasl); -- 2.56.0
