https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a8d256bf23cefe9e8d163e...
commit a8d256bf23cefe9e8d163e1a6522928e63796a16 Author: Eric Kohl eric.kohl@reactos.org AuthorDate: Sun Feb 18 18:47:42 2018 +0100 Commit: Eric Kohl eric.kohl@reactos.org CommitDate: Mon Feb 19 00:14:58 2018 +0100
[SERVICES] Update a drivers status properly
- ScmUnloadDriver: Handle failed unload properly. - ScmGetDriverStatus: A driver is running when its driver object was found. Otherwise it has been stopped. - ScmControlDriver: Check a drivers status before and after unloading.
CORE-14317 --- base/system/services/driver.c | 91 +++++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 30 deletions(-)
diff --git a/base/system/services/driver.c b/base/system/services/driver.c index 819183e5c0..2293acd053 100644 --- a/base/system/services/driver.c +++ b/base/system/services/driver.c @@ -71,6 +71,7 @@ done: return RtlNtStatusToDosError(Status); }
+ static DWORD ScmUnloadDriver(PSERVICE lpService) @@ -79,6 +80,7 @@ ScmUnloadDriver(PSERVICE lpService) BOOLEAN WasPrivilegeEnabled = FALSE; PWSTR pszDriverPath; UNICODE_STRING DriverPath; + DWORD dwError;
/* Build the driver path */ /* 52 = wcslen(L"\Registry\Machine\System\CurrentControlSet\Services\") */ @@ -107,10 +109,15 @@ ScmUnloadDriver(PSERVICE lpService) { /* We encountered a failure, exit properly */ DPRINT1("SERVICES: Cannot acquire driver-unloading privilege, Status = 0x%08lx\n", Status); + dwError = RtlNtStatusToDosError(Status); goto done; }
Status = NtUnloadDriver(&DriverPath); + if (Status == STATUS_INVALID_DEVICE_REQUEST) + dwError = ERROR_INVALID_SERVICE_CONTROL; + else + dwError = RtlNtStatusToDosError(Status);
/* Release driver-unloading privilege */ RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, @@ -120,7 +127,7 @@ ScmUnloadDriver(PSERVICE lpService)
done: HeapFree(GetProcessHeap(), 0, pszDriverPath); - return RtlNtStatusToDosError(Status); + return dwError; }
@@ -139,6 +146,7 @@ ScmGetDriverStatus(PSERVICE lpService, ULONG Index; DWORD dwError = ERROR_SUCCESS; BOOLEAN bFound = FALSE; + DWORD dwPreviousState;
DPRINT1("ScmGetDriverStatus() called\n");
@@ -239,46 +247,61 @@ ScmGetDriverStatus(PSERVICE lpService, * We found the driver: it means it's running * We didn't find the driver: it wasn't running */ - if ((bFound != FALSE) && - (lpService->Status.dwCurrentState != SERVICE_STOP_PENDING)) + if (bFound) { - if (lpService->Status.dwCurrentState == SERVICE_STOPPED) + /* Found, return it's running */ + + dwPreviousState = lpService->Status.dwCurrentState; + + /* It is running */ + lpService->Status.dwCurrentState = SERVICE_RUNNING; + + if (dwPreviousState == SERVICE_STOPPED) { + /* Make it run if it was stopped before */ lpService->Status.dwWin32ExitCode = ERROR_SUCCESS; lpService->Status.dwServiceSpecificExitCode = ERROR_SUCCESS; + lpService->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; lpService->Status.dwCheckPoint = 0; lpService->Status.dwWaitHint = 0; - lpService->Status.dwControlsAccepted = 0; } - else - { - lpService->Status.dwCurrentState = SERVICE_RUNNING; - lpService->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
- if (lpService->Status.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED) - lpService->Status.dwWin32ExitCode = ERROR_SUCCESS; - } + if (lpService->Status.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED) + lpService->Status.dwWin32ExitCode = ERROR_SUCCESS; } - /* Not found, return it's stopped */ else { - lpService->Status.dwCurrentState = SERVICE_STOPPED; - lpService->Status.dwControlsAccepted = 0; - lpService->Status.dwCheckPoint = 0; - lpService->Status.dwWaitHint = 0; + /* Not found, return it's stopped */
if (lpService->Status.dwCurrentState == SERVICE_STOP_PENDING) + { + /* Stopped successfully */ lpService->Status.dwWin32ExitCode = ERROR_SUCCESS; + lpService->Status.dwCurrentState = SERVICE_STOPPED; + lpService->Status.dwControlsAccepted = 0; + lpService->Status.dwCheckPoint = 0; + lpService->Status.dwWaitHint = 0; + } + else if (lpService->Status.dwCurrentState == SERVICE_STOPPED) + { + /* Don't change the current status */ + } else + { lpService->Status.dwWin32ExitCode = ERROR_GEN_FAILURE; + lpService->Status.dwCurrentState = SERVICE_STOPPED; + lpService->Status.dwControlsAccepted = 0; + lpService->Status.dwCheckPoint = 0; + lpService->Status.dwWaitHint = 0; + } }
/* Copy service status if required */ if (lpServiceStatus != NULL) { - memcpy(lpServiceStatus, - &lpService->Status, - sizeof(SERVICE_STATUS)); + RtlCopyMemory(lpServiceStatus, + &lpService->Status, + sizeof(SERVICE_STATUS)); }
DPRINT1("ScmGetDriverStatus() done (Error: %lu)\n", dwError); @@ -320,26 +343,34 @@ ScmControlDriver(PSERVICE lpService, switch (dwControl) { case SERVICE_CONTROL_STOP: + /* Check the drivers status */ + dwError = ScmGetDriverStatus(lpService, + lpServiceStatus); + if (dwError != ERROR_SUCCESS) + goto done; + + /* Fail, if it is not running */ if (lpService->Status.dwCurrentState != SERVICE_RUNNING) { dwError = ERROR_INVALID_SERVICE_CONTROL; goto done; }
+ /* Unload the driver */ dwError = ScmUnloadDriver(lpService); - if (dwError == ERROR_SUCCESS) + if (dwError == ERROR_INVALID_SERVICE_CONTROL) { - lpService->Status.dwCurrentState = SERVICE_STOPPED; + /* The driver cannot be stopped, mark it non-stoppable */ lpService->Status.dwControlsAccepted = 0; - lpService->Status.dwWin32ExitCode = ERROR_SUCCESS; - - if (lpServiceStatus != NULL) - { - RtlCopyMemory(lpServiceStatus, - &lpService->Status, - sizeof(SERVICE_STATUS)); - } + goto done; } + + /* Make the driver 'stop pending' */ + lpService->Status.dwCurrentState = SERVICE_STOP_PENDING; + + /* Check the drivers status again */ + dwError = ScmGetDriverStatus(lpService, + lpServiceStatus); break;
case SERVICE_CONTROL_INTERROGATE: