sys,dll: symbolic link testing

This commit is contained in:
Bill Zissimopoulos 2016-09-11 17:04:01 -07:00
parent 997476f015
commit bd0acf2289
4 changed files with 98 additions and 71 deletions

View File

@ -1056,87 +1056,87 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
FSP_FILE_SYSTEM *FileSystem, PVOID Context, FSP_FILE_SYSTEM *FileSystem, PVOID Context,
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize), PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize),
PVOID Context, PVOID Context,
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent, PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent0,
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize) PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize)
{ {
WCHAR c, *p, *lastp; PWSTR TargetPath, RemainderPath, LastPathComponent, NewRemainderPath, ReparseTargetPath;
PWSTR TargetPath, TargetPathEnd, ReparseTargetPath; WCHAR RemainderChar;
union union
{ {
REPARSE_DATA_BUFFER V; REPARSE_DATA_BUFFER V;
UINT8 B[FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX]; UINT8 B[FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX];
} ReparseDataBuf; } ReparseDataBuf;
PREPARSE_DATA_BUFFER ReparseData = &ReparseDataBuf.V; PREPARSE_DATA_BUFFER ReparseData = &ReparseDataBuf.V;
SIZE_T Size, ReparseTargetPathLength, MaxTries = 32; SIZE_T ReparseDataSize, RemainderPathSize, ReparseTargetPathLength;
BOOLEAN ResolveLastPathComponent;
ULONG MaxTries = 32;
NTSTATUS Result; NTSTATUS Result;
TargetPath = Buffer; TargetPath = Buffer;
TargetPathEnd = TargetPath + *PSize / sizeof(WCHAR); RemainderPathSize = (lstrlenW(FileName) + 1) * sizeof(WCHAR);
Size = (lstrlenW(FileName) + 1) * sizeof(WCHAR); if (RemainderPathSize > *PSize)
if (Size > *PSize)
return STATUS_REPARSE_POINT_NOT_RESOLVED; return STATUS_REPARSE_POINT_NOT_RESOLVED;
memcpy(TargetPath, FileName, Size); memcpy(TargetPath, FileName, RemainderPathSize);
p = TargetPath + ReparsePointIndex; ResolveLastPathComponent = ResolveLastPathComponent0;
c = *p; RemainderPath = TargetPath + ReparsePointIndex;
for (;;) for (;;)
{ {
while (L'\\' == *p) while (L'\\' == *RemainderPath)
p++; RemainderPath++;
lastp = p; LastPathComponent = RemainderPath;
while (L'\\' != *p) while (L'\\' != *RemainderPath)
{ {
if (L'\0' == *p) if (L'\0' == *RemainderPath)
{ {
if (!ResolveLastPathComponent) if (!ResolveLastPathComponent)
goto exit; goto exit;
ResolveLastPathComponent = FALSE; ResolveLastPathComponent = FALSE;
break; break;
} }
p++; RemainderPath++;
} }
/* handle dot and dotdot! */ /* handle dot and dotdot! */
if (L'.' == lastp[0]) if (L'.' == LastPathComponent[0])
{ {
if (p == lastp + 1) if (RemainderPath == LastPathComponent + 1)
/* dot */ /* dot */
continue; continue;
if (L'.' == lastp[1] && p == lastp + 2) if (L'.' == LastPathComponent[1] && RemainderPath == LastPathComponent + 2)
{ {
/* dotdot */ /* dotdot */
p = lastp; RemainderPath = LastPathComponent;
while (TargetPath < p) while (TargetPath < RemainderPath)
{ {
p--; RemainderPath--;
if (L'\\' != *p) if (L'\\' != *RemainderPath)
break; break;
} }
while (TargetPath < p) while (TargetPath < RemainderPath)
{ {
p--; RemainderPath--;
if (L'\\' == *p) if (L'\\' == *RemainderPath)
break; break;
} }
continue; continue;
} }
} }
c = *p; RemainderChar = *RemainderPath; *RemainderPath = L'\0';
*p = L'\0'; ReparseDataSize = sizeof ReparseDataBuf;
Size = sizeof ReparseDataBuf; Result = GetReparsePointByName(FileSystem, Context, TargetPath, '\0' != RemainderChar,
Result = GetReparsePointByName(FileSystem, Context, TargetPath, '\0' != c, ReparseData, &ReparseDataSize);
ReparseData, &Size); *RemainderPath = RemainderChar;
*p = c;
if (STATUS_NOT_A_REPARSE_POINT == Result) if (STATUS_NOT_A_REPARSE_POINT == Result)
/* it was not a reparse point; continue */ /* it was not a reparse point; continue */
continue; continue;
else if (!NT_SUCCESS(Result)) else if (!NT_SUCCESS(Result))
{ {
if (STATUS_OBJECT_NAME_NOT_FOUND != Result || '\0' != c) if (STATUS_OBJECT_NAME_NOT_FOUND != Result || '\0' != RemainderChar)
Result = STATUS_OBJECT_PATH_NOT_FOUND; Result = STATUS_OBJECT_PATH_NOT_FOUND;
return Result; return Result;
} }
@ -1162,30 +1162,38 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
return STATUS_REPARSE_POINT_NOT_RESOLVED; return STATUS_REPARSE_POINT_NOT_RESOLVED;
/* if device relative symlink replace whole path; else replace last path component */ /* if device relative symlink replace whole path; else replace last path component */
p = ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0] ? NewRemainderPath = ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0] ?
TargetPath : lastp; TargetPath : LastPathComponent;
if (ReparseTargetPathLength + sizeof(WCHAR) > (TargetPathEnd - p) * sizeof(WCHAR)) RemainderPathSize = (lstrlenW(RemainderPath) + 1) * sizeof(WCHAR);
if (NewRemainderPath + (ReparseTargetPathLength + RemainderPathSize) / sizeof(WCHAR) >
TargetPath + *PSize / sizeof(WCHAR))
return STATUS_REPARSE_POINT_NOT_RESOLVED; return STATUS_REPARSE_POINT_NOT_RESOLVED;
memcpy(p, ReparseTargetPath, ReparseTargetPathLength); /* move remainder path to its new position */
p[ReparseTargetPathLength / sizeof(WCHAR)] = L'\0'; memmove(NewRemainderPath + ReparseTargetPathLength, RemainderPath, RemainderPathSize);
/* copy symlink target */
memcpy(NewRemainderPath, ReparseTargetPath, ReparseTargetPathLength);
ResolveLastPathComponent = ResolveLastPathComponent0;
RemainderPath = NewRemainderPath;
} }
exit: exit:
*PSize = (PUINT8)p - (PUINT8)TargetPath; *PSize = (PUINT8)RemainderPath - (PUINT8)TargetPath;
PIoStatus->Status = STATUS_REPARSE; PIoStatus->Status = STATUS_REPARSE;
PIoStatus->Information = 0/*IO_REPARSE*/; PIoStatus->Information = 0/*IO_REPARSE*/;
return STATUS_REPARSE; return STATUS_REPARSE;
reparse_data_exit: reparse_data_exit:
if (Size > *PSize) if (ReparseDataSize > *PSize)
return IO_REPARSE_TAG_SYMLINK != ReparseData->ReparseTag ? return IO_REPARSE_TAG_SYMLINK != ReparseData->ReparseTag ?
STATUS_IO_REPARSE_DATA_INVALID : STATUS_REPARSE_POINT_NOT_RESOLVED; STATUS_IO_REPARSE_DATA_INVALID : STATUS_REPARSE_POINT_NOT_RESOLVED;
*PSize = Size; *PSize = ReparseDataSize;
memcpy(Buffer, ReparseData, Size); memcpy(Buffer, ReparseData, ReparseDataSize);
PIoStatus->Status = STATUS_REPARSE; PIoStatus->Status = STATUS_REPARSE;
PIoStatus->Information = ReparseData->ReparseTag; PIoStatus->Information = ReparseData->ReparseTag;

View File

@ -485,7 +485,7 @@ NTSTATUS FspFsvolCreateComplete(
FSP_FILE_NODE *FileNode = FileDesc->FileNode; FSP_FILE_NODE *FileNode = FileDesc->FileNode;
FSP_FILE_NODE *OpenedFileNode; FSP_FILE_NODE *OpenedFileNode;
PREPARSE_DATA_BUFFER ReparseData; PREPARSE_DATA_BUFFER ReparseData;
UNICODE_STRING ReparseTargetPrefix, ReparseTargetPath; UNICODE_STRING ReparseTargetPrefix0, ReparseTargetPrefix1, ReparseTargetPath;
if (FspFsctlTransactCreateKind == Request->Kind) if (FspFsctlTransactCreateKind == Request->Kind)
{ {
@ -514,14 +514,15 @@ NTSTATUS FspFsvolCreateComplete(
* path. Prefix it with our device name and send it to the IO Manager. * path. Prefix it with our device name and send it to the IO Manager.
* *
* IO_REPARSE_TAG_SYMLINK means that the user-mode file system has returned a full * IO_REPARSE_TAG_SYMLINK means that the user-mode file system has returned a full
* symbolic link reparse buffer. In this case send the target path to the IO Manager, * symbolic link reparse buffer. In this case send the target path to the IO Manager.
* and prefix it with our device name depending on SYMLINK_FLAG_RELATIVE.
*/ */
if (IO_REPARSE == Response->IoStatus.Information) if (IO_REPARSE == Response->IoStatus.Information)
{ {
RtlCopyMemory(&ReparseTargetPrefix, &FsvolDeviceExtension->VolumeName, RtlCopyMemory(&ReparseTargetPrefix0, &FsvolDeviceExtension->VolumeName,
sizeof ReparseTargetPrefix); sizeof ReparseTargetPrefix0);
RtlCopyMemory(&ReparseTargetPrefix1, &FsvolDeviceExtension->VolumePrefix,
sizeof ReparseTargetPrefix1);
ReparseTargetPath.Length = ReparseTargetPath.MaximumLength = ReparseTargetPath.Length = ReparseTargetPath.MaximumLength =
Response->Rsp.Create.Reparse.FileName.Size; Response->Rsp.Create.Reparse.FileName.Size;
@ -529,7 +530,9 @@ NTSTATUS FspFsvolCreateComplete(
(PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.FileName.Offset); (PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.FileName.Offset);
if ((PUINT8)ReparseTargetPath.Buffer + ReparseTargetPath.Length > if ((PUINT8)ReparseTargetPath.Buffer + ReparseTargetPath.Length >
(PUINT8)Response + Response->Size || 0 == ReparseTargetPath.Length) (PUINT8)Response + Response->Size ||
sizeof(WCHAR) > ReparseTargetPath.Length ||
L'\\' != ReparseTargetPath.Buffer[0])
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED); FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
} }
else else
@ -540,18 +543,18 @@ NTSTATUS FspFsvolCreateComplete(
if ((PUINT8)ReparseData + Response->Rsp.Create.Reparse.Data.Size > if ((PUINT8)ReparseData + Response->Rsp.Create.Reparse.Data.Size >
(PUINT8)Response + Response->Size) (PUINT8)Response + Response->Size)
FSP_RETURN(Result = STATUS_IO_REPARSE_DATA_INVALID); FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
Result = FsRtlValidateReparsePointBuffer(Response->Rsp.Create.Reparse.Data.Size, Result = FsRtlValidateReparsePointBuffer(Response->Rsp.Create.Reparse.Data.Size,
ReparseData); ReparseData);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
FSP_RETURN(); FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
if (0 == (ReparseData->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE)) if (FlagOn(ReparseData->SymbolicLinkReparseBuffer.Flags, SYMLINK_FLAG_RELATIVE))
RtlZeroMemory(&ReparseTargetPrefix, sizeof ReparseTargetPrefix); FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
else
RtlCopyMemory(&ReparseTargetPrefix, &FsvolDeviceExtension->VolumeName, RtlZeroMemory(&ReparseTargetPrefix0, sizeof ReparseTargetPrefix0);
sizeof ReparseTargetPrefix); RtlZeroMemory(&ReparseTargetPrefix1, sizeof ReparseTargetPrefix1);
ReparseTargetPath.Buffer = ReparseData->SymbolicLinkReparseBuffer.PathBuffer + ReparseTargetPath.Buffer = ReparseData->SymbolicLinkReparseBuffer.PathBuffer +
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR); ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
@ -559,20 +562,21 @@ NTSTATUS FspFsvolCreateComplete(
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength; ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
} }
if (ReparseTargetPrefix.Length + ReparseTargetPath.Length > if (ReparseTargetPrefix0.Length + ReparseTargetPrefix1.Length + ReparseTargetPath.Length >
FileObject->FileName.MaximumLength) FileObject->FileName.MaximumLength)
{ {
PVOID Buffer = FspAllocExternal( PVOID Buffer = FspAllocExternal(
ReparseTargetPrefix.Length + ReparseTargetPath.Length); ReparseTargetPrefix0.Length + ReparseTargetPrefix1.Length + ReparseTargetPath.Length);
if (0 == Buffer) if (0 == Buffer)
FSP_RETURN(Result = STATUS_INSUFFICIENT_RESOURCES); FSP_RETURN(Result = STATUS_INSUFFICIENT_RESOURCES);
FspFreeExternal(FileObject->FileName.Buffer); FspFreeExternal(FileObject->FileName.Buffer);
FileObject->FileName.MaximumLength = FileObject->FileName.MaximumLength =
ReparseTargetPrefix.Length + ReparseTargetPath.Length; ReparseTargetPrefix0.Length + ReparseTargetPrefix1.Length + ReparseTargetPath.Length;
FileObject->FileName.Buffer = Buffer; FileObject->FileName.Buffer = Buffer;
} }
FileObject->FileName.Length = 0; FileObject->FileName.Length = 0;
RtlAppendUnicodeStringToString(&FileObject->FileName, &ReparseTargetPrefix); RtlAppendUnicodeStringToString(&FileObject->FileName, &ReparseTargetPrefix0);
RtlAppendUnicodeStringToString(&FileObject->FileName, &ReparseTargetPrefix1);
RtlAppendUnicodeStringToString(&FileObject->FileName, &ReparseTargetPath); RtlAppendUnicodeStringToString(&FileObject->FileName, &ReparseTargetPath);
/* /*

View File

@ -145,7 +145,7 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
ReparseTargetPathLength = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength; ReparseTargetPathLength = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
/* is this an absolute path? determine if target resides on same device as link */ /* is this an absolute path? determine if target resides on same device as link */
if (0 == (ReparseData->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) && if (!FlagOn(ReparseData->SymbolicLinkReparseBuffer.Flags, SYMLINK_FLAG_RELATIVE) &&
ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0]) ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0])
{ {
UNICODE_STRING TargetObjectName; UNICODE_STRING TargetObjectName;

View File

@ -219,23 +219,15 @@ void reparse_nfs_test(void)
} }
} }
static void reparse_symlink_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout) static void reparse_symlink_dotest0(ULONG Flags, PWSTR Prefix,
PWSTR FilePath, PWSTR LinkPath, PWSTR TargetPath)
{ {
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
HANDLE Handle; HANDLE Handle;
BOOL Success; BOOL Success;
WCHAR FilePath[MAX_PATH], LinkPath[MAX_PATH];
PUINT8 NameInfoBuf[sizeof(FILE_NAME_INFO) + MAX_PATH]; PUINT8 NameInfoBuf[sizeof(FILE_NAME_INFO) + MAX_PATH];
PFILE_NAME_INFO PNameInfo = (PVOID)NameInfoBuf; PFILE_NAME_INFO PNameInfo = (PVOID)NameInfoBuf;
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\file0", Success = CreateSymbolicLinkW(LinkPath, TargetPath, 0);
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(LinkPath, sizeof LinkPath, L"%s%s\\link0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = CreateSymbolicLinkW(LinkPath, FilePath, 0);
if (Success) if (Success)
{ {
Handle = CreateFileW(FilePath, Handle = CreateFileW(FilePath,
@ -277,6 +269,29 @@ static void reparse_symlink_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTime
ASSERT(ERROR_PRIVILEGE_NOT_HELD == GetLastError()); ASSERT(ERROR_PRIVILEGE_NOT_HELD == GetLastError());
FspDebugLog(__FUNCTION__ ": need SE_CREATE_SYMBOLIC_LINK_PRIVILEGE\n"); FspDebugLog(__FUNCTION__ ": need SE_CREATE_SYMBOLIC_LINK_PRIVILEGE\n");
} }
}
static void reparse_symlink_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
WCHAR FilePath[MAX_PATH], LinkPath[MAX_PATH], TargetPath[MAX_PATH];
PUINT8 NameInfoBuf[sizeof(FILE_NAME_INFO) + MAX_PATH];
PFILE_NAME_INFO PNameInfo = (PVOID)NameInfoBuf;
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\file0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(LinkPath, sizeof LinkPath, L"%s%s\\link0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
reparse_symlink_dotest0(Flags, Prefix, FilePath, LinkPath, FilePath);
StringCbPrintfW(TargetPath, sizeof TargetPath, L"%s\\file0",
-1 == Flags ? Prefix + 6 : L"");
reparse_symlink_dotest0(Flags, Prefix, FilePath, LinkPath, TargetPath);
reparse_symlink_dotest0(Flags, Prefix, FilePath, LinkPath, L"file0");
memfs_stop(memfs); memfs_stop(memfs);
} }