[WIN32K]
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Sat, 22 Dec 2012 17:43:20 +0000 (17:43 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Sat, 22 Dec 2012 17:43:20 +0000 (17:43 +0000)
- Rewrite NtUserGetAtomName, make it return the length in WCHARs instead of bytes, as it is supposed to be. Fix a buffer overrun, when the caller passes a too large UNICODE_STRING buffer. Probe the output buffers before accessing them. Makes sure the target string is always NULL terminated, even if the buffer is too small for the whole name.
- Remove NULL termination code from IntGetAtomName, since that is already done by RtlQueryAtomInAtomTable

svn path=/trunk/; revision=57970

reactos/win32ss/include/ntuser.h
reactos/win32ss/user/ntuser/useratom.c

index 1b1bb3d..77dce0e 100644 (file)
@@ -1893,11 +1893,13 @@ NTAPI
 NtUserGetAsyncKeyState(
   INT Key);
 
-DWORD
-NTAPI
+_Success_(return!=0)
+_At_(pustrName->Buffer, _Out_z_bytecap_post_bytecount_(pustrName->MaximumLength, return*2+2))
+ULONG
+APIENTRY
 NtUserGetAtomName(
-    ATOM nAtom,
-    PUNICODE_STRING pBuffer);
+    _In_ ATOM atom,
+    _Inout_ PUNICODE_STRING pustrName);
 
 UINT
 NTAPI
index 17defa1..f8c845c 100644 (file)
@@ -34,11 +34,11 @@ IntAddAtom(LPWSTR AtomName)
 }
 
 ULONG FASTCALL
-IntGetAtomName(RTL_ATOM nAtom, LPWSTR lpBuffer, ULONG nSize)
+IntGetAtomName(RTL_ATOM nAtom, LPWSTR lpBuffer, ULONG cjBufSize)
 {
    NTSTATUS Status = STATUS_SUCCESS;
    PTHREADINFO pti;
-   ULONG Size = nSize;
+   ULONG Size = cjBufSize;
 
    pti = PsGetCurrentThreadWin32Thread();
    if (pti->rpdesk == NULL)
@@ -49,13 +49,12 @@ IntGetAtomName(RTL_ATOM nAtom, LPWSTR lpBuffer, ULONG nSize)
 
    Status = RtlQueryAtomInAtomTable(gAtomTable, nAtom, NULL, NULL, lpBuffer, &Size);
 
-   if (Size < nSize)
-      *(lpBuffer + Size/sizeof(WCHAR)) = 0;
    if (!NT_SUCCESS(Status))
    {
       SetLastNtError(Status);
       return 0;
    }
+
    return Size;
 }
 
@@ -78,30 +77,67 @@ IntAddGlobalAtom(LPWSTR lpBuffer, BOOL PinAtom)
    return Atom;
 }
 
-DWORD
+/*!
+ * \brief Returns the name of an atom.
+ *
+ * \param atom - The atom to be queried.
+ * \param pustrName - Pointer to an initialized UNICODE_STRING that receives
+ *                    the name of the atom. The function does not update the
+                      Length member. The string is always NULL-terminated.
+ *
+ * \return The length of the name in characters, or 0 if the function fails.
+ *
+ * \note The function does not aquire any global lock, since synchronisation is
+ *       handled by the RtlAtom function.
+ */
+_Success_(return!=0)
+_At_(pustrName->Buffer, _Out_z_bytecap_post_bytecount_(pustrName->MaximumLength, return*2+2))
+ULONG
 APIENTRY
 NtUserGetAtomName(
-    ATOM nAtom,
-    PUNICODE_STRING pBuffer)
+    _In_ ATOM atom,
+    _Inout_ PUNICODE_STRING pustrName)
 {
-   DWORD Ret;
-   WCHAR Buffer[256];
-   UNICODE_STRING CapturedName = {0};
-   UserEnterShared();
-   CapturedName.Buffer = (LPWSTR)&Buffer;
-   CapturedName.MaximumLength = sizeof(Buffer);
-   Ret = IntGetAtomName((RTL_ATOM)nAtom, CapturedName.Buffer, (ULONG)CapturedName.Length);
-   _SEH2_TRY
-   {
-      RtlCopyMemory(pBuffer->Buffer, &Buffer, pBuffer->MaximumLength);
-   }
-   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-   {
-      Ret = 0;
-   }
-   _SEH2_END
-   UserLeave();
-   return Ret;
+    WCHAR awcBuffer[256];
+    ULONG cjLength;
+
+    /* Retrieve the atom name into a local buffer (max length is 255 chars) */
+    cjLength = IntGetAtomName((RTL_ATOM)atom, awcBuffer, sizeof(awcBuffer));
+    if (cjLength != 0)
+    {
+        _SEH2_TRY
+        {
+            /* Probe the unicode string and the buffer */
+            ProbeForRead(pustrName, sizeof(*pustrName), 1);
+            ProbeForWrite(pustrName->Buffer, pustrName->MaximumLength, 1);
+
+            /* Check if we have enough space to write the NULL termination */
+            if (pustrName->MaximumLength >= sizeof(UNICODE_NULL))
+            {
+                /* Limit the length to the buffer size */
+                cjLength = min(pustrName->MaximumLength - sizeof(UNICODE_NULL),
+                               cjLength);
+
+                /* Copy the string and NULL terminate it */
+                RtlCopyMemory(pustrName->Buffer, awcBuffer, cjLength);
+                pustrName->Buffer[cjLength / sizeof(WCHAR)] = L'\0';
+            }
+            else
+            {
+                cjLength = 0;
+            }
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* On exception, set last error and fail */
+            SetLastNtError(_SEH2_GetExceptionCode());
+            cjLength = 0;
+        }
+        _SEH2_END
+    }
+
+    /* Return the length in characters */
+    return cjLength / sizeof(WCHAR);
 }
 
 /* EOF */