mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 17:52:56 +00:00
- Implement canonicalizing the service binary path properly, handling all possible cases (instead of a memory-overwriting hack Christoph noticed yesterday).
svn path=/trunk/; revision=31768
This commit is contained in:
parent
9f1182353d
commit
c325864075
1 changed files with 379 additions and 17 deletions
|
@ -995,6 +995,380 @@ done:
|
||||||
return dwError;
|
return dwError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create a path suitable for the bootloader out of the full path */
|
||||||
|
DWORD
|
||||||
|
ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
|
||||||
|
{
|
||||||
|
DWORD ServiceNameLen, BufferSize, ExpandedLen;
|
||||||
|
WCHAR Dest;
|
||||||
|
WCHAR *Expanded;
|
||||||
|
UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
NTSTATUS Status;
|
||||||
|
HANDLE SymbolicLinkHandle;
|
||||||
|
|
||||||
|
DPRINT("ScmConvertToBootPathName %S\n", CanonName);
|
||||||
|
|
||||||
|
ServiceNameLen = wcslen(CanonName);
|
||||||
|
/* First check, if it's already good */
|
||||||
|
if (ServiceNameLen > 12 &&
|
||||||
|
!wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
|
||||||
|
{
|
||||||
|
*RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
|
||||||
|
|
||||||
|
if (*RelativeName == NULL)
|
||||||
|
{
|
||||||
|
DPRINT1("Error allocating memory for boot driver name!\n");
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy it */
|
||||||
|
wcscpy(*RelativeName, CanonName);
|
||||||
|
|
||||||
|
DPRINT1("Bootdriver name %S\n", *RelativeName);
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If it has %SystemRoot% prefix, substitute it to \System*/
|
||||||
|
if (ServiceNameLen > 13 &&
|
||||||
|
!wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
|
||||||
|
{
|
||||||
|
/* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
|
||||||
|
*RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR));
|
||||||
|
|
||||||
|
if (*RelativeName == NULL)
|
||||||
|
{
|
||||||
|
DPRINT1("Error allocating memory for boot driver name!\n");
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy it */
|
||||||
|
wcscpy(*RelativeName, L"\\SystemRoot\\");
|
||||||
|
wcscat(*RelativeName, CanonName + 13);
|
||||||
|
|
||||||
|
DPRINT1("Bootdriver name %S\n", *RelativeName);
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get buffer size needed for expanding env strings */
|
||||||
|
BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
|
||||||
|
|
||||||
|
if (BufferSize <= 1)
|
||||||
|
{
|
||||||
|
DPRINT1("Error during a call to ExpandEnvironmentStringsW()\n");
|
||||||
|
return ERROR_INVALID_ENVIRONMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate memory, since the size is known now */
|
||||||
|
Expanded = LocalAlloc(LMEM_ZEROINIT, BufferSize * sizeof(WCHAR) + sizeof(WCHAR));
|
||||||
|
if (!Expanded)
|
||||||
|
{
|
||||||
|
DPRINT1("Error allocating memory for boot driver name!\n");
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expand it */
|
||||||
|
if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
|
||||||
|
BufferSize)
|
||||||
|
{
|
||||||
|
DPRINT1("Error during a call to ExpandEnvironmentStringsW()\n");
|
||||||
|
LocalFree(Expanded);
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert to NY-style path */
|
||||||
|
if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
|
||||||
|
{
|
||||||
|
DPRINT1("Error during a call to RtlDosPathNameToNtPathName_U()\n");
|
||||||
|
return ERROR_INVALID_ENVIRONMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT("Converted to NT-style %wZ\n", &NtPathName);
|
||||||
|
|
||||||
|
/* No need to keep the dos-path anymore */
|
||||||
|
LocalFree(Expanded);
|
||||||
|
|
||||||
|
/* Copy it to the allocated place */
|
||||||
|
Expanded = LocalAlloc(LMEM_ZEROINIT, NtPathName.Length + sizeof(WCHAR));
|
||||||
|
if (!Expanded)
|
||||||
|
{
|
||||||
|
DPRINT1("Error allocating memory for boot driver name!\n");
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandedLen = NtPathName.Length / sizeof(WCHAR);
|
||||||
|
wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
|
||||||
|
Expanded[ExpandedLen] = 0;
|
||||||
|
|
||||||
|
if (ServiceNameLen > ExpandedLen &&
|
||||||
|
!wcsnicmp(Expanded, CanonName, ExpandedLen))
|
||||||
|
{
|
||||||
|
/* Only \SystemRoot\ is missing */
|
||||||
|
*RelativeName = LocalAlloc(LMEM_ZEROINIT,
|
||||||
|
(ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
|
||||||
|
|
||||||
|
if (*RelativeName == NULL)
|
||||||
|
{
|
||||||
|
DPRINT1("Error allocating memory for boot driver name!\n");
|
||||||
|
LocalFree(Expanded);
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
wcscpy(*RelativeName, L"\\SystemRoot\\");
|
||||||
|
wcscat(*RelativeName, CanonName + ExpandedLen);
|
||||||
|
|
||||||
|
RtlFreeUnicodeString(&NtPathName);
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The most complex case starts here */
|
||||||
|
RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&SystemRoot,
|
||||||
|
OBJ_CASE_INSENSITIVE,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Open this symlink */
|
||||||
|
Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
LinkTarget.Length = 0;
|
||||||
|
LinkTarget.MaximumLength = 0;
|
||||||
|
|
||||||
|
DPRINT("Opened symbolic link object\n");
|
||||||
|
|
||||||
|
Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
|
||||||
|
if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
|
||||||
|
{
|
||||||
|
/* Check if required buffer size is sane */
|
||||||
|
if (BufferSize > 0xFFFD)
|
||||||
|
{
|
||||||
|
DPRINT1("Too large buffer required\n");
|
||||||
|
*RelativeName = 0;
|
||||||
|
|
||||||
|
if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
|
||||||
|
LocalFree(Expanded);
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alloc the string */
|
||||||
|
LinkTarget.Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize + sizeof(WCHAR));
|
||||||
|
if (!LinkTarget.Buffer)
|
||||||
|
{
|
||||||
|
DPRINT1("Unable to alloc buffer\n");
|
||||||
|
if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
|
||||||
|
LocalFree(Expanded);
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do a real query now */
|
||||||
|
LinkTarget.Length = BufferSize;
|
||||||
|
LinkTarget.MaximumLength = LinkTarget.Length + sizeof(WCHAR);
|
||||||
|
|
||||||
|
Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT("LinkTarget: %wZ\n", &LinkTarget);
|
||||||
|
|
||||||
|
ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
|
||||||
|
if ((ServiceNameLen > ExpandedLen) &&
|
||||||
|
!wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
|
||||||
|
{
|
||||||
|
*RelativeName = LocalAlloc(LMEM_ZEROINIT,
|
||||||
|
(ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
|
||||||
|
|
||||||
|
if (*RelativeName == NULL)
|
||||||
|
{
|
||||||
|
DPRINT1("Unable to alloc buffer\n");
|
||||||
|
if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
|
||||||
|
LocalFree(Expanded);
|
||||||
|
RtlFreeUnicodeString(&NtPathName);
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy it over, substituting the first part
|
||||||
|
with SystemRoot */
|
||||||
|
wcscpy(*RelativeName, L"\\SystemRoot\\");
|
||||||
|
wcscat(*RelativeName, CanonName+ExpandedLen+1);
|
||||||
|
|
||||||
|
/* Cleanup */
|
||||||
|
if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
|
||||||
|
LocalFree(Expanded);
|
||||||
|
RtlFreeUnicodeString(&NtPathName);
|
||||||
|
|
||||||
|
/* Return success */
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
|
||||||
|
LocalFree(Expanded);
|
||||||
|
RtlFreeUnicodeString(&NtPathName);
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DPRINT1("Error, Status = %08X\n", Status);
|
||||||
|
if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
|
||||||
|
LocalFree(Expanded);
|
||||||
|
RtlFreeUnicodeString(&NtPathName);
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DPRINT1("Error, Status = %08X\n", Status);
|
||||||
|
if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
|
||||||
|
LocalFree(Expanded);
|
||||||
|
RtlFreeUnicodeString(&NtPathName);
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DPRINT1("Error, Status = %08X\n", Status);
|
||||||
|
LocalFree(Expanded);
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Failure */
|
||||||
|
*RelativeName = NULL;
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
ScmCanonDriverImagePath(DWORD dwStartType,
|
||||||
|
wchar_t *lpServiceName,
|
||||||
|
wchar_t **lpCanonName)
|
||||||
|
{
|
||||||
|
DWORD ServiceNameLen, Result;
|
||||||
|
UNICODE_STRING NtServiceName;
|
||||||
|
WCHAR *RelativeName;
|
||||||
|
WCHAR *SourceName = lpServiceName;
|
||||||
|
|
||||||
|
/* Calculate the length of the service's name */
|
||||||
|
ServiceNameLen = wcslen(lpServiceName);
|
||||||
|
|
||||||
|
/* 12 is wcslen(L"\\SystemRoot\\") */
|
||||||
|
if (ServiceNameLen > 12 &&
|
||||||
|
!wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
|
||||||
|
{
|
||||||
|
/* SystemRoot prefix is already included */
|
||||||
|
|
||||||
|
*lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
|
||||||
|
|
||||||
|
if (*lpCanonName == NULL)
|
||||||
|
{
|
||||||
|
DPRINT1("Error allocating memory for canonized service name!\n");
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If it's a boot-time driver, it must be systemroot relative */
|
||||||
|
if (dwStartType == SERVICE_BOOT_START)
|
||||||
|
SourceName += 12;
|
||||||
|
|
||||||
|
/* Copy it */
|
||||||
|
wcscpy(*lpCanonName, SourceName);
|
||||||
|
|
||||||
|
DPRINT("Canonicalized name %S\n", *lpCanonName);
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if it has %SystemRoot% (len=13) */
|
||||||
|
if (ServiceNameLen > 13 &&
|
||||||
|
!wcsnicmp(L"%SystemRoot%\\", lpServiceName, 13))
|
||||||
|
{
|
||||||
|
/* Substitute %SystemRoot% with \\SystemRoot\\ */
|
||||||
|
*lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
|
||||||
|
|
||||||
|
if (*lpCanonName == NULL)
|
||||||
|
{
|
||||||
|
DPRINT1("Error allocating memory for canonized service name!\n");
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If it's a boot-time driver, it must be systemroot relative */
|
||||||
|
if (dwStartType == SERVICE_BOOT_START)
|
||||||
|
wcscpy(*lpCanonName, L"\\SystemRoot\\");
|
||||||
|
|
||||||
|
wcscat(*lpCanonName, lpServiceName);
|
||||||
|
|
||||||
|
DPRINT("Canonicalized name %S\n", *lpCanonName);
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if it's a relative path name */
|
||||||
|
if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
|
||||||
|
{
|
||||||
|
*lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
|
||||||
|
|
||||||
|
if (*lpCanonName == NULL)
|
||||||
|
{
|
||||||
|
DPRINT1("Error allocating memory for canonized service name!\n");
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Just copy it over without changing */
|
||||||
|
wcscpy(*lpCanonName, lpServiceName);
|
||||||
|
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* It seems to be a DOS path, convert it */
|
||||||
|
if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
|
||||||
|
{
|
||||||
|
DPRINT1("RtlDosPathNameToNtPathName_U() failed!\n");
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
*lpCanonName = LocalAlloc(LMEM_ZEROINIT, NtServiceName.Length + sizeof(WCHAR));
|
||||||
|
|
||||||
|
if (*lpCanonName == NULL)
|
||||||
|
{
|
||||||
|
DPRINT1("Error allocating memory for canonized service name!\n");
|
||||||
|
RtlFreeUnicodeString(&NtServiceName);
|
||||||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the string */
|
||||||
|
wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
|
||||||
|
|
||||||
|
/* The unicode string is not needed anymore */
|
||||||
|
RtlFreeUnicodeString(&NtServiceName);
|
||||||
|
|
||||||
|
if (dwStartType != SERVICE_BOOT_START)
|
||||||
|
{
|
||||||
|
DPRINT("Canonicalized name %S\n", *lpCanonName);
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The service is boot-started, so must be relative */
|
||||||
|
Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
|
||||||
|
if (Result)
|
||||||
|
{
|
||||||
|
/* There is a problem, free name and return */
|
||||||
|
LocalFree(*lpCanonName);
|
||||||
|
DPRINT1("Error converting named!\n");
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(RelativeName);
|
||||||
|
|
||||||
|
/* Copy that string */
|
||||||
|
wcscpy(*lpCanonName, RelativeName + 12);
|
||||||
|
|
||||||
|
/* Free the allocated buffer */
|
||||||
|
LocalFree(RelativeName);
|
||||||
|
|
||||||
|
DPRINT("Canonicalized name %S\n", *lpCanonName);
|
||||||
|
|
||||||
|
/* Success */
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function 12 */
|
/* Function 12 */
|
||||||
DWORD
|
DWORD
|
||||||
|
@ -1058,24 +1432,12 @@ ScmrCreateServiceW(handle_t BindingHandle,
|
||||||
|
|
||||||
if (dwServiceType & SERVICE_DRIVER)
|
if (dwServiceType & SERVICE_DRIVER)
|
||||||
{
|
{
|
||||||
lpImagePath = (WCHAR*) HeapAlloc(GetProcessHeap(),
|
dwError = ScmCanonDriverImagePath(dwStartType,
|
||||||
HEAP_ZERO_MEMORY,
|
lpBinaryPathName,
|
||||||
(wcslen(lpBinaryPathName) + 5) * sizeof(WCHAR));
|
&lpImagePath);
|
||||||
if (lpImagePath == NULL)
|
|
||||||
{
|
|
||||||
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lpBinaryPathName[1] == L':')
|
if (dwError != ERROR_SUCCESS)
|
||||||
{
|
goto done;
|
||||||
wcscpy(lpImagePath, L"\\??\\");
|
|
||||||
wcscat(lpImagePath, lpBinaryPathName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wcscpy(lpImagePath, lpBinaryPathName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a new service entry */
|
/* Allocate a new service entry */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue