Giter VIP home page Giter VIP logo

Comments (1)

lundman avatar lundman commented on September 2, 2024

One reply on ntfsd ML points this out:



Is there any way around it? yes, but undocumented and only in case IO_REPARSE_TAG_MOUNT_POINT (but not in case IO_REPARSE_TAG_SYMLINK)

first of all - why this happens ? this is done by NTFS in NtfsFindStartingNode procedure
NTFS uppercase file name during parsing in NtfsFindStartingNode for calculate hash
which than used in NtfsFindPrefixHashEntry. also if PrefixHashEntry found - NTFS revert file name component back,
by call memmove from NtfsFindPrefixHashEntry. so NTFS usual temporary uppercase file name and than revert it to original form
but in case reparse point found - uppercase whole name, but revert back only until reparse name. 
part after reparse file name left in uppercase

in case say \Pool\HelloWorld\XxXx NTFS first convert name to \POOL\HELLOWORLD\XXXX, then revert back to \Pool\HELLOWORLD\XXXX
and return STATUS_REPARSE with IO_REPARSE_TAG_MOUNT_POINT in your case and return 
Tail.Overlay.AuxiliaryBuffer will point to REPARSE_DATA_BUFFER
assume that in REPARSE_DATA_BUFFER will be \Pool -> \MyDevice[\SomePath]
based on this info IopParseDevice transorm file name and new Irp will be sendto \MyDevice device
new file name will be [\SomePath]\HELLOWORLD\XXXX

before win7 (or vista - i not check here) when you view request to [\SomePath]\HELLOWORLD\XXXX
you can not even know - are user direct open 
\MyDevice[\SomePath]\HELLOWORLD\XXXX 
or open via reparse
\??\c:\Pool\HELLOWORLD\XXXX

but after extra create parameter (ECP) appeared, situation is changed.

begin how minimum win7 (i not check on vista) special IopSymlinkECPGuid exist in kernel:

struct __declspec(uuid("73d5118a-88ba-439f-92f4-46d38952d250")) IopSymlinkECPGuid; 

and IopParseDevice attach ECP context of type IopSymlinkECPGuid to Irp after reparse.
so now we can know exactly, are create request was via reparse - need check for IopSymlinkECPGuid

	PECP_LIST EcpList;
	SYMLINK_ECP_CONTEXT* EcpContext;

	if (0 <= FsRtlGetEcpListFromIrp(Irp, &EcpList) && EcpList &&
		0 <= FsRtlFindExtraCreateParameter(EcpList, &__uuidof(IopSymlinkECPGuid), (void**)&EcpContext, 0)){
		
		//...
	}

the context point to next structure:

struct SYMLINK_ECP_CONTEXT
{
	USHORT UnparsedNameLength;
	union {
		USHORT Flags;
		struct {
			USHORT MountPoint : 1;
		};
	};
	USHORT DeviceNameLength;
	USHORT Zero;
	SYMLINK_ECP_CONTEXT* Reparsed;
	UNICODE_STRING Name;
};

the Flags i not exactly research - 
in case IO_REPARSE_TAG_MOUNT_POINT (a00000003) low bit is set to 1, Flags == 3
in case IO_REPARSE_TAG_SYMLINK (a000000c) Flags == 2
also exist special case for undocumented reparse tag 80000019

the Name always containing full path (including device name) to file

Zero always init to 0 (padding field)

DeviceNameLength containing length in bytes of device path in Name

in case IO_REPARSE_TAG_MOUNT_POINT:
Name containing original file path from open request
UnparsedNameLength containing length in bytes of unparsed suffix (path after mount pount component)
Reparsed point to linked SYMLINK_ECP_CONTEXT data with 
  Flags = 0, Name containing reparsed file path
  
in case IO_REPARSE_TAG_SYMLINK the UnparsedNameLength and Reparsed is always 0
and Name containing reparsed file path

so in case IO_REPARSE_TAG_SYMLINK SYMLINK_ECP_CONTEXT containing much less info compare IO_REPARSE_TAG_MOUNT_POINT.

let concrete example:

on \Device\HarddiskVolume2 exist mount point :

\Pool -> \MyDevice[\SomePath]

and somebody try open file \Device\HarddiskVolume2\Pool\HelloWorld\XxXx

----- Irp #1 to \Device\HarddiskVolume2 --------

FileName = \Pool\HelloWorld\XxXx
no IopSymlinkECPGuid context

NTFS transform FileName to \Pool\HELLOWORLD\XXXX and return

(STATUS_REPARSE, IO_REPARSE_TAG_MOUNT_POINT)

----- Irp #2 to \MyDevice --------

FileName = [\SomePath]\HELLOWORLD\XXXX 
exist IopSymlinkECPGuid context (Flags = 3):

Name = \Device\HarddiskVolume2\Pool\HelloWorld\XxXx
DeviceNameLength = size of L"\Device\HarddiskVolume2" (not including terminated 0)
UnparsedNameLength = sizeof of L"\HelloWorld\XxXx" (not including terminated 0)
Reparsed -> IopSymlinkECPGuid context (Flags = 0):
    Name = \MyDevice[\SomePath]\HELLOWORLD\XXXX
    DeviceNameLength = size of L"\MyDevice"
    UnparsedNameLength = 0
    Reparsed = 0
    
so based on this info you can got original unparsed file name (in original case) - \HelloWorld\XxXx
and modify file name from [\SomePath]\HELLOWORLD\XXXX to \HelloWorld\XxXx

BOOLEAN RevertFileName(PIRP Irp)
{
	PECP_LIST EcpList;
	SYMLINK_ECP_CONTEXT* EcpContext;

	if (0 <= FsRtlGetEcpListFromIrp(Irp, &EcpList) && 
		EcpList &&
		0 <= FsRtlFindExtraCreateParameter(EcpList, &__uuidof(IopSymlinkECPGuid), (void**)&EcpContext, 0) &&
		!FsRtlIsEcpFromUserMode(EcpContext) &&
		EcpContext->MountPoint
		)
	{
		if (USHORT UnparsedNameLength = EcpContext->UnparsedNameLength)
		{
			PUNICODE_STRING FileName = &IoGetCurrentIrpStackLocation(Irp)->FileObject->FileName;
			USHORT FileNameLength = FileName->Length;
			USHORT NameLength = EcpContext->Name.Length;

			if (UnparsedNameLength <= NameLength && UnparsedNameLength <= FileNameLength)
			{
				UNICODE_STRING us1 = {
					UnparsedNameLength, 
					UnparsedNameLength,
					(PWSTR)RtlOffsetToPointer(FileName->Buffer, FileNameLength - UnparsedNameLength)
				};

				UNICODE_STRING us2 = {
					UnparsedNameLength, 
					UnparsedNameLength,
					(PWSTR)RtlOffsetToPointer(EcpContext->Name.Buffer, NameLength - UnparsedNameLength)
				};

				if (RtlEqualUnicodeString(&us1, &us2, TRUE))
				{
					memcpy(us1.Buffer, us2.Buffer, UnparsedNameLength);

					return TRUE;
				}
			}
		}
	}

	return FALSE;
}

some logs:
https://i.imgur.com/fUUFRWM.png https://pastebin.com/nRpZrZtJ
https://i.imgur.com/W3ywGUw.png https://pastebin.com/kCvzMRyi
https://i.imgur.com/2k0dARs.png https://pastebin.com/geHM893X


from zfsin.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.