ZwSetInformationFile BSOD error when trying to rename a file.

Hello there,

Hope someone can figure out what I missed on the following code I created to rename a file.
The status of ZwSetInformationFile returns Success but after reaching at the end of my routine, bluescreen occurs and I can’t figure out what I missed.
Here’s the code I created to rename a file:

NTSTATUS
RenameFile(
IN UNICODE_STRING OldFileName,
IN UNICODE_STRING NewFileName
)
{
NTSTATUS Status = STATUS_SUCCESS;
HANDLE FileHandle;
HANDLE RootDirHandle;
OBJECT_ATTRIBUTES FileObjectAttributes;
OBJECT_ATTRIBUTES RootDirObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING uniFullFileName;
UNICODE_STRING uniFullNewFileName;
UNICODE_STRING uniDiskDrive;
FILE_RENAME_INFORMATION frInfo;

RtlInitUnicodeString( &uniDiskDrive, L"\??\C:\" );

uniFullFileName.Length = ( wcslen(uniDiskDrive.Buffer) + wcslen(OldFileName.Buffer) ) * sizeof(WCHAR);
uniFullFileName.MaximumLength = uniFullFileName.Length + 2;
uniFullFileName.Buffer = ExAllocatePoolWithTag(
NonPagedPool,
uniFullFileName.MaximumLength,
TAG_GENERAL
);

if( uniFullFileName.Buffer == NULL ) {
KdPrint( (“%s: Can’t allocate memory for a buffer.\n”, NAMEBASE));
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Exit;
}

RtlCopyUnicodeString( &uniFullFileName, &uniDiskDrive );

Status = RtlAppendUnicodeStringToString(
&uniFullFileName,
&OldFileName
);

if( !NT_SUCCESS( Status ) ) {
KdPrint( (“%s: RtlAppendUnicodeStringToString Fails.\n”, NAMEBASE) );
goto Exit;
} //endif

InitializeObjectAttributes(
&FileObjectAttributes,
&uniFullFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);

Status = ZwCreateFile(
&FileHandle, // returned file handle
FILE_ANY_ACCESS, // desired access
&FileObjectAttributes, // ptr to object attributes
&IoStatusBlock, // ptr to I/O status block
NULL, // allocation size
FILE_ATTRIBUTE_NORMAL, // file attributes
0, // share access
FILE_OPEN, // create disposition
FILE_SYNCHRONOUS_IO_NONALERT, // create options
NULL, // ptr to extended attributes
0);

if( !NT_SUCCESS( Status ) ) {
KdPrint( (“%s: ZwCreateFile Fails on RenameFile.\n”, NAMEBASE) );
KdPrint( (“%s: Possibly the file doesn’t exist.\n”, NAMEBASE) );
goto Exit;
} //endif

//
// Open the Directory
//

InitializeObjectAttributes(
&RootDirObjectAttributes,
&uniRamdiskDrive,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);

Status = ZwCreateFile(
&RootDirHandle, // returned file handle
FILE_ANY_ACCESS, // desired access
&RootDirObjectAttributes, // ptr to object attributes
&IoStatusBlock, // ptr to I/O status block
NULL, // allocation size
FILE_ATTRIBUTE_NORMAL, // file attributes
0, // share access
FILE_OPEN, // create disposition
FILE_SYNCHRONOUS_IO_NONALERT, // create options
NULL, // ptr to extended attributes
0);

if( !NT_SUCCESS( Status ) ) {
KdPrint( (“%s: ZwCreateFile Fails on RenameFile.\n”, NAMEBASE) );
KdPrint( (“%s: Possibly the file doesn’t exist.\n”, NAMEBASE) );
goto Exit;
} //endif

uniFullNewFileName.Length = ( wcslen(uniRamdiskDrive.Buffer) + wcslen(NewFileName.Buffer) ) * sizeof(WCHAR);
uniFullNewFileName.MaximumLength = uniFullNewFileName.Length + 2;
uniFullNewFileName.Buffer = ExAllocatePoolWithTag(
NonPagedPool,
uniFullNewFileName.MaximumLength,
TAG_GENERAL
);

frInfo.ReplaceIfExists = FALSE;
frInfo.RootDirectory = RootDirHandle;
frInfo.FileNameLength = NewFileName.Length;
//frInfo.FileName = *NewFileName.Buffer;
memcpy( frInfo.FileName, NewFileName.Buffer, frInfo.FileNameLength + 2 );

Status = ZwSetInformationFile(
FileHandle,
&IoStatusBlock,
&frInfo,
sizeof(FILE_RENAME_INFORMATION) + NewFileName.Length + 2,
FileRenameInformation
);

if( !NT_SUCCESS( Status ) ) {
KdPrint( (“%s: ZwSetInformationFile Fails on RamdiskRenameFile.\n”, NAMEBASE) );
goto Exit;
} //endif

Exit:
return Status;
}

I tried setting frInfo.RootDirectory = NULL but same result. Also I did to assign the new filename with the complete path but still my driver causes BSOD error. Hope someone here can figure out what’s wrong with my implementation.

Thanks.

Just how long is frInfo.FileName?

wrote in message news:xxxxx@ntdev…
> Hello there,
>
> Hope someone can figure out what I missed on the following code I created
> to rename a file.
> The status of ZwSetInformationFile returns Success but after reaching at
> the end of my routine, bluescreen occurs and I can’t figure out what I
> missed.
> Here’s the code I created to rename a file:
>
> NTSTATUS
> RenameFile(
> IN UNICODE_STRING OldFileName,
> IN UNICODE_STRING NewFileName
> )
> {
> NTSTATUS Status = STATUS_SUCCESS;
> HANDLE FileHandle;
> HANDLE RootDirHandle;
> OBJECT_ATTRIBUTES FileObjectAttributes;
> OBJECT_ATTRIBUTES RootDirObjectAttributes;
> IO_STATUS_BLOCK IoStatusBlock;
> UNICODE_STRING uniFullFileName;
> UNICODE_STRING uniFullNewFileName;
> UNICODE_STRING uniDiskDrive;
> FILE_RENAME_INFORMATION frInfo;
>
> RtlInitUnicodeString( &uniDiskDrive, L"\??\C:\" );
>
> uniFullFileName.Length = ( wcslen(uniDiskDrive.Buffer) +
> wcslen(OldFileName.Buffer) ) * sizeof(WCHAR);
> uniFullFileName.MaximumLength = uniFullFileName.Length + 2;
> uniFullFileName.Buffer = ExAllocatePoolWithTag(
> NonPagedPool,
> uniFullFileName.MaximumLength,
> TAG_GENERAL
> );
>
> if( uniFullFileName.Buffer == NULL ) {
> KdPrint( (“%s: Can’t allocate memory for a buffer.\n”, NAMEBASE));
> Status = STATUS_INSUFFICIENT_RESOURCES;
> goto Exit;
> }
>
> RtlCopyUnicodeString( &uniFullFileName, &uniDiskDrive );
>
> Status = RtlAppendUnicodeStringToString(
> &uniFullFileName,
> &OldFileName
> );
>
> if( !NT_SUCCESS( Status ) ) {
> KdPrint( (“%s: RtlAppendUnicodeStringToString Fails.\n”, NAMEBASE) );
> goto Exit;
> } //endif
>
> InitializeObjectAttributes(
> &FileObjectAttributes,
> &uniFullFileName,
> OBJ_CASE_INSENSITIVE,
> NULL,
> NULL
> );
>
> Status = ZwCreateFile(
> &FileHandle, // returned file handle
> FILE_ANY_ACCESS, // desired access
> &FileObjectAttributes, // ptr to object attributes
> &IoStatusBlock, // ptr to I/O status block
> NULL, // allocation size
> FILE_ATTRIBUTE_NORMAL, // file attributes
> 0, // share access
> FILE_OPEN, // create disposition
> FILE_SYNCHRONOUS_IO_NONALERT, // create options
> NULL, // ptr to extended attributes
> 0);
>
> if( !NT_SUCCESS( Status ) ) {
> KdPrint( (“%s: ZwCreateFile Fails on RenameFile.\n”, NAMEBASE) );
> KdPrint( (“%s: Possibly the file doesn’t exist.\n”, NAMEBASE) );
> goto Exit;
> } //endif
>
> //
> // Open the Directory
> //
>
> InitializeObjectAttributes(
> &RootDirObjectAttributes,
> &uniRamdiskDrive,
> OBJ_CASE_INSENSITIVE,
> NULL,
> NULL
> );
>
> Status = ZwCreateFile(
> &RootDirHandle, // returned file handle
> FILE_ANY_ACCESS, // desired access
> &RootDirObjectAttributes, // ptr to object attributes
> &IoStatusBlock, // ptr to I/O status block
> NULL, // allocation size
> FILE_ATTRIBUTE_NORMAL, // file attributes
> 0, // share access
> FILE_OPEN, // create disposition
> FILE_SYNCHRONOUS_IO_NONALERT, // create options
> NULL, // ptr to extended attributes
> 0);
>
> if( !NT_SUCCESS( Status ) ) {
> KdPrint( (“%s: ZwCreateFile Fails on RenameFile.\n”, NAMEBASE) );
> KdPrint( (“%s: Possibly the file doesn’t exist.\n”, NAMEBASE) );
> goto Exit;
> } //endif
>
>
>
> uniFullNewFileName.Length = ( wcslen(uniRamdiskDrive.Buffer) +
> wcslen(NewFileName.Buffer) ) * sizeof(WCHAR);
> uniFullNewFileName.MaximumLength = uniFullNewFileName.Length + 2;
> uniFullNewFileName.Buffer = ExAllocatePoolWithTag(
> NonPagedPool,
> uniFullNewFileName.MaximumLength,
> TAG_GENERAL
> );
>
> frInfo.ReplaceIfExists = FALSE;
> frInfo.RootDirectory = RootDirHandle;
> frInfo.FileNameLength = NewFileName.Length;
> //frInfo.FileName = *NewFileName.Buffer;
> memcpy( frInfo.FileName, NewFileName.Buffer, frInfo.FileNameLength + 2 );
>
> Status = ZwSetInformationFile(
> FileHandle,
> &IoStatusBlock,
> &frInfo,
> sizeof(FILE_RENAME_INFORMATION) + NewFileName.Length + 2,
> FileRenameInformation
> );
>
> if( !NT_SUCCESS( Status ) ) {
> KdPrint( (“%s: ZwSetInformationFile Fails on RamdiskRenameFile.\n”,
> NAMEBASE) );
> goto Exit;
> } //endif
>
> Exit:
> return Status;
> }
>
> I tried setting frInfo.RootDirectory = NULL but same result. Also I did to
> assign the new filename with the complete path but still my driver causes
> BSOD error. Hope someone here can figure out what’s wrong with my
> implementation.
>
> Thanks.
>

I am afraid you are spreading misinformation all over the place. Look below:

//frInfo.FileName = *NewFileName.Buffer;
memcpy( frInfo.FileName, NewFileName.Buffer, frInfo.FileNameLength + 2 );

Assuming that the first line is commented, frInfo.FileName is not initialized, so that you copy memory to the middle of nowhere. BANG!!! If you uncomment it, frInfo.FileName will be set not to NewFileName.Buffer but to *the first element * of the NewFileName.Buffer (i.e. WCHAR, rather than pointer) because of ‘*’ operator, so that, again, memcpy() will cause access violation. No matter how you look at it, you are just bound to bluescreen BEFORE even having called ZwSetInformationFile(). In general, the very first thing people do in your situation is attaching a debugger. However, for this or that reason, you chose to go to the NG, and to make things even worse, did not bother to gather proper information about your error. What kind of reaction would you expect from us???

Anton Bassov

Anton,

He bluescreens after because of overwriting the stack (frInfo.FileName is on
the stack)

Alan
wrote in message news:xxxxx@ntdev…
>
> I am afraid you are spreading misinformation all over the place. Look
> below:
>
> //frInfo.FileName = *NewFileName.Buffer;
> memcpy( frInfo.FileName, NewFileName.Buffer, frInfo.FileNameLength + 2 );
>
> Assuming that the first line is commented, frInfo.FileName is not
> initialized, so that you copy memory to the middle of nowhere. BANG!!! If
> you uncomment it, frInfo.FileName will be set not to NewFileName.Buffer
> but to the first element * of the NewFileName.Buffer (i.e. WCHAR, rather
> than pointer) because of '
’ operator, so that, again, memcpy() will cause
> access violation. No matter how you look at it, you are just bound to
> bluescreen BEFORE even having called ZwSetInformationFile(). In general,
> the very first thing people do in your situation is attaching a debugger.
> However, for this or that reason, you chose to go to the NG, and to make
> things even worse, did not bother to gather proper information about your
> error. What kind of reaction would you expect from us???
>
> Anton Bassov
>

Alan,

He bluescreens after because of overwriting the stack (frInfo.FileName is on the stack)

I am afraid you are too optimistic - in order to reach this stage he has to specify not frInfo.FileName but &frInfo.FileName as a first argument to memcpy()…

Anton Bassov

Anton,

The compiler will do this in C, as it is an array. Not a very big one, mind
you, but an array nonetheless :wink:

Alan
wrote in message news:xxxxx@ntdev…
> Alan,
>
>> He bluescreens after because of overwriting the stack (frInfo.FileName is
>> on the stack)
>
> I am afraid you are too optimistic - in order to reach this stage he has
> to specify not frInfo.FileName but &frInfo.FileName as a first argument to
> memcpy()…
>
> Anton Bassov
>

I am also not sure if the code below will work

memcpy( frInfo.FileName, NewFileName.Buffer, frInfo.FileNameLength + 2 );

I also changed this one into this:

RtlCopyMemory( &frInfo.FileName[0], NewFileName.Buffer, frInfo.FileNameLength + 2 );

But still the error occurs.

frInfo is a FILE_RENAME_INFORMATION structure that contains the ff data:

typedef struct _FILE_RENAME_INFORMATION {
BOOLEAN ReplaceIfExists;
HANDLE RootDirectory;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;

The error is DRIVER_OVERRAN_STACK_BUFFER (f7).

Alan,

The compiler will do this in C, as it is an array.

Shit, I just overlooked the fact that FileName field of FILE_RENAME_INFORMATION is WCHAR FileName[1], rather than a pointer - thank you for pointing it out. In such case his code has no chance to make a successful call to memcpy() at all, no matter what he does - WCHAR FileName[1] means that FileName is a variable-size array of WCHARs that immediately follows FILE_RENAME_INFORMATION, which, in turn, means that the only way to make use of this structure is either to initialize it straight away, or to cast dynamically allocated memory to PFILE_RENAME_INFORMATION. However, he is allocating uninitialized structure like that on the stack, so that he has no chance to do anything with it without BSOD…

Therefore, he still has no chance to call ZwSetInformationFile() becuse hestill bluescreens even before he has a chance to do it…

Anton Bassov

Anton,

I shouldn’t be so terse. I was hoping that my alluding to the size of the
Filename field in the structure would be sufficient for the OP to work it
out, but obviously not.
On the other hand, you’re incorrect to say that the BSOD will occur before
or during the call. It will occur when the overwritten stack is used.
In this case it appears that the other local variables are not being
overwritten, as the call succeeds, so the BSOD will occur at the RET
instruction, popping an invalid IP friom the stack.

alan

wrote in message news:xxxxx@ntdev…
> Alan,
>
>> The compiler will do this in C, as it is an array.
>
> Shit, I just overlooked the fact that FileName field of
> FILE_RENAME_INFORMATION is WCHAR FileName[1], rather than a pointer -
> thank you for pointing it out. In such case his code has no chance to make
> a successful call to memcpy() at all, no matter what he does - WCHAR
> FileName[1] means that FileName is a variable-size array of WCHARs that
> immediately follows FILE_RENAME_INFORMATION, which, in turn, means that
> the only way to make use of this structure is either to initialize it
> straight away, or to cast dynamically allocated memory to
> PFILE_RENAME_INFORMATION. However, he is allocating uninitialized
> structure like that on the stack, so that he has no chance to do anything
> with it without BSOD…
>
> Therefore, he still has no chance to call ZwSetInformationFile() becuse
> hestill bluescreens even before he has a chance to do it…
>
> Anton Bassov
>
>

Allocate FILE_RENAME_INFORMATION dynamically and not on stack.

Also note that + 2 is redundant - UNICODE_STRING does not require zero
termination.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

wrote in message news:xxxxx@ntdev…
> I am also not sure if the code below will work
>
> memcpy( frInfo.FileName, NewFileName.Buffer, frInfo.FileNameLength + 2 );
>
> I also changed this one into this:
>
> RtlCopyMemory( &frInfo.FileName[0], NewFileName.Buffer, frInfo.FileNameLength
+ 2 );
>
> But still the error occurs.
>
> frInfo is a FILE_RENAME_INFORMATION structure that contains the ff data:
>
> typedef struct _FILE_RENAME_INFORMATION {
> BOOLEAN ReplaceIfExists;
> HANDLE RootDirectory;
> ULONG FileNameLength;
> WCHAR FileName[1];
> } FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
>
> The error is DRIVER_OVERRAN_STACK_BUFFER (f7).
>
>

Alan,

On the other hand, you’re incorrect to say that the BSOD will occur before or during the call.

Actually, after having a thought about it, I came to the conclusion that, indeed, it looks that he has a chance to call memcpy() successfully - once the stack grows downwards, unless he copies pretty large buffer, he is going to copy it to the valid memory that stack occupies, so that FileName is technically valid for the duration of this call. Furthermore, his call to ZwSetInformationFile() may also to be successful. However, when he tries to return from the function he is going to crash because of overwritten return address…

Anton Bassov

>>Actually, after having a thought about it, I came to the conclusion that, indeed, it looks that he has a chance to call memcpy() successfully - once the stack grows downwards, unless he copies pretty large buffer, he is going to copy it to the valid memory that stack occupies, so that FileName is technically valid for the duration of this call. Furthermore, his call to ZwSetInformationFile() may also to be successful. However, when he tries to return from the function he is going to crash because of overwritten return address…

You’re actually right, ZwSetInformationFile is successfull and so the memcpy(), and also when I try to return from the function, this is where the crash occur.

I had to try also allocating FILE_RENAME_INFORMATION dynamically and I’ll get back to you for any progress.

xxxxx@gmail.com wrote:

I am also not sure if the code below will work

memcpy( frInfo.FileName, NewFileName.Buffer, frInfo.FileNameLength + 2 );

I also changed this one into this:

RtlCopyMemory( &frInfo.FileName[0], NewFileName.Buffer, frInfo.FileNameLength + 2 );

But still the error occurs.

frInfo is a FILE_RENAME_INFORMATION structure that contains the ff data:

typedef struct _FILE_RENAME_INFORMATION {
BOOLEAN ReplaceIfExists;
HANDLE RootDirectory;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;

The error is DRIVER_OVERRAN_STACK_BUFFER (f7).

Are you REALLY unable to see the problem in this code, even with the
very excellent hints that have already been provided, and even though
this single post shows everything you need to identify the problem? I’m
agog at that.

I guess I will try to be more explicit. You are trying to copy an file
name into frInfo.FileName. Presumably, the file name is many characters
long – let’s say 40 characters. How big is frInfo.FileName? You
posted it in your message! It’s a ONE-CHARACTER array. You are trying
to copy 80 bytes into an array designed to hold 2 bytes. Of COURSE it
overran the stack!

This structure is not designed to be allocated on the stack like this:
FILE_RENAME_INFORMATION frInfo;

You must dynamically allocate this structure from pool, adding enough
space so that there is ROOM for the filename.
FILE_RENAME_INFORMATION * frInfo;
frInfo = ExAllocatePoolWithTag(
NonPagedPool,
sizeof(FILE_RENAME_INFORMATION) + length_of_new_file_name *
sizeof(WCHAR),
TAG_GENERAL
)

THEN you can memcpy the new file name into frInfo->FileName.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Hello Tim,

I tried Maxim’s suggestion by implementing dynamic allocation just like what you showed and now it works. Thanks for the help guys, my driver won’t crash anymore. I just thought it will work when the structure is allocated directly to the stack. I’ll take note of this for my future implementations. Thanks again anyway.