advapi32: test and fix ChangeServiceConfig2 when given a zero length or a null description (try4, resend)

Bernhard Übelacker bernhardu at mailbox.org
Wed Oct 11 08:36:16 CDT 2017


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.

Try 1: https://www.winehq.org/pipermail/wine-patches/2015-March/137996.html
Review: https://www.winehq.org/pipermail/wine-devel/2015-March/106999.html
        https://www.winehq.org/pipermail/wine-devel/2015-March/107000.html
        https://www.winehq.org/pipermail/wine-devel/2015-March/107002.html
        https://www.winehq.org/pipermail/wine-devel/2015-March/107014.html
        https://www.winehq.org/pipermail/wine-devel/2015-March/107025.html
        https://www.winehq.org/pipermail/wine-devel/2015-March/107075.html
        https://www.winehq.org/pipermail/wine-devel/2015-March/107086.html

Changes in try 2:
* Move check of descr->lpDescription to server side
* Add some more tests and check the results.

Try 2: https://www.winehq.org/pipermail/wine-patches/2015-June/139762.html
Testbot: https://www.winehq.org/pipermail/wine-devel/2015-June/107788.html

No changes in try 3.

Try 3: https://www.winehq.org/pipermail/wine-patches/2015-July/140923.html
Testbot: https://www.winehq.org/pipermail/wine-devel/2015-July/108455.html
Review: https://www.winehq.org/pipermail/wine-devel/2015-July/108496.html

No changes in try 4.

Signed-off-by: Bernhard Übelacker <bernhardu at mailbox.org>
---
 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 ab7ae2e8fe..405cef7662 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 8c95b7eb77..4435af935d 100644
--- a/programs/services/rpc.c
+++ b/programs/services/rpc.c
@@ -826,6 +826,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.11.0




More information about the wine-patches mailing list