VirtualBox

Changeset 78368 in vbox for trunk


Ignore:
Timestamp:
May 3, 2019 3:02:54 AM (6 years ago)
Author:
vboxsync
Message:

winnt/vboxsf: Workaround for SetEndOfFile() to the cached file size (i.e. the file size percieved by the guest) being incorrectly nooped out by the RDBSS code. Since the host may have appended (or truncated) the file without the guest noticing, a SetEndOfFile call must restore the file size to what the guest expected. A possible scenario would be resaving a document to overwrite host edits that extended the file (a bit unusual, though, since the editor would typically re-open the file, but it could happen). bugref:9172

Location:
trunk/src/VBox/Additions/WINNT/SharedFolders/driver
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/WINNT/SharedFolders/driver/info.cpp

    r78366 r78368  
    2222#include "vbsf.h"
    2323#include <iprt/err.h>
     24
     25extern "C" NTSTATUS NTAPI RxSetEndOfFileInfo(PRX_CONTEXT, PIRP, PFCB, PFOBX);
    2426
    2527
     
    18331835     *     db 4                    ; 75      FileCaseSensitiveInformationForceAccessCheck, - for the i/o manager, w10-1809.
    18341836     */
    1835     switch (RxContext->Info.FileInformationClass)
     1837    switch ((int)RxContext->Info.FileInformationClass)
    18361838    {
    18371839        /*
     
    19441946         *       will hide calls which does not change the size from us.  This is of course not
    19451947         *       the case for non-local file systems, as the server is the only which up-to-date
    1946          *       information.  Don't see an easy way of working around it, so ignoring it for now.
     1948         *       information.
     1949         *
     1950         *       We work around this either by modifying FCB.Header.FileSize slightly when it equals
     1951         *       the new size.  This is either done below in the FileEndOfFileInformation + 4096 case,
     1952         *       or when using older WDK libs in VBoxHookMjSetInformation.  The FCB is locked
     1953         *       exclusivly while we operate with the incorrect Header.FileSize value, which should
     1954         *       prevent anyone else from making use of it till it has been updated again.
     1955         *
    19471956         */
    19481957        case FileEndOfFileInformation:
     
    19581967            break;
    19591968        }
     1969
     1970#if 0 /* This only works for more recent versions of the RDBSS library, not for the one we're using (WDK 7600.16385.1). */
     1971        /*
     1972         * HACK ALERT! This is FileEndOfFileInformation after it passed thru
     1973         * VBoxHookMjSetInformation so we can twiddle the cached file size in
     1974         * the FCB to ensure the set EOF request always reaches the host.
     1975         *
     1976         * Note! We have to call thru RxSetEndOfFileInfo to benefit from its
     1977         *       update logic and avoid needing to replicate that code.
     1978         */
     1979        case FileEndOfFileInformation + 4096:
     1980        {
     1981            PFILE_END_OF_FILE_INFORMATION pInfo = (PFILE_END_OF_FILE_INFORMATION)RxContext->Info.Buffer;
     1982            Log(("VBOXSF: MrxSetFileInfo: FileEndOfFileInformation+4096: new EndOfFile 0x%RX64, FileSize = 0x%RX64\n",
     1983                 pInfo->EndOfFile.QuadPart, capFcb->Header.FileSize.QuadPart));
     1984
     1985            /* Undo the change from VBoxHookMjSetInformation:  */
     1986            Assert(RxContext->CurrentIrpSp);
     1987            RxContext->CurrentIrpSp->Parameters.SetFile.FileInformationClass = FileEndOfFileInformation;
     1988            RxContext->Info.FileInformationClass                             = FileEndOfFileInformation;
     1989
     1990            /* Tweak the size if necessary and forward the call. */
     1991            int64_t const cbOldSize = capFcb->Header.FileSize.QuadPart;
     1992            if (   pInfo->EndOfFile.QuadPart != cbOldSize
     1993                || !(capFcb->FcbState & FCB_STATE_PAGING_FILE))
     1994            {
     1995                Status = RxSetEndOfFileInfo(RxContext, RxContext->CurrentIrp, (PFCB)capFcb, (PFOBX)capFobx);
     1996                Log(("VBOXSF: MrxSetFileInfo: FileEndOfFileInformation+4096: Status 0x%08X\n",
     1997                     Status));
     1998            }
     1999            else
     2000            {
     2001                int64_t const cbHackedSize = cbOldSize ? cbOldSize - 1 : 1;
     2002                capFcb->Header.FileSize.QuadPart = cbHackedSize;
     2003                Status = RxSetEndOfFileInfo(RxContext, RxContext->CurrentIrp, (PFCB)capFcb, (PFOBX)capFobx);
     2004                if (   !NT_SUCCESS(Status)
     2005                    && capFcb->Header.FileSize.QuadPart == cbHackedSize)
     2006                    capFcb->Header.FileSize.QuadPart = cbOldSize;
     2007                else
     2008                    Assert(   capFcb->Header.FileSize.QuadPart != cbHackedSize
     2009                           || pVBoxFobx->Info.cbObject == cbHackedSize);
     2010                Log(("VBOXSF: MrxSetFileInfo: FileEndOfFileInformation+4096: Status 0x%08X (tweaked)\n",
     2011                     Status));
     2012            }
     2013            break;
     2014        }
     2015#endif
    19602016
    19612017        /// @todo FileModeInformation ?
  • trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsf.cpp

    r78355 r78368  
    492492}
    493493
     494/**
     495 * Intercepts IRP_MJ_SET_INFORMATION to workaround a RDBSS quirk in the
     496 * FileEndOfFileInformation handling.
     497 *
     498 * We will add 4096 to the FileEndOfFileInformation function value and pick it
     499 * up in VBoxMRxSetFileInfo after RxCommonSetInformation has done the necessary
     500 * locking.  If we find that the desired file size matches the cached one, just
     501 * issue the call directly, otherwise subtract 4096 and call the
     502 * RxSetEndOfFileInfo worker.
     503 */
     504static NTSTATUS VBoxHookMjSetInformation(PDEVICE_OBJECT pDevObj, PIRP pIrp)
     505{
     506    PMRX_VBOX_DEVICE_EXTENSION  pDevExt  = (PMRX_VBOX_DEVICE_EXTENSION)((PBYTE)pDevObj + sizeof(RDBSS_DEVICE_OBJECT));
     507    PIO_STACK_LOCATION          pStack   = IoGetCurrentIrpStackLocation(pIrp);
     508    PFILE_OBJECT                pFileObj = pStack->FileObject;
     509    NTSTATUS                    rcNt;
     510
     511    Log(("VBOXSF: VBoxHookMjSetInformation: pDevObj %p, pDevExt %p, pFileObj %p, FileInformationClass %d, Length %#x\n",
     512         pDevObj, pDevObj->DeviceExtension, pFileObj, pStack->Parameters.SetFile.FileInformationClass, pStack->Parameters.SetFile.Length));
     513    if (pFileObj)
     514        Log2(("VBOXSF: VBoxHookMjSetInformation: FileName=%.*ls\n", pFileObj->FileName.Length / sizeof(WCHAR), pFileObj->FileName.Buffer));
     515
     516    /*
     517     * Setting EOF info?
     518     */
     519    if (pStack->Parameters.SetFile.FileInformationClass == FileEndOfFileInformation)
     520    {
     521#if 0 /* This only works for more recent versions of the RDBSS library, not for the one we're using (WDK 7600.16385.1). */
     522        pStack->Parameters.SetFile.FileInformationClass = (FILE_INFORMATION_CLASS)(FileEndOfFileInformation + 4096);
     523        rcNt = pDevExt->pfnRDBSSSetInformation(pDevObj, pIrp);
     524        Log(("VBOXSF: VBoxHookMjSetInformation: returns %#x (hacked)\n", rcNt));
     525        return rcNt;
     526#else
     527        /*
     528         * For the older WDK, we have to detect the same-size situation up front and hack
     529         * it here instead of in VBoxMRxSetFileInfo.  This means we need to lock the FCB
     530         * before modifying the Fcb.Header.FileSize value and ASSUME the locking is
     531         * reentrant and nothing else happens during RDBSS dispatching wrt that...
     532         */
     533        PMRX_FCB pFcb = (PMRX_FCB)pFileObj->FsContext;
     534        if (   (NODE_TYPE_CODE)pFcb->Header.NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE
     535            && pIrp->AssociatedIrp.SystemBuffer != NULL
     536            && pStack->Parameters.SetFile.Length >= sizeof(FILE_END_OF_FILE_INFORMATION))
     537        {
     538            LONGLONG cbFileNew = -42;
     539            __try
     540            {
     541                cbFileNew = ((PFILE_END_OF_FILE_INFORMATION)pIrp->AssociatedIrp.SystemBuffer)->EndOfFile.QuadPart;
     542            }
     543            __except(EXCEPTION_EXECUTE_HANDLER)
     544            {
     545                cbFileNew = -42;
     546            }
     547            if (   cbFileNew >= 0
     548                && pFcb->Header.FileSize.QuadPart == cbFileNew
     549                && !(pFcb->FcbState & FCB_STATE_PAGING_FILE))
     550            {
     551                /* Now exclusivly lock the FCB like RxCommonSetInformation would do
     552                   to reduce chances of races and of anyone else grabbing the value
     553                   while it's incorrect on purpose. */
     554                NTSTATUS rcNtLock = RxAcquireExclusiveFcb(NULL, (PFCB)pFcb);
     555                if (NT_SUCCESS(rcNtLock))
     556                {
     557                    if (pFcb->Header.FileSize.QuadPart == cbFileNew)
     558                    {
     559                        int64_t const cbHackedSize = cbFileNew ? cbFileNew - 1 : 1;
     560                        pFcb->Header.FileSize.QuadPart = cbHackedSize;
     561                        rcNt = pDevExt->pfnRDBSSSetInformation(pDevObj, pIrp);
     562                        if (   !NT_SUCCESS(rcNt)
     563                            && pFcb->Header.FileSize.QuadPart == cbHackedSize)
     564                            pFcb->Header.FileSize.QuadPart = cbFileNew;
     565# ifdef VBOX_STRICT
     566                        else
     567                        {
     568                            PMRX_FOBX pFobx = (PMRX_FOBX)pFileObj->FsContext2;
     569                            PMRX_VBOX_FOBX pVBoxFobX = VBoxMRxGetFileObjectExtension(pFobx);
     570                            Assert(   pFcb->Header.FileSize.QuadPart != cbHackedSize
     571                                   || (pVBoxFobX && pVBoxFobX->Info.cbObject == cbHackedSize));
     572                        }
     573# endif
     574                        RxReleaseFcb(NULL, pFcb);
     575                        Log(("VBOXSF: VBoxHookMjSetInformation: returns %#x (hacked, cbFileNew=%#RX64)\n", rcNt, cbFileNew));
     576                        return rcNt;
     577                    }
     578                    RxReleaseFcb(NULL, pFcb);
     579                }
     580            }
     581        }
     582#endif
     583    }
     584
     585    /*
     586     * No hack needed.
     587     */
     588    rcNt = pDevExt->pfnRDBSSSetInformation(pDevObj, pIrp);
     589    Log(("VBOXSF: VBoxHookMjSetInformation: returns %#x\n", rcNt));
     590    return rcNt;
     591}
     592
    494593NTSTATUS DriverEntry(IN PDRIVER_OBJECT  DriverObject,
    495594                     IN PUNICODE_STRING RegistryPath)
     
    649748    pDeviceExtension->pfnRDBSSCreate = DriverObject->MajorFunction[IRP_MJ_CREATE];
    650749    DriverObject->MajorFunction[IRP_MJ_CREATE] = VBoxHookMjCreate;
     750
     751    /* Intercept IRP_MJ_SET_INFORMATION to ensure we call the host for all
     752     * FileEndOfFileInformation requestes, even if the new size matches the
     753     * old one.  We don't know if someone else might have modified the file
     754     * size cached in the FCB since the last time we update it.
     755     */
     756    pDeviceExtension->pfnRDBSSSetInformation = DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION];
     757    DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = VBoxHookMjSetInformation;
    651758
    652759
  • trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsf.h

    r78366 r78368  
    8282    /** Saved pointer to the original IRP_MJ_CREATE handler. */
    8383    NTSTATUS (NTAPI * pfnRDBSSCreate)(PDEVICE_OBJECT pDevObj, PIRP pIrp);
     84    /** Saved pointer to the original IRP_MJ_SET_INFORMATION handler. */
     85    NTSTATUS (NTAPI * pfnRDBSSSetInformation)(PDEVICE_OBJECT pDevObj, PIRP pIrp);
    8486
    8587} MRX_VBOX_DEVICE_EXTENSION, *PMRX_VBOX_DEVICE_EXTENSION;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette