1
votes

I have a file which I want to delete, it's handle is held by system process so everytime I try to delete it it gives Access denied but for some reason cygwin is able to delete it.

I've downloaded the coreutils and investigated the source code of rm executable and found that it uses unlink function to achieve it. I've created a little test program which uses same function but it gives me Access denied anyway.

Then I found this article and guy describes how cygwin is able to delete a file which is the following:

Cygwin opens files always with all sharing flags set, so a file opened by a Cygwin process should not result in a sharing violation in another open call. The exception is the first NtOpenFile in unlink_nt, which opens the file with FILE_SHARE_DELETE only to find out if the file has an open handle somewhere else. In that case it gets a STATUS_SHARING_VIOLATION, the next NtOpenFile will open the file with all sharing flags set, and unlink_nt will try to delete the file or to rename it, or to move it to the recycle bin, dependent on its path.

Which makes sense, So I started to implement same thing. Here is my code:

HANDLE file;
PIO_STATUS_BLOCK stat;

UNICODE_STRING myUnicodeStr;
RtlInitUnicodeString(&myUnicodeStr, L"C:\\Program Files (x86)\\TSU\\bin\\TSU.sys");

POBJECT_ATTRIBUTES attr;
InitializeObjectAttributes (attr, &myUnicodeStr, OBJ_OPENIF, NULL, NULL);

NtOpenFile(&file, MAXIMUM_ALLOWED, attr, NULL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_DELETE_ON_CLOSE);

NtClose(file);

As you can see I'm trying to open file with sharing flags set and also used FILE_DELETE_ON_CLOSE since I close the handle and I want it to be deleted afterwards.

The problem I have is Segmentation Fault(I'm using cygwin win10) for some reason. Little debugging showed that problem is in InitializeObjectAttributes function for some reason.

P.S I know it's not the best solution to delete file when it's handle is held by some other process but the main goal is to mimic the rm.exe's behaviour in this way. Hope you can help. Thanks.

1
Change POBJECT_ATTRIBUTES attr; InitializeObjectAttributes (attr, ...); to OBJECT_ATTRIBUTES attr; InitializeObjectAttributes (&attr, ...);, and then pass &attr to NtOpenFile()Remy Lebeau
because file can not be deleted while it in use.RbMm
this impossible in windowsRbMm
it really not delete file of course but move it to $Recycle.BinRbMm
look in $Recycle.Bin (om same disk) for "deleted" fileRbMm

1 Answers

2
votes

under windows not always possible delete file. for example when some process mapping this file as an image

if try delete running EXE file with rm.exe - it first call ZwOpenFile with DesiredAccess = DELETE, ShareAccess = FILE_SHARE_DELETE and OpenOptions = FILE_OPEN_FOR_BACKUP_INTENT. this is ok. than called ZwSetInformationFile with FileDispositionInformation - the DeleteFile from FILE_DISPOSITION_INFORMATION set to TRUE. this call failed with status STATUS_CANNOT_DELETE.

filesystem return STATUS_CANNOT_DELETE exactly from this place:

        //  Make sure there is no process mapping this file as an image.

        if (!MmFlushImageSection( &Fcb->NonPaged->SectionObjectPointers,
                                  MmFlushForDelete )) {

            DebugTrace(-1, Dbg, "Cannot delete user mapped image\n", 0);

            return STATUS_CANNOT_DELETE;
}

than rm.exe again try open file, already with OpenOptions = FILE_OPEN_FOR_BACKUP_INTENT | FILE_DELETE_ON_CLOSE options. but this call of course fail with the same STATUS_CANNOT_DELETE. now error from this point:

//  If the user wants to delete on close, we must check at this
//  point though.
//

if (FlagOn(*DesiredAccess, FILE_WRITE_DATA) || DeleteOnClose) {

    Fcb->OpenCount += 1;
    DecrementFcbOpenCount = TRUE;

    if (!MmFlushImageSection( &Fcb->NonPaged->SectionObjectPointers,
                              MmFlushForWrite )) {

        Iosb.Status = DeleteOnClose ? STATUS_CANNOT_DELETE :
                                      STATUS_SHARING_VIOLATION;
        try_return( Iosb );
    }
}

after this rm.exe again call ZwSetInformationFile already with FileRenameInformation - where RootDirectory from FILE_RENAME_INFORMATION point to volume (on which file located) root (so like \Device\HarddiskVolume<N>\ and FileName point to some path in recycle bin. as result file actually moved but not deleted. rm.exe deceives you