VirtualBox

Ignore:
Timestamp:
May 12, 2019 4:32:53 PM (6 years ago)
Author:
vboxsync
Message:

winnt/vboxsf: Rewrote NtQueryVolumeInformationFile / FileFsVolumeInformation handling, correcting the handling of too small buffers (STATUS_BUFFER_OVERFLOW rather than TOO_SMALL + always return correct volume label length; also drop the null terminator like ntfs does). bugref:9172

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

Legend:

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

    r78383 r78471  
    522522}
    523523
     524/**
     525 * Updates VBSFNTFCBEXT::VolInfo.
     526 */
     527static NTSTATUS vbsfNtUpdateFcbVolInfo(PVBSFNTFCBEXT pVBoxFcbX, PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension,
     528                                       PMRX_VBOX_FOBX pVBoxFobx)
     529{
     530    NTSTATUS          rcNt;
     531    VBOXSFVOLINFOREQ *pReq = (VBOXSFVOLINFOREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
     532    if (pReq)
     533    {
     534        int vrc = VbglR0SfHostReqQueryVolInfo(pNetRootExtension->map.root, pReq, pVBoxFobx->hFile);
     535        if (RT_SUCCESS(vrc))
     536        {
     537            pVBoxFcbX->VolInfo           = pReq->VolInfo;
     538            pVBoxFcbX->nsVolInfoUpToDate = RTTimeSystemNanoTS();
     539            rcNt = STATUS_SUCCESS;
     540        }
     541        else
     542            rcNt = vbsfNtVBoxStatusToNt(vrc);
     543        VbglR0PhysHeapFree(pReq);
     544    }
     545    else
     546        rcNt = STATUS_INSUFFICIENT_RESOURCES;
     547    return rcNt;
     548}
     549
     550
     551/**
     552 * Handles NtQueryVolumeInformationFile / FileFsVolumeInformation
     553 */
     554static NTSTATUS vbsfNtQueryVolumeInfo(IN OUT PRX_CONTEXT pRxContext,
     555                                      PFILE_FS_VOLUME_INFORMATION pInfo,
     556                                      ULONG cbInfo,
     557                                      PMRX_NET_ROOT pNetRoot,
     558                                      PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension,
     559                                      PMRX_VBOX_FOBX pVBoxFobx,
     560                                      PVBSFNTFCBEXT pVBoxFcbX)
     561{
     562    /*
     563     * NtQueryVolumeInformationFile should've checked the minimum buffer size
     564     * but just in case.
     565     */
     566    AssertReturnStmt(cbInfo >= RT_UOFFSETOF(FILE_FS_VOLUME_INFORMATION, VolumeLabel),
     567                     pRxContext->InformationToReturn = RT_UOFFSETOF(FILE_FS_VOLUME_INFORMATION, VolumeLabel),
     568                     STATUS_BUFFER_TOO_SMALL);
     569
     570    /*
     571     * Get up-to-date serial number.
     572     *
     573     * If we have a unixy host, we'll get additional unix attributes and the
     574     * serial number is the same as INodeIdDevice.
     575     *
     576     * Note! Because it's possible that the host has mount points within the
     577     *       shared folder as well as symbolic links pointing out files or
     578     *       directories outside the tree, we cannot just cache the serial
     579     *       number in the net root extension data and skip querying it here.
     580     *
     581     *       OTOH, only we don't report inode info from the host, so the only
     582     *       thing the serial number can be used for is to cache/whatever
     583     *       volume space information.  So, we should probably provide a
     584     *       shortcut here via mount option, registry and guest properties.
     585     */
     586    /** @todo Make See OTOH above wrt. one serial per net root.   */
     587    uint64_t nsNow = RTTimeSystemNanoTS();
     588    if (   pVBoxFobx->Info.Attr.enmAdditional == SHFLFSOBJATTRADD_UNIX
     589        && pVBoxFobx->Info.Attr.u.Unix.INodeIdDevice != 0
     590        && pVBoxFobx->nsUpToDate - nsNow < RT_NS_100US /** @todo implement proper TTL */)
     591        pInfo->VolumeSerialNumber = pVBoxFobx->Info.Attr.u.Unix.INodeIdDevice;
     592    else if (pVBoxFcbX->nsVolInfoUpToDate - nsNow < RT_NS_100MS /** @todo implement proper volume info TTL */ )
     593        pInfo->VolumeSerialNumber = pVBoxFcbX->VolInfo.ulSerial;
     594    else
     595    {
     596        /* Must fetch the info. */
     597        NTSTATUS Status = vbsfNtUpdateFcbVolInfo(pVBoxFcbX, pNetRootExtension, pVBoxFobx);
     598        if (NT_SUCCESS(Status))
     599            pInfo->VolumeSerialNumber = pVBoxFcbX->VolInfo.ulSerial;
     600        else
     601            return Status;
     602    }
     603    Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsVolumeInformation: VolumeSerialNumber=%#010RX32\n", pInfo->VolumeSerialNumber));
     604
     605    /*
     606     * Fill in the static info.
     607     */
     608    pInfo->VolumeCreationTime.QuadPart  = 0;
     609    pInfo->SupportsObjects              = FALSE;
     610
     611    /*
     612     * The volume label.
     613     *
     614     * We may get queries with insufficient buffer space for the whole (or any)
     615     * volume label.  In those cases we're to return STATUS_BUFFER_OVERFLOW,
     616     * return the returned number of bytes in Ios.Information and set the
     617     * VolumeLabelLength to the actual length (rather than the returned).  At
     618     * least this is was FAT and NTFS does (however, it is not what the NulMrx
     619     * sample from the 6.1.6001.18002 does).
     620     *
     621     * Note! VolumeLabelLength is a byte count.
     622     * Note! NTFS does not include a terminator, so neither do we.
     623     */
     624    uint32_t const cbShareName  = pNetRoot->pNetRootName->Length
     625                                - pNetRoot->pSrvCall->pSrvCallName->Length
     626                                - sizeof(WCHAR) /* Remove the leading backslash. */;
     627    uint32_t const cbVolLabel   = VBOX_VOLNAME_PREFIX_SIZE + cbShareName;
     628    pInfo->VolumeLabelLength    = cbVolLabel;
     629
     630    WCHAR const   *pwcShareName = &pNetRoot->pNetRootName->Buffer[pNetRoot->pSrvCall->pSrvCallName->Length / sizeof(WCHAR) + 1];
     631    uint32_t       cbCopied     = RT_UOFFSETOF(FILE_FS_VOLUME_INFORMATION, VolumeLabel);
     632    NTSTATUS       Status;
     633    if (cbInfo >= cbCopied + cbVolLabel)
     634    {
     635        memcpy(pInfo->VolumeLabel, VBOX_VOLNAME_PREFIX, VBOX_VOLNAME_PREFIX_SIZE);
     636        memcpy(&pInfo->VolumeLabel[VBOX_VOLNAME_PREFIX_SIZE / sizeof(WCHAR)], pwcShareName, cbShareName);
     637        cbCopied += cbVolLabel;
     638        Status = STATUS_SUCCESS;
     639        Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsVolumeInformation: full result (%#x)\n", cbCopied));
     640    }
     641    else
     642    {
     643        if (cbInfo > cbCopied)
     644        {
     645            uint32_t cbLeft = cbInfo - cbCopied;
     646            memcpy(pInfo->VolumeLabel, VBOX_VOLNAME_PREFIX, RT_MIN(cbLeft, VBOX_VOLNAME_PREFIX_SIZE));
     647            if (cbLeft > VBOX_VOLNAME_PREFIX_SIZE)
     648                memcpy(&pInfo->VolumeLabel[VBOX_VOLNAME_PREFIX_SIZE / sizeof(WCHAR)], pwcShareName, cbShareName);
     649            Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsVolumeInformation: partial result (%#x, needed %#x)\n",
     650                 cbCopied, cbCopied + cbVolLabel));
     651            cbCopied = cbInfo;
     652        }
     653        else
     654            Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsVolumeInformation: partial result no label (%#x, needed %#x)\n",
     655                 cbCopied, cbCopied + cbVolLabel));
     656        Status = STATUS_BUFFER_OVERFLOW;
     657    }
     658
     659    /*
     660     * Update the return length in the context.
     661     */
     662    pRxContext->Info.LengthRemaining = cbInfo - cbCopied;
     663    pRxContext->InformationToReturn  = cbCopied; /* whatever */
     664
     665    return Status;
     666}
     667
    524668NTSTATUS VBoxMRxQueryVolumeInfo(IN OUT PRX_CONTEXT RxContext)
    525669{
     
    549693        case FileFsVolumeInformation:
    550694        {
    551             PFILE_FS_VOLUME_INFORMATION pInfo = (PFILE_FS_VOLUME_INFORMATION)pInfoBuffer;
    552 
    553             PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
    554             PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
    555 
    556             PWCHAR pRootName;
    557             ULONG cbRootName;
    558 
    559             PSHFLVOLINFO pShflVolInfo;
    560             uint32_t cbHGCMBuffer;
    561             uint8_t *pHGCMBuffer;
    562             int vrc;
    563 
    564             Log(("VBOXSF: MrxQueryVolumeInfo: FileFsVolumeInformation\n"));
    565 
    566             if (!pVBoxFobx)
    567             {
    568                 Log(("VBOXSF: MrxQueryVolumeInfo: pVBoxFobx is NULL!\n"));
    569                 Status = STATUS_INVALID_PARAMETER;
    570                 break;
    571             }
    572 
    573             cbRootName = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length;
    574             cbRootName -= sizeof(WCHAR); /* Remove the leading backslash. */
    575             pRootName = pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR));
    576             pRootName++; /* Remove the leading backslash. */
    577 
    578             Log(("VBOXSF: MrxQueryVolumeInfo: FileFsVolumeInformation: Root name = %.*ls, %d bytes\n",
    579                  cbRootName / sizeof(WCHAR), pRootName, cbRootName));
    580 
    581             cbToCopy = FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel);
    582 
    583             cbString  = VBOX_VOLNAME_PREFIX_SIZE;
    584             cbString += cbRootName;
    585             cbString += sizeof(WCHAR);
    586 
    587             Log(("VBOXSF: MrxQueryVolumeInfo: FileFsVolumeInformation: cbToCopy %d, cbString %d\n",
    588                  cbToCopy, cbString));
    589 
    590             if (cbInfoBuffer < cbToCopy)
    591             {
    592                 Status = STATUS_BUFFER_TOO_SMALL;
    593                 break;
    594             }
    595 
    596             RtlZeroMemory(pInfo, cbToCopy);
    597 
    598             /* Query serial number. */
    599             cbHGCMBuffer = sizeof(SHFLVOLINFO);
    600             pHGCMBuffer = (uint8_t *)vbsfNtAllocNonPagedMem(cbHGCMBuffer);
    601             if (!pHGCMBuffer)
    602             {
    603                 Status = STATUS_INSUFFICIENT_RESOURCES;
    604                 break;
    605             }
    606 
    607             vrc = VbglR0SfFsInfo(&g_SfClient, &pNetRootExtension->map, pVBoxFobx->hFile,
    608                                  SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbHGCMBuffer, (PSHFLDIRINFO)pHGCMBuffer);
    609 
    610             if (vrc != VINF_SUCCESS)
    611             {
    612                 Status = vbsfNtVBoxStatusToNt(vrc);
    613                 vbsfNtFreeNonPagedMem(pHGCMBuffer);
    614                 break;
    615             }
    616 
    617             pShflVolInfo = (PSHFLVOLINFO)pHGCMBuffer;
    618             pInfo->VolumeSerialNumber = pShflVolInfo->ulSerial;
    619             vbsfNtFreeNonPagedMem(pHGCMBuffer);
    620 
    621             pInfo->VolumeCreationTime.QuadPart = 0;
    622             pInfo->SupportsObjects = FALSE;
    623 
    624             if (cbInfoBuffer >= cbToCopy + cbString)
    625             {
    626                 RtlCopyMemory(&pInfo->VolumeLabel[0],
    627                               VBOX_VOLNAME_PREFIX,
    628                               VBOX_VOLNAME_PREFIX_SIZE);
    629                 RtlCopyMemory(&pInfo->VolumeLabel[VBOX_VOLNAME_PREFIX_SIZE / sizeof(WCHAR)],
    630                               pRootName,
    631                               cbRootName);
    632                 pInfo->VolumeLabel[cbString / sizeof(WCHAR) -  1] = 0;
    633             }
    634             else
    635             {
    636                 cbString = cbInfoBuffer - cbToCopy;
    637 
    638                 RtlCopyMemory(&pInfo->VolumeLabel[0],
    639                               VBOX_VOLNAME_PREFIX,
    640                               RT_MIN(cbString, VBOX_VOLNAME_PREFIX_SIZE));
    641                 if (cbString > VBOX_VOLNAME_PREFIX_SIZE)
    642                 {
    643                     RtlCopyMemory(&pInfo->VolumeLabel[VBOX_VOLNAME_PREFIX_SIZE / sizeof(WCHAR)],
    644                                   pRootName,
    645                                   cbString - VBOX_VOLNAME_PREFIX_SIZE);
    646                 }
    647             }
    648 
    649             pInfo->VolumeLabelLength = cbString;
    650 
    651             cbToCopy += cbString;
    652 
    653             Log(("VBOXSF: MrxQueryVolumeInfo: FileFsVolumeInformation: VolumeLabelLength %d\n",
    654                  pInfo->VolumeLabelLength));
    655 
    656             Status = STATUS_SUCCESS;
    657             break;
     695            AssertReturn(pVBoxFobx, STATUS_INVALID_PARAMETER);
     696            Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsVolumeInformation\n"));
     697
     698            Status = vbsfNtQueryVolumeInfo(RxContext, (PFILE_FS_VOLUME_INFORMATION)RxContext->Info.Buffer,
     699                                           RxContext->Info.Length, capFcb->pNetRoot, pNetRootExtension, pVBoxFobx,
     700                                           VBoxMRxGetFcbExtension(capFcb));
     701            return Status;
    658702        }
    659703
     
    17471791    Log(("VBOXSF: vbsfNtRename: FileNameLength = %#x (%d), FileName = %.*ls\n",
    17481792         cbFilename, cbFilename, cbFilename / sizeof(WCHAR), &pRenameInfo->FileName[0]));
     1793
     1794/** @todo Add new function that also closes the handle, like for remove, saving a host call. */
    17491795
    17501796    /* Must close the file before renaming it! */
  • trunk/src/VBox/Additions/WINNT/SharedFolders/driver/vbsf.h

    r78468 r78471  
    125125    PMRX_VBOX_FOBX            pFobxLastWriteTime;
    126126    PMRX_VBOX_FOBX            pFobxChangeTime;
     127    /** @} */
     128
     129    /** @name Cached volume info.
     130     * @{ */
     131    /** The RTTimeSystemNanoTS value when VolInfo was retrieved, 0 to force update. */
     132    uint64_t                  nsVolInfoUpToDate;
     133    /** Volume information. */
     134    SHFLVOLINFO               VolInfo;
    127135    /** @} */
    128136} VBSFNTFCBEXT;
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