[PATCH] advapi32: test and fix ChangeServiceConfig2 when given a zero length or a null description (try2, resend)

Bernhard Übelacker bernhardu at vr-web.de
Fri Jul 17 05:11:48 CDT 2015


This patch avoids an error 998 while Flatout 2 tries to setup the copy
protection drivers/services.
Happens during the first run of FlatOut2.exe after the patch to v1.2.

The only visible sign in terminal output of the failure is this:
     err:rpc:I_RpcReceive we got fault packet with status 0x3e6

This is because the SC_RPC_CONFIG_INFOW parameter has in its
descr->lpDescription a null pointer instead of a valid LPWSTR.

This null pointer is accessed in svcctl_ChangeServiceConfig2W and
causes an exception there, but is hidden by the RPC layer.

Following are the contents of the dialogs shown after the fault:

  Protection Driver Installer Fatal Error
    Unhandled exception in the Protection Driver Installer.
    Try restart the application, if the problem still persist, contact the
    customer support service and provide the information following.

    Type: class LCommon::System::ServiceControl::Service::Exception
    Location: void __thiscall
    LCommon::System::ServiceControl::Service::ChangeDescription(class LUnicodeString)
    Line: 357
    Error Code: 998

  Protection Driver Management Fatal Error
    Unhandled exception in the Protection Driver
    Management subsystem.
    Try restart the application, if the problem still persist,
    contact the
    customer support service and provide the information following.

    Type: class
    LCommon::System::WindowsErrorException
    Location: enum DriverManager::Result __thiscall
    DriverManager::InstallDrivers(void)
    Line: 677
    Error Code: 998

  Schutz-System
    Fehler
    Beim Öffnen der Kopierschutztreiber kam es zu einem unerwarteten Fehler.
    Fehlernummer: 998.
---
 dlls/advapi32/tests/service.c | 66 +++++++++++++++++++++++++++++++++++++++++++
 programs/services/rpc.c       |  3 ++
 2 files changed, 69 insertions(+)

diff --git a/dlls/advapi32/tests/service.c b/dlls/advapi32/tests/service.c
index 81d2f74..13a24f5 100644
--- a/dlls/advapi32/tests/service.c
+++ b/dlls/advapi32/tests/service.c
@@ -36,6 +36,7 @@ static const CHAR spooler[] = "Spooler"; /* Should be available on all platforms
 static CHAR selfname[MAX_PATH];
 
 static BOOL (WINAPI *pChangeServiceConfig2A)(SC_HANDLE,DWORD,LPVOID);
+static BOOL (WINAPI *pChangeServiceConfig2W)(SC_HANDLE,DWORD,LPVOID);
 static BOOL (WINAPI *pEnumServicesStatusExA)(SC_HANDLE, SC_ENUM_TYPE, DWORD,
                                              DWORD, LPBYTE, DWORD, LPDWORD,
                                              LPDWORD, LPDWORD, LPCSTR);
@@ -57,6 +58,7 @@ static void init_function_pointers(void)
     HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
 
     pChangeServiceConfig2A = (void*)GetProcAddress(hadvapi32, "ChangeServiceConfig2A");
+    pChangeServiceConfig2W = (void*)GetProcAddress(hadvapi32, "ChangeServiceConfig2W");
     pEnumServicesStatusExA= (void*)GetProcAddress(hadvapi32, "EnumServicesStatusExA");
     pEnumServicesStatusExW= (void*)GetProcAddress(hadvapi32, "EnumServicesStatusExW");
     pGetSecurityInfo = (void *)GetProcAddress(hadvapi32, "GetSecurityInfo");
@@ -1954,6 +1956,7 @@ static void test_queryconfig2(void)
     DWORD expected, needed;
     BYTE buffer[MAX_PATH];
     LPSERVICE_DESCRIPTIONA pConfig = (LPSERVICE_DESCRIPTIONA)buffer;
+    LPSERVICE_DESCRIPTIONW pConfigW = (LPSERVICE_DESCRIPTIONW)buffer;
     SERVICE_PRESHUTDOWN_INFO preshutdown_info;
     static const CHAR servicename [] = "Winetest";
     static const CHAR displayname [] = "Winetest dummy service";
@@ -1961,6 +1964,9 @@ static void test_queryconfig2(void)
     static const CHAR dependencies[] = "Master1\0Master2\0+MasterGroup1\0";
     static const CHAR password    [] = "";
     static const CHAR description [] = "Description";
+    static const CHAR description_empty[] = "";
+    static const WCHAR descriptionW [] = {'D','e','s','c','r','i','p','t','i','o','n','W',0};
+    static const WCHAR descriptionW_empty[] = {0};
 
     if(!pQueryServiceConfig2A)
     {
@@ -2121,6 +2127,66 @@ static void test_queryconfig2(void)
     ret = pQueryServiceConfig2W(svc_handle, SERVICE_CONFIG_DESCRIPTION,buffer, needed,&needed);
     ok(ret, "expected QueryServiceConfig2W to succeed\n");
 
+    pConfig->lpDescription = (LPSTR)description;
+    ret = pChangeServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION, &buffer);
+    ok(ret, "expected ChangeServiceConfig2A to succeed\n");
+
+    pConfig->lpDescription = NULL;
+    ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION, buffer, sizeof(buffer), &needed);
+    ok(ret, "expected QueryServiceConfig2A to succeed\n");
+    ok(pConfig->lpDescription && !strcmp(description, pConfig->lpDescription),
+        "expected lpDescription to be %s, got %s\n", description, pConfig->lpDescription);
+
+    pConfig->lpDescription = NULL;
+    ret = pChangeServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION, &buffer);
+    ok(ret, "expected ChangeServiceConfig2A to succeed\n");
+
+    pConfig->lpDescription = NULL;
+    ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION, buffer, sizeof(buffer), &needed);
+    ok(ret, "expected QueryServiceConfig2A to succeed\n");
+    ok(pConfig->lpDescription && !strcmp(description, pConfig->lpDescription),
+        "expected lpDescription to be %s, got %s\n", description, pConfig->lpDescription);
+
+    pConfig->lpDescription = (LPSTR)description_empty;
+    ret = pChangeServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION, &buffer);
+    ok(ret, "expected ChangeServiceConfig2A to succeed\n");
+
+    pConfig->lpDescription = (void*)0xdeadbeef;
+    ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION, buffer, sizeof(buffer), &needed);
+    ok(ret, "expected QueryServiceConfig2A to succeed\n");
+    ok(!pConfig->lpDescription,
+        "expected lpDescription to be null, got %s\n", pConfig->lpDescription);
+
+    pConfigW->lpDescription = (LPWSTR)descriptionW;
+    ret = pChangeServiceConfig2W(svc_handle, SERVICE_CONFIG_DESCRIPTION, &buffer);
+    ok(ret, "expected ChangeServiceConfig2W to succeed\n");
+
+    pConfigW->lpDescription = NULL;
+    ret = pQueryServiceConfig2W(svc_handle, SERVICE_CONFIG_DESCRIPTION, buffer, sizeof(buffer), &needed);
+    ok(ret, "expected QueryServiceConfig2A to succeed\n");
+    ok(pConfigW->lpDescription && !lstrcmpW(descriptionW, pConfigW->lpDescription),
+        "expected lpDescription to be %s, got %s\n", wine_dbgstr_w(descriptionW), wine_dbgstr_w(pConfigW->lpDescription));
+
+    pConfigW->lpDescription = NULL;
+    ret = pChangeServiceConfig2W(svc_handle, SERVICE_CONFIG_DESCRIPTION, &buffer);
+    ok(ret, "expected ChangeServiceConfig2W to succeed\n");
+
+    pConfigW->lpDescription = NULL;
+    ret = pQueryServiceConfig2W(svc_handle, SERVICE_CONFIG_DESCRIPTION, buffer, sizeof(buffer), &needed);
+    ok(ret, "expected QueryServiceConfig2A to succeed\n");
+    ok(pConfigW->lpDescription && !lstrcmpW(descriptionW, pConfigW->lpDescription),
+        "expected lpDescription to be %s, got %s\n", wine_dbgstr_w(descriptionW), wine_dbgstr_w(pConfigW->lpDescription));
+
+    pConfigW->lpDescription = (LPWSTR)descriptionW_empty;
+    ret = pChangeServiceConfig2W(svc_handle, SERVICE_CONFIG_DESCRIPTION, &buffer);
+    ok(ret, "expected ChangeServiceConfig2W to succeed\n");
+
+    pConfigW->lpDescription = (void*)0xdeadbeef;
+    ret = pQueryServiceConfig2W(svc_handle, SERVICE_CONFIG_DESCRIPTION, buffer, sizeof(buffer), &needed);
+    ok(ret, "expected QueryServiceConfig2A to succeed\n");
+    ok(!pConfigW->lpDescription,
+        "expected lpDescription to be null, got %s\n", wine_dbgstr_w(pConfigW->lpDescription));
+
     SetLastError(0xdeadbeef);
     ret = pQueryServiceConfig2W(svc_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
             (LPBYTE)&preshutdown_info, sizeof(preshutdown_info), &needed);
diff --git a/programs/services/rpc.c b/programs/services/rpc.c
index 89a8c91..753e7ec 100644
--- a/programs/services/rpc.c
+++ b/programs/services/rpc.c
@@ -798,6 +798,9 @@ DWORD __cdecl svcctl_ChangeServiceConfig2W( SC_RPC_HANDLE hService, SC_RPC_CONFI
         {
             WCHAR *descr = NULL;
 
+            if (!config.u.descr->lpDescription)
+                break;
+
             if (config.u.descr->lpDescription[0])
             {
                 if (!(descr = strdupW( config.u.descr->lpDescription )))
-- 
2.1.4




More information about the wine-patches mailing list