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.
This commit is contained in:
Mounir IDRASSI
2026-06-21 02:36:58 +02:00
parent 0d375e9a6a
commit adac089fd6
5 changed files with 53 additions and 8 deletions
-2
View File
@@ -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
+35 -6
View File
@@ -110,8 +110,7 @@ namespace VeraCrypt
}
#endif
template <class T>
unique_ptr <T> CoreService::GetResponse ()
unique_ptr <Serializable> CoreService::GetResponseObject ()
{
unique_ptr <Serializable> deserializedObject (Serializable::DeserializeNew (ServiceOutputStream));
@@ -119,6 +118,14 @@ namespace VeraCrypt
if (deserializedException)
deserializedException->Throw();
return deserializedObject;
}
template <class T>
unique_ptr <T> CoreService::GetResponse ()
{
unique_ptr <Serializable> deserializedObject (GetResponseObject());
if (dynamic_cast <T *> (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 <Serializable>()->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 <T> response (GetResponse <T>());
unique_ptr <Serializable> response (GetResponseObject());
if (dynamic_cast <ElevatedServiceStartedResponse *> (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 <T> ();
}
if (dynamic_cast <T *> (response.get()) == nullptr)
throw ParameterIncorrect (SRC_POS);
ElevatedServiceAvailable = true;
return response;
return unique_ptr <T> (dynamic_cast <T *> (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 <T>();
}
+1
View File
@@ -46,6 +46,7 @@ namespace VeraCrypt
static void Stop ();
protected:
static unique_ptr <Serializable> GetResponseObject ();
template <class T> static unique_ptr <T> GetResponse ();
template <class T> static unique_ptr <T> SendRequest (CoreServiceRequest &request);
static void StartElevated (const CoreServiceRequest &request);
+11
View File
@@ -15,6 +15,16 @@
namespace VeraCrypt
{
// ElevatedServiceStartedResponse
void ElevatedServiceStartedResponse::Deserialize (shared_ptr <Stream> stream)
{
}
void ElevatedServiceStartedResponse::Serialize (shared_ptr <Stream> stream) const
{
Serializable::Serialize (stream);
}
// CheckFilesystemResponse
void CheckFilesystemResponse::Deserialize (shared_ptr <Stream> 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);
+6
View File
@@ -22,6 +22,12 @@ namespace VeraCrypt
{
};
struct ElevatedServiceStartedResponse : CoreServiceResponse
{
ElevatedServiceStartedResponse () { }
TC_SERIALIZABLE (ElevatedServiceStartedResponse);
};
struct CheckFilesystemResponse : CoreServiceResponse
{
CheckFilesystemResponse () { }