Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delay between CloseHandle function call and SMB Close request

Tags:

windows

smb

The bit of code below opens a file on an SMB share and closes it immediately. For some reason I'm seeing a delay between the CloseHandle call and the SMB Close request being sent over the wire.

#include <Windows.h>
#include <stdio.h>

typedef NTSTATUS (__stdcall *NtQuerySecurityObjectPtr)(
    _In_  HANDLE               Handle,
    _In_  SECURITY_INFORMATION SecurityInformation,
    _Out_ PSECURITY_DESCRIPTOR SecurityDescriptor,
    _In_  ULONG                Length,
    _Out_ PULONG               LengthNeeded
    );

void printTime() {
    SYSTEMTIME time;
    GetSystemTime(&time);
    int required = GetTimeFormat(LOCALE_INVARIANT, 0, &time, nullptr, nullptr, 0);
    LPTSTR buffer = (LPTSTR)GlobalAlloc(GPTR, required * sizeof(TCHAR));
    GetTimeFormat(LOCALE_INVARIANT, 0, &time, nullptr, buffer, required);
    wprintf(L"%s\n", buffer);
}

int main()
{
    LPCTSTR file = L"\\\\192.168.13.163\\share\\file1";
    HANDLE f = INVALID_HANDLE_VALUE;


    f = CreateFile(
        file,
        GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        nullptr,
        CREATE_ALWAYS,
        FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN,
        INVALID_HANDLE_VALUE
        );
    CloseHandle(f);
    printTime();

    return 0;
}

I ran this code with a debugger and put a breakpoint right after the printTime call. In one test run of this printTime outputs 12:18:11. In Wireshark I see the corresponding Close request being sent out at 12:18:20. So there's about 10s delay between the function call and the message being sent out.

I thought this might be due to a handle being leaked somewhere or some other process keeping a handle to the file open, but I don't think that's the case. If I halt the program right before the CloseHandle call, the sysinternals handle tool, executed in a system user shell, shows me that my process has a handle to the file

C:\Users\pepijn\Desktop>Handle.exe file1

Handle v4.0
Copyright (C) 1997-2014 Mark Russinovich
Sysinternals - www.sysinternals.com

SmbClose.exe       pid: 7020   type: File            C8: \Device\Mup\192.168.13.163\DMTest_share\file1

Running the same command right after the CloseHandle call results in no handles being found

C:\Users\pepijn\Desktop>Handle.exe file1

Handle v4.0
Copyright (C) 1997-2014 Mark Russinovich
Sysinternals - www.sysinternals.com

No matching handles found.

Does anyone know what could be the cause of this delay?

The closest related question on this topic I could find is FileStream.Close() is not closing the file handle instantly. The accepted answer there is that some other process might be holding on to the file. As stated above, I don't think that's the case here. I don't have any virus scanners running and I would expect any open handles to show up in the output of Handle since it's running with elevated privileges.

like image 842
Pepijn Van Eeckhoudt Avatar asked Oct 27 '25 12:10

Pepijn Van Eeckhoudt


2 Answers

Thanks to the first answer I had a better idea of where to look. As far as I can tell this is intentional behaviour in the Windows SMB redirector. It has a cache of open file handles that are reaped every x seconds. This is done to transparently optimise applications that open/close/reopen files often. There are a number of registry keys that should influence this (see https://support.microsoft.com/en-us/kb/102981, https://msdn.microsoft.com/en-us/library/windows/hardware/dn567661%28v=vs.85%29.aspx, https://social.msdn.microsoft.com/Forums/en-US/832d395b-6e6f-4658-8dbb-120138a4cd7c/smb2-registry-settings?forum=os_fileservices) but none of these seem to result in an immediate SMB close request on CloseHandle. The best result I've been able to get is by setting CacheFileTimeout to 0. That still leaves a delay of somewhere between 3-5 seconds (probably determined by how often the cleanup timer is triggered).

like image 66
Pepijn Van Eeckhoudt Avatar answered Oct 30 '25 01:10

Pepijn Van Eeckhoudt


This is apparently due to Batch Oplock (or relative Lease) granted by the server on file open. You can prove this by inspecting Create response with Wireshark.

One of recommended tricks to avoid batch oplocks being granted si opening the same file for reading in another application right before your original CreateFile call.

like image 23
Mark Rabinovich Avatar answered Oct 30 '25 02:10

Mark Rabinovich



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!