dll: FspFsctlFixServiceSecurity: deny SERVICE_STOP to Everyone

Although the FSD can now be unloaded, this can only be done safely via
the new FSP_FSCTL_UNLOAD control code. For this reason we disable the
ability to stop the FSD via the Service Manager.
This commit is contained in:
Bill Zissimopoulos 2022-08-19 19:43:48 +01:00
parent 9670caa3fe
commit 7e59c2e5a6

View File

@ -617,8 +617,7 @@ static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
PSID WorldSid; PSID WorldSid;
PSECURITY_DESCRIPTOR SecurityDescriptor = 0; PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
PSECURITY_DESCRIPTOR NewSecurityDescriptor = 0; PSECURITY_DESCRIPTOR NewSecurityDescriptor = 0;
EXPLICIT_ACCESSW AccessEntry; EXPLICIT_ACCESSW AccessEntries[2];
ACCESS_MASK AccessRights;
PACL Dacl; PACL Dacl;
BOOL DaclPresent, DaclDefaulted; BOOL DaclPresent, DaclDefaulted;
DWORD Size; DWORD Size;
@ -663,41 +662,28 @@ static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
goto exit; goto exit;
} }
/* prepare an EXPLICIT_ACCESS for the SERVICE_QUERY_STATUS | SERVICE_START right for Everyone */ /* prepare an EXPLICIT_ACCESS for the SERVICE_QUERY_STATUS | SERVICE_START rights for Everyone */
AccessEntry.grfAccessPermissions = SERVICE_QUERY_STATUS | SERVICE_START; AccessEntries[0].grfAccessPermissions = SERVICE_QUERY_STATUS | SERVICE_START;
AccessEntry.grfAccessMode = GRANT_ACCESS; AccessEntries[0].grfAccessMode = GRANT_ACCESS;
AccessEntry.grfInheritance = NO_INHERITANCE; AccessEntries[0].grfInheritance = NO_INHERITANCE;
AccessEntry.Trustee.pMultipleTrustee = 0; AccessEntries[0].Trustee.pMultipleTrustee = 0;
AccessEntry.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; AccessEntries[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
AccessEntry.Trustee.TrusteeForm = TRUSTEE_IS_SID; AccessEntries[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
AccessEntry.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; AccessEntries[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
AccessEntry.Trustee.ptstrName = WorldSid; AccessEntries[0].Trustee.ptstrName = WorldSid;
/* get the effective rights for Everyone */ /* prepare an EXPLICIT_ACCESS to deny the SERVICE_STOP right to Everyone */
AccessRights = 0; AccessEntries[1].grfAccessPermissions = SERVICE_STOP;
if (DaclPresent && 0 != Dacl) AccessEntries[1].grfAccessMode = DENY_ACCESS;
{ AccessEntries[1].grfInheritance = NO_INHERITANCE;
LastError = GetEffectiveRightsFromAclW(Dacl, &AccessEntry.Trustee, &AccessRights); AccessEntries[1].Trustee.pMultipleTrustee = 0;
if (0 != LastError) AccessEntries[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
/* AccessEntries[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
* Apparently GetEffectiveRightsFromAclW can fail with ERROR_CIRCULAR_DEPENDENCY AccessEntries[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
* in some rare circumstances. Calling GetEffectiveRightsFromAclW is not essential AccessEntries[1].Trustee.ptstrName = WorldSid;
* in this instance. It is only done to check whether the "Everyone/World" SID
* already has the access required to start the FSD; if it does not have those
* rights already they are added. It is probably safe to just assume that the
* required rights are not there if GetEffectiveRightsFromAclW fails; the worst
* that can happen is that the rights get added twice (which is benign).
*
* See https://github.com/winfsp/winfsp/issues/62
*/
AccessRights = 0;
}
/* do we have the required access rights? */
if (AccessEntry.grfAccessPermissions != (AccessRights & AccessEntry.grfAccessPermissions))
{
/* create a new security descriptor with the new access */ /* create a new security descriptor with the new access */
LastError = BuildSecurityDescriptorW(0, 0, 1, &AccessEntry, 0, 0, SecurityDescriptor, LastError = BuildSecurityDescriptorW(0, 0, 2, AccessEntries, 0, 0, SecurityDescriptor,
&Size, &NewSecurityDescriptor); &Size, &NewSecurityDescriptor);
if (0 != LastError) if (0 != LastError)
{ {
@ -711,7 +697,6 @@ static NTSTATUS FspFsctlFixServiceSecurity(HANDLE SvcHandle)
Result = FspNtStatusFromWin32(GetLastError()); Result = FspNtStatusFromWin32(GetLastError());
goto exit; goto exit;
} }
}
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;