[PATCH 1/4] [NTDLL]: added ldt query on processes

Eric Pouech eric.pouech at wanadoo.fr
Sat Nov 4 04:52:29 CST 2006


- NtQueryInformationProcess: implemented ProcessLdtInformation class

A+
---

 dlls/ntdll/process.c         |   48 ++++++++++++
 dlls/ntdll/tests/Makefile.in |    1 
 dlls/ntdll/tests/selector.c  |  164 ++++++++++++++++++++++++++++++++++++++++++
 include/winternl.h           |    6 ++
 4 files changed, 217 insertions(+), 2 deletions(-)

diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c
index 5af750d..7b8fcaa 100644
--- a/dlls/ntdll/process.c
+++ b/dlls/ntdll/process.c
@@ -34,6 +34,7 @@ #include "windef.h"
 #include "winternl.h"
 #include "ntdll_misc.h"
 #include "wine/server.h"
+#include "wine/library.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
 
@@ -104,7 +105,6 @@ NTSTATUS WINAPI NtQueryInformationProces
     UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority);
     UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort);
     UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken);
-    UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation);
     UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize);
     UNIMPLEMENTED_INFO_CLASS(ProcessDefaultHardErrorMode);
     UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers);
@@ -291,6 +291,50 @@ NTSTATUS WINAPI NtQueryInformationProces
         }
         else ret = STATUS_INFO_LENGTH_MISMATCH;
         break;
+    case ProcessLdtInformation:
+#ifdef __i386__
+        if (ProcessHandle != GetCurrentProcess())
+        {
+            FIXME("Unsupported yet on other processes\n");
+            ret = STATUS_NOT_IMPLEMENTED;
+        }
+        else if ((ProcessInformationLength & 7) == 0)
+        {
+            PROCESS_LDT_INFORMATION*    pli = ProcessInformation;
+            LDT_ENTRY                   le;
+
+            /* only works for clean LDT indexes */
+            if ((pli->dwSelector & 7) != 0)
+                ret = STATUS_INVALID_LDT_OFFSET;
+            else if (ProcessInformationLength < 2 * sizeof(DWORD) + pli->dwSize)
+                ret = STATUS_INFO_LENGTH_MISMATCH;
+            else if ((pli->dwSize % sizeof(LDT_ENTRY)) != 0)
+                ret = STATUS_INVALID_LDT_SIZE;
+            else
+            {
+                int i;
+                
+                len = 2 * sizeof(DWORD);
+                for (i = 0; i < pli->dwSize / sizeof(LDT_ENTRY); i++)
+                {
+                    wine_ldt_get_entry(pli->dwSelector + (i << 3) + 4, &le);
+                    if (!wine_ldt_is_empty(&le))
+                    {
+                        len += sizeof(LDT_ENTRY);
+                        pli->ldt[i] = le;
+                    }
+                }
+                /* FIXME: it should return the full LDT size, but we don't
+                 * properly handle this field yet
+                 */
+                pli->dwSize = 0;
+            }
+        }
+        else ret = STATUS_INFO_LENGTH_MISMATCH;
+#else
+        ret = STATUS_NOT_IMPLEMENTED;
+#endif
+        break;
     default:
         FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n",
               ProcessHandle,ProcessInformationClass,
@@ -300,7 +344,7 @@ NTSTATUS WINAPI NtQueryInformationProces
         break;
     }
 
-    if (ReturnLength) *ReturnLength = len;
+    if (ret == STATUS_SUCCESS && ReturnLength) *ReturnLength = len;
     
     return ret;
 }
diff --git a/dlls/ntdll/tests/Makefile.in b/dlls/ntdll/tests/Makefile.in
index cccc4c5..de923fa 100644
--- a/dlls/ntdll/tests/Makefile.in
+++ b/dlls/ntdll/tests/Makefile.in
@@ -21,6 +21,7 @@ CTESTS = \
 	rtl.c \
 	rtlbitmap.c \
 	rtlstr.c \
+	selector.c \
 	string.c \
 	time.c
 
diff --git a/dlls/ntdll/tests/selector.c b/dlls/ntdll/tests/selector.c
new file mode 100644
index 0000000..4d3ea92
--- /dev/null
+++ b/dlls/ntdll/tests/selector.c
@@ -0,0 +1,164 @@
+/*
+ * LDT and GDT tests
+ *
+ * Copyright 2006 Eric Pouech
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include <ntstatus.h>
+#define WIN32_NO_STATUS
+#include <windows.h>
+#include <stdio.h>
+#include <winternl.h>
+#include "wine/test.h"
+
+#ifdef __i386__
+
+/* TODO:
+ * - test the dwSize value returned from ProcessLdtInformation (should be the total
+ *   LDT size, but we don't handle it yet correctly)
+ */
+static int (WINAPI *pNtQueryInformationProcess)(HANDLE,DWORD,VOID*,DWORD,DWORD*);
+
+#define __SEL(x,r)      (((x) << 3) | ((r) & 3))
+#define LDT(x,r)        (__SEL((x), (r)) | 4)
+#define GDT(x,r)        __SEL((x), (r))
+/* in Process related APIs, we can only pass LDT, but in form of
+ * entry in the LDT table
+ */
+#define PROC_LDT(x)     __SEL((x), 0)
+
+static unsigned find_unused_ldt_entry(void)
+{
+    DWORD                       buf[4];
+    PROCESS_LDT_INFORMATION*    pli = (PROCESS_LDT_INFORMATION*)buf;
+    NTSTATUS                    status;
+    DWORD                       dw;
+    unsigned                    entry;
+
+    /* Wine cannot use the first 512 slots :-/ */
+    for (entry = 512; entry < 8192; entry++)
+    {
+        pli->dwSelector = PROC_LDT(entry);
+        pli->dwSize = 8;
+        memset(&pli->ldt[0], 0, sizeof(LDT_ENTRY));
+        status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessLdtInformation, buf, 16, &dw);
+        if (status == STATUS_SUCCESS && !pli->ldt->HighWord.Bits.Pres)
+            break;
+    }
+    ok(entry < 8192, "Couldn't find an unused slot in LDT\n");
+    return entry;
+}
+
+static void test_fail_process(unsigned entry)
+{
+    DWORD                       buf[12];
+    PROCESS_LDT_INFORMATION*    pli = (PROCESS_LDT_INFORMATION*)buf;
+    NTSTATUS                    status;
+    DWORD dw;
+
+    pli->dwSelector = PROC_LDT(entry);
+    pli->dwSize = 8;
+    dw = 0x12345678;
+    status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessLdtInformation, buf, 16, &dw);
+    ok(status == STATUS_SUCCESS, "Wrong status %x\n", status);
+    ok(dw == 8, "Wrong dw value %d\n", dw);
+    ok(pli->dwSize == 0, "Wrong pli->dwSize value %d\n", pli->dwSize);
+
+    pli->dwSelector = LDT(entry, 3);
+    pli->dwSize = 8;
+    dw = 0x12345678;
+    status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessLdtInformation, buf, 16, &dw);
+    ok(status == STATUS_INVALID_LDT_OFFSET, "Wrong status %x\n", status);
+    ok(dw == 0x12345678, "Wrong dw value %d\n", dw);
+    ok(pli->dwSize == 8, "Wrong pli->dwSize value %d\n", pli->dwSize);
+
+    pli->dwSelector = LDT(entry, 0);
+    pli->dwSize = 8;
+    dw = 0x12345678;
+    status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessLdtInformation, buf, 16, &dw);
+    ok(status == STATUS_INVALID_LDT_OFFSET, "Wrong status %x\n", status);
+    ok(dw == 0x12345678, "Wrong dw value %d\n", dw);
+    ok(pli->dwSize == 8, "Wrong pli->dwSize value %d\n", pli->dwSize);
+
+    pli->dwSelector = PROC_LDT(entry);
+    pli->dwSize = 8;
+    dw = 0;
+    status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessLdtInformation, buf,8, &dw);
+    ok(status == STATUS_INFO_LENGTH_MISMATCH, "Wrong status %x\n", status);
+    ok(pli->dwSize == 8, "Wrong pli->dwSize value %d\n", pli->dwSize);
+
+    pli->dwSelector = PROC_LDT(entry);
+    pli->dwSize = 8;
+    dw = 0;
+    status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessLdtInformation, buf, 24, &dw);
+    ok(status == STATUS_SUCCESS, "Wrong status %x\n", status);
+    ok(dw == 8, "Wrong dw value %d\n", dw);
+    ok(pli->dwSize == 0, "Wrong pli->dwSize value %d\n", pli->dwSize);
+
+    pli->dwSelector = PROC_LDT(entry);
+    pli->dwSize = 16;
+    dw = 0;
+    status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessLdtInformation, buf, 24, &dw);
+    ok(status == STATUS_SUCCESS, "Wrong status %x\n", status);
+    ok(dw == 8, "Wrong dw value %d\n", dw);
+    ok(pli->dwSize == 0, "Wrong pli->dwSize value %d\n", pli->dwSize);
+
+    pli->dwSelector = PROC_LDT(entry);
+    pli->dwSize = 0;
+    dw = 0;
+    status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessLdtInformation, buf, 16, &dw);
+    ok(status == STATUS_SUCCESS, "Wrong status %x\n", status);
+    ok(dw == 8, "Wrong dw value %d\n", dw);
+    ok(pli->dwSize == 0, "Wrong pli->dwSize value %d\n", pli->dwSize);
+
+    pli->dwSelector = PROC_LDT(entry);
+    pli->dwSize = 32;
+    dw = 0x4321;
+    status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessLdtInformation, buf, 24, &dw);
+    ok(status == STATUS_INFO_LENGTH_MISMATCH, "Wrong status %x\n", status);
+    ok(dw == 0x4321, "Wrong dw value %d\n", dw);
+    ok(pli->dwSize == 32, "Wrong pli->dwSize value %d\n", pli->dwSize);
+
+
+    pli->dwSelector = PROC_LDT(8192);
+    pli->dwSize = 8;
+    dw = 0;
+    status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessLdtInformation, buf, 16, &dw);
+    ok(status == STATUS_SUCCESS, "Wrong status %x\n", status);
+    ok(dw == 8, "Wrong dw value %d\n", dw);
+    ok(pli->dwSize == 0, "Wrong pli->dwSize value %d\n", pli->dwSize);
+}
+#endif /* __i386__ */
+
+START_TEST(selector)
+{
+#ifdef __i386__
+    HANDLE      h;
+    unsigned    entry;
+
+    h = LoadLibrary("ntdll.dll");
+
+    if (!h) return;
+#define X(f) p##f = (void*)GetProcAddress(h, #f); if (!p##f) {printf("Cannot load " #f "\n"); return;}
+    X(NtQueryInformationProcess);
+#undef X
+    /* first, find an unused selector */
+    entry = find_unused_ldt_entry();
+    if (entry >= 8192) return;
+
+    test_fail_process(entry);
+#endif /* __i386__ */
+}
diff --git a/include/winternl.h b/include/winternl.h
index 304f5af..4373ffd 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -976,6 +976,12 @@ typedef struct _PROCESS_PRIORITY_CLASS {
     UCHAR       PriorityClass;
 } PROCESS_PRIORITY_CLASS, *PPROCESS_PRIORITY_CLASS;
 
+typedef struct _PROCESS_LDT_INFORMATION {
+    DWORD       dwSelector;
+    DWORD       dwSize;         /* number of bytes for ldt[] array */
+    LDT_ENTRY   ldt[1];         /* in fact, as many as dwNumber */
+} PROCESS_LDT_INFORMATION;
+
 typedef struct _RTL_HEAP_DEFINITION {
     ULONG Length; /* = sizeof(RTL_HEAP_DEFINITION) */
 



More information about the wine-patches mailing list