From adac089fd6cb2ebc11932b7d46c893e14e6d6e3d Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Sun, 21 Jun 2026 02:36:58 +0200 Subject: [PATCH] Linux/macOS: surface post-sudo elevation errors Separate sudo authentication success from elevated request execution state by acknowledging when the elevated core service starts successfully. Once that channel is available, propagate later failures instead of showing repeated administrator password dialogs. Initialize the sudo dummy-password flag consistently on macOS, avoiding an uninitialized read of UseDummySudoPassword. Register admin-password cleanup before elevation attempts so plaintext sudo credentials are erased on early-return and post-sudo failure paths. References #1788. --- src/Core/CoreBase.cpp | 2 -- src/Core/Unix/CoreService.cpp | 41 +++++++++++++++++++++++---- src/Core/Unix/CoreService.h | 1 + src/Core/Unix/CoreServiceResponse.cpp | 11 +++++++ src/Core/Unix/CoreServiceResponse.h | 6 ++++ 5 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/Core/CoreBase.cpp b/src/Core/CoreBase.cpp index 5eadd6d2..c4bc9721 100644 --- a/src/Core/CoreBase.cpp +++ b/src/Core/CoreBase.cpp @@ -20,9 +20,7 @@ namespace VeraCrypt { CoreBase::CoreBase () : DeviceChangeInProgress (false) -#if defined(TC_LINUX ) || defined (TC_FREEBSD) , UseDummySudoPassword (false) -#endif #if defined(TC_UNIX) ,AllowInsecureMount (false) #endif diff --git a/src/Core/Unix/CoreService.cpp b/src/Core/Unix/CoreService.cpp index e69df959..014b5c8f 100644 --- a/src/Core/Unix/CoreService.cpp +++ b/src/Core/Unix/CoreService.cpp @@ -110,8 +110,7 @@ namespace VeraCrypt } #endif - template - unique_ptr CoreService::GetResponse () + unique_ptr CoreService::GetResponseObject () { unique_ptr deserializedObject (Serializable::DeserializeNew (ServiceOutputStream)); @@ -119,6 +118,14 @@ namespace VeraCrypt if (deserializedException) deserializedException->Throw(); + return deserializedObject; + } + + template + unique_ptr CoreService::GetResponse () + { + unique_ptr deserializedObject (GetResponseObject()); + if (dynamic_cast (deserializedObject.get()) == nullptr) throw ParameterIncorrect (SRC_POS); @@ -199,14 +206,21 @@ namespace VeraCrypt if (!ElevatedPrivileges && request->ElevateUserPrivileges) { + bool elevatedServiceStarted = false; + if (!ElevatedServiceAvailable) { finally_do_arg (string *, &request->AdminPassword, { StringConverter::Erase (*finally_arg); }); CoreService::StartElevated (*request); ElevatedServiceAvailable = true; + elevatedServiceStarted = true; } + // Report sudo/elevated-service success before executing the request. + if (elevatedServiceStarted) + ElevatedServiceStartedResponse().Serialize (outputStream); + request->Serialize (ServiceInputStream); GetResponse ()->Serialize (outputStream); continue; @@ -424,6 +438,7 @@ namespace VeraCrypt request.UserEnvPATH = Core->GetUserEnvPATH(); request.UseDummySudoPassword = Core->GetUseDummySudoPassword(); request.AllowInsecureMount = Core->GetAllowInsecureMount(); + finally_do_arg (string *, &request.AdminPassword, { StringConverter::Erase (*finally_arg); }); if (request.RequiresElevation()) { @@ -482,12 +497,28 @@ namespace VeraCrypt try { request.Serialize (ServiceInputStream); - unique_ptr response (GetResponse ()); + + unique_ptr response (GetResponseObject()); + if (dynamic_cast (response.get()) != nullptr) + { + // The elevated channel is usable even if the forwarded request fails. + // Any later failure must be propagated as the real error rather than + // triggering another administrator-password prompt. + ElevatedServiceAvailable = true; + return GetResponse (); + } + + if (dynamic_cast (response.get()) == nullptr) + throw ParameterIncorrect (SRC_POS); + ElevatedServiceAvailable = true; - return response; + return unique_ptr (dynamic_cast (response.release())); } catch (ElevationFailed &e) { + if (ElevatedServiceAvailable) + throw; + if (!request.FastElevation) { ExceptionEventArgs args (e); @@ -502,8 +533,6 @@ namespace VeraCrypt } } - finally_do_arg (string *, &request.AdminPassword, { StringConverter::Erase (*finally_arg); }); - request.Serialize (ServiceInputStream); return GetResponse (); } diff --git a/src/Core/Unix/CoreService.h b/src/Core/Unix/CoreService.h index 59dc32b1..fb772bd8 100644 --- a/src/Core/Unix/CoreService.h +++ b/src/Core/Unix/CoreService.h @@ -46,6 +46,7 @@ namespace VeraCrypt static void Stop (); protected: + static unique_ptr GetResponseObject (); template static unique_ptr GetResponse (); template static unique_ptr SendRequest (CoreServiceRequest &request); static void StartElevated (const CoreServiceRequest &request); diff --git a/src/Core/Unix/CoreServiceResponse.cpp b/src/Core/Unix/CoreServiceResponse.cpp index b1741b76..e14eea2b 100644 --- a/src/Core/Unix/CoreServiceResponse.cpp +++ b/src/Core/Unix/CoreServiceResponse.cpp @@ -15,6 +15,16 @@ namespace VeraCrypt { + // ElevatedServiceStartedResponse + void ElevatedServiceStartedResponse::Deserialize (shared_ptr stream) + { + } + + void ElevatedServiceStartedResponse::Serialize (shared_ptr stream) const + { + Serializable::Serialize (stream); + } + // CheckFilesystemResponse void CheckFilesystemResponse::Deserialize (shared_ptr stream) { @@ -124,6 +134,7 @@ namespace VeraCrypt Serializable::Serialize (stream); } + TC_SERIALIZER_FACTORY_ADD_CLASS (ElevatedServiceStartedResponse); TC_SERIALIZER_FACTORY_ADD_CLASS (CheckFilesystemResponse); TC_SERIALIZER_FACTORY_ADD_CLASS (DismountFilesystemResponse); TC_SERIALIZER_FACTORY_ADD_CLASS (DismountVolumeResponse); diff --git a/src/Core/Unix/CoreServiceResponse.h b/src/Core/Unix/CoreServiceResponse.h index c792ad31..d6c318ba 100644 --- a/src/Core/Unix/CoreServiceResponse.h +++ b/src/Core/Unix/CoreServiceResponse.h @@ -22,6 +22,12 @@ namespace VeraCrypt { }; + struct ElevatedServiceStartedResponse : CoreServiceResponse + { + ElevatedServiceStartedResponse () { } + TC_SERIALIZABLE (ElevatedServiceStartedResponse); + }; + struct CheckFilesystemResponse : CoreServiceResponse { CheckFilesystemResponse () { }