diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index 5e6451d3..846d0523 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -232,7 +232,8 @@ typedef struct UINT32 HasRestorePrivilege:1; /* requestor has TOKEN_HAS_RESTORE_PRIVILEGE */ UINT32 OpenTargetDirectory:1; /* open target dir and report FILE_{EXISTS,DOES_NOT_EXIST} */ UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */ - UINT32 ReservedFlags:26; + UINT32 HasTrailingBackslash:1; /* FileName had trailing backslash */ + UINT32 ReservedFlags:25; UINT16 NamedStream; /* request targets named stream; colon offset in FileName */ } Create; struct diff --git a/src/dll/fsop.c b/src/dll/fsop.c index c93e6cfb..30ab7138 100644 --- a/src/dll/fsop.c +++ b/src/dll/fsop.c @@ -189,7 +189,10 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem, ParentDesiredAccess = FILE_ADD_SUBDIRECTORY; else ParentDesiredAccess = FILE_ADD_FILE; - if ((Request->Req.Create.FileAttributes & FILE_ATTRIBUTE_READONLY) && + if (Request->Req.Create.HasTrailingBackslash && + !(Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE)) + Result = STATUS_OBJECT_NAME_INVALID; + else if ((Request->Req.Create.FileAttributes & FILE_ATTRIBUTE_READONLY) && (Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE)) Result = STATUS_CANNOT_DELETE; else @@ -209,11 +212,14 @@ NTSTATUS FspFileSystemCreateCheck(FSP_FILE_SYSTEM *FileSystem, { *PSecurityDescriptor = 0; - Result = FspAccessCheckEx(FileSystem, Request, TRUE, AllowTraverseCheck, - Request->Req.Create.DesiredAccess | - FILE_WRITE_DATA | - ((Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE) ? DELETE : 0), - &GrantedAccess, 0); + if (Request->Req.Create.HasTrailingBackslash) + Result = STATUS_OBJECT_NAME_INVALID; + else + Result = FspAccessCheckEx(FileSystem, Request, TRUE, AllowTraverseCheck, + Request->Req.Create.DesiredAccess | + FILE_WRITE_DATA | + ((Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE) ? DELETE : 0), + &GrantedAccess, 0); if (STATUS_REPARSE == Result) Result = FspFileSystemCallResolveReparsePoints(FileSystem, Request, Response, GrantedAccess); else if (NT_SUCCESS(Result)) diff --git a/src/dll/security.c b/src/dll/security.c index 801ca1d0..c1f278a2 100644 --- a/src/dll/security.c +++ b/src/dll/security.c @@ -191,6 +191,13 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem, if (!NT_SUCCESS(Result) || STATUS_REPARSE == Result) goto exit; + if (!CheckParentOrMain && Request->Req.Create.HasTrailingBackslash && + !(FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + Result = STATUS_OBJECT_NAME_INVALID; + goto exit; + } + if (Request->Req.Create.UserMode && 0 < SecurityDescriptorSize) { if (0 == DesiredAccess) diff --git a/src/sys/create.c b/src/sys/create.c index e5cbe595..4c698c04 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -193,6 +193,7 @@ static NTSTATUS FspFsvolCreateNoLock( BooleanFlagOn(AccessState->Flags, TOKEN_HAS_BACKUP_PRIVILEGE); BOOLEAN HasRestorePrivilege = BooleanFlagOn(AccessState->Flags, TOKEN_HAS_RESTORE_PRIVILEGE); + BOOLEAN HasTrailingBackslash = FALSE; FSP_FILE_NODE *FileNode, *RelatedFileNode; FSP_FILE_DESC *FileDesc; UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 }; @@ -350,12 +351,7 @@ static NTSTATUS FspFsvolCreateNoLock( if (sizeof(WCHAR) * 2/* not empty or root */ <= FileNode->FileName.Length && L'\\' == FileNode->FileName.Buffer[FileNode->FileName.Length / sizeof(WCHAR) - 1]) { - if (!FlagOn(CreateOptions, FILE_DIRECTORY_FILE)) - { - FspFileNodeDereference(FileNode); - return STATUS_OBJECT_NAME_INVALID; - } - + HasTrailingBackslash = TRUE; FileNode->FileName.Length -= sizeof(WCHAR); } @@ -507,6 +503,7 @@ static NTSTATUS FspFsvolCreateNoLock( Request->Req.Create.HasRestorePrivilege = HasRestorePrivilege; Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY); Request->Req.Create.CaseSensitive = CaseSensitive; + Request->Req.Create.HasTrailingBackslash = HasTrailingBackslash; Request->Req.Create.NamedStream = MainFileName.Length; ASSERT(