VirtualBox

Changeset 64240 in vbox for trunk/src


Ignore:
Timestamp:
Oct 13, 2016 12:35:30 PM (8 years ago)
Author:
vboxsync
Message:

Storage/Devices/DrvHost*: Separate the host specific code in drvHostDvdSendCmd() into separate sources for each host

Location:
trunk/src/VBox/Devices
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Makefile.kmk

    r64239 r64240  
    201201        Storage/DrvHostBase-freebsd.cpp
    202202
     203 VBoxDD_SOURCES.linux += \
     204        Storage/DrvHostBase-linux.cpp
     205
     206 VBoxDD_SOURCES.solaris += \
     207        Storage/DrvHostBase-solaris.cpp
     208
     209 VBoxDD_SOURCES.win += \
     210        Storage/DrvHostBase-win.cpp
     211
    203212 #VBoxDD_SOURCES.win += Storage/HBDMgmt-win.cpp #Disabled until remaining issues are sorted out
    204213
  • trunk/src/VBox/Devices/Storage/DrvHostBase.h

    r64239 r64240  
    189189void DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis);
    190190DECLCALLBACK(void) DRVHostBaseDestruct(PPDMDRVINS pDrvIns);
    191 #if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
     191
    192192DECLHIDDEN(int) drvHostBaseScsiCmdOs(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMMEDIATXDIR enmTxDir,
    193193                                     void *pvBuf, uint32_t *pcbBuf, uint8_t *pbSense, size_t cbSense, uint32_t cTimeoutMillies);
    194 #endif
    195194
    196195
  • trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp

    r64239 r64240  
    118118*********************************************************************************************************************************/
    119119static DECLCALLBACK(int) drvHostDvdDoLock(PDRVHOSTBASE pThis, bool fLock);
     120
    120121#ifdef VBOX_WITH_SUID_WRAPPER
    121 static int solarisCheckUserAuth();
    122 static int solarisEnterRootMode(uid_t *pEffUserID);
    123 static int solarisExitRootMode(uid_t *pEffUserID);
    124 #endif
    125 
     122/**
     123 * Checks if the current user is authorized using Solaris' role-based access control.
     124 * Made as a separate function with so that it need not be invoked each time we need
     125 * to gain root access.
     126 *
     127 * @returns VBox error code.
     128 */
     129static int solarisCheckUserAuth()
     130{
     131    /* Uses Solaris' role-based access control (RBAC).*/
     132    struct passwd *pPass = getpwuid(getuid());
     133    if (pPass == NULL || chkauthattr("solaris.device.cdrw", pPass->pw_name) == 0)
     134        return VERR_PERMISSION_DENIED;
     135
     136    return VINF_SUCCESS;
     137}
     138#endif
    126139
    127140/** @interface_method_impl{PDMIMOUNT,pfnUnmount} */
     
    421434    LogFlow(("%s: cmd[0]=%#04x txdir=%d pcbBuf=%d timeout=%d\n", __FUNCTION__, pbCmd[0], enmTxDir, *pcbBuf, cTimeoutMillies));
    422435
    423 #if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
    424436    /*
    425437     * Pass the request on to the internal scsi command interface.
     
    428440    if (enmTxDir == PDMMEDIATXDIR_FROM_DEVICE)
    429441        memset(pvBuf, '\0', *pcbBuf); /* we got read size, but zero it anyway. */
    430     rc = drvHostBaseScsiCmdOs(pThis, pbCmd, 12, PDMMEDIATXDIR_FROM_DEVICE, pvBuf, pcbBuf, pabSense, cbSense, cTimeoutMillies);
     442    rc = drvHostBaseScsiCmdOs(pThis, pbCmd, 12, enmTxDir, pvBuf, pcbBuf, pabSense, cbSense, cTimeoutMillies);
    431443    if (rc == VERR_UNRESOLVED_ERROR)
    432444        /* sense information set */
    433445        rc = VERR_DEV_IO_ERROR;
    434 
    435 #elif defined(RT_OS_LINUX)
    436     int direction;
    437     struct cdrom_generic_command cgc;
    438 
    439     switch (enmTxDir)
    440     {
    441         case PDMMEDIATXDIR_NONE:
    442             Assert(*pcbBuf == 0);
    443             direction = CGC_DATA_NONE;
    444             break;
    445         case PDMMEDIATXDIR_FROM_DEVICE:
    446             Assert(*pcbBuf != 0);
    447             Assert(*pcbBuf <= SCSI_MAX_BUFFER_SIZE);
    448             /* Make sure that the buffer is clear for commands reading
    449              * data. The actually received data may be shorter than what
    450              * we expect, and due to the unreliable feedback about how much
    451              * data the ioctl actually transferred, it's impossible to
    452              * prevent that. Returning previous buffer contents may cause
    453              * security problems inside the guest OS, if users can issue
    454              * commands to the CDROM device. */
    455             memset(pThis->pbDoubleBuffer, '\0', *pcbBuf);
    456             direction = CGC_DATA_READ;
    457             break;
    458         case PDMMEDIATXDIR_TO_DEVICE:
    459             Assert(*pcbBuf != 0);
    460             Assert(*pcbBuf <= SCSI_MAX_BUFFER_SIZE);
    461             memcpy(pThis->pbDoubleBuffer, pvBuf, *pcbBuf);
    462             direction = CGC_DATA_WRITE;
    463             break;
    464         default:
    465             AssertMsgFailed(("enmTxDir invalid!\n"));
    466             direction = CGC_DATA_NONE;
    467     }
    468     memset(&cgc, '\0', sizeof(cgc));
    469     memcpy(cgc.cmd, pbCmd, CDROM_PACKET_SIZE);
    470     cgc.buffer = (unsigned char *)pThis->pbDoubleBuffer;
    471     cgc.buflen = *pcbBuf;
    472     cgc.stat = 0;
    473     Assert(cbSense >= sizeof(struct request_sense));
    474     cgc.sense = (struct request_sense *)pabSense;
    475     cgc.data_direction = direction;
    476     cgc.quiet = false;
    477     cgc.timeout = cTimeoutMillies;
    478     rc = ioctl(RTFileToNative(pThis->hFileDevice), CDROM_SEND_PACKET, &cgc);
    479     if (rc < 0)
    480     {
    481         if (errno == EBUSY)
    482             rc = VERR_PDM_MEDIA_LOCKED;
    483         else if (errno == ENOSYS)
    484             rc = VERR_NOT_SUPPORTED;
    485         else
    486         {
    487             rc = RTErrConvertFromErrno(errno);
    488             if (rc == VERR_ACCESS_DENIED && cgc.sense->sense_key == SCSI_SENSE_NONE)
    489                 cgc.sense->sense_key = SCSI_SENSE_ILLEGAL_REQUEST;
    490             Log2(("%s: error status %d, rc=%Rrc\n", __FUNCTION__, cgc.stat, rc));
    491         }
    492     }
    493     switch (enmTxDir)
    494     {
    495         case PDMMEDIATXDIR_FROM_DEVICE:
    496             memcpy(pvBuf, pThis->pbDoubleBuffer, *pcbBuf);
    497             break;
    498         default:
    499             ;
    500     }
    501     Log2(("%s: after ioctl: cgc.buflen=%d txlen=%d\n", __FUNCTION__, cgc.buflen, *pcbBuf));
    502     /* The value of cgc.buflen does not reliably reflect the actual amount
    503      * of data transferred (for packet commands with little data transfer
    504      * it's 0). So just assume that everything worked ok. */
    505 
    506 #elif defined(RT_OS_SOLARIS)
    507     struct uscsi_cmd usc;
    508     union scsi_cdb scdb;
    509     memset(&usc, 0, sizeof(struct uscsi_cmd));
    510     memset(&scdb, 0, sizeof(scdb));
    511 
    512     switch (enmTxDir)
    513     {
    514         case PDMMEDIATXDIR_NONE:
    515             Assert(*pcbBuf == 0);
    516             usc.uscsi_flags = USCSI_READ;
    517             /* nothing to do */
    518             break;
    519 
    520         case PDMMEDIATXDIR_FROM_DEVICE:
    521             Assert(*pcbBuf != 0);
    522             /* Make sure that the buffer is clear for commands reading
    523              * data. The actually received data may be shorter than what
    524              * we expect, and due to the unreliable feedback about how much
    525              * data the ioctl actually transferred, it's impossible to
    526              * prevent that. Returning previous buffer contents may cause
    527              * security problems inside the guest OS, if users can issue
    528              * commands to the CDROM device. */
    529             memset(pvBuf, '\0', *pcbBuf);
    530             usc.uscsi_flags = USCSI_READ;
    531             break;
    532         case PDMMEDIATXDIR_TO_DEVICE:
    533             Assert(*pcbBuf != 0);
    534             usc.uscsi_flags = USCSI_WRITE;
    535             break;
    536         default:
    537             AssertMsgFailedReturn(("%d\n", enmTxDir), VERR_INTERNAL_ERROR);
    538     }
    539     usc.uscsi_flags |= USCSI_RQENABLE;
    540     usc.uscsi_rqbuf = (char *)pabSense;
    541     usc.uscsi_rqlen = cbSense;
    542     usc.uscsi_cdb = (caddr_t)&scdb;
    543     usc.uscsi_cdblen = 12;
    544     memcpy (usc.uscsi_cdb, pbCmd, usc.uscsi_cdblen);
    545     usc.uscsi_bufaddr = (caddr_t)pvBuf;
    546     usc.uscsi_buflen = *pcbBuf;
    547     usc.uscsi_timeout = (cTimeoutMillies + 999) / 1000;
    548 
    549     /* We need root privileges for user-SCSI under Solaris. */
    550 #ifdef VBOX_WITH_SUID_WRAPPER
    551     uid_t effUserID = geteuid();
    552     solarisEnterRootMode(&effUserID); /** @todo check return code when this really works. */
    553 #endif
    554     rc = ioctl(RTFileToNative(pThis->hFileRawDevice), USCSICMD, &usc);
    555 #ifdef VBOX_WITH_SUID_WRAPPER
    556     solarisExitRootMode(&effUserID);
    557 #endif
    558     if (rc < 0)
    559     {
    560         if (errno == EPERM)
    561             return VERR_PERMISSION_DENIED;
    562         if (usc.uscsi_status)
    563         {
    564             rc = RTErrConvertFromErrno(errno);
    565             Log2(("%s: error status. rc=%Rrc\n", __FUNCTION__, rc));
    566         }
    567     }
    568     Log2(("%s: after ioctl: residual buflen=%d original buflen=%d\n", __FUNCTION__, usc.uscsi_resid, usc.uscsi_buflen));
    569 
    570 #elif defined(RT_OS_WINDOWS)
    571     int direction;
    572     struct _REQ
    573     {
    574         SCSI_PASS_THROUGH_DIRECT spt;
    575         uint8_t aSense[64];
    576     } Req;
    577     DWORD cbReturned = 0;
    578 
    579     switch (enmTxDir)
    580     {
    581         case PDMMEDIATXDIR_NONE:
    582             direction = SCSI_IOCTL_DATA_UNSPECIFIED;
    583             break;
    584         case PDMMEDIATXDIR_FROM_DEVICE:
    585             Assert(*pcbBuf != 0);
    586             /* Make sure that the buffer is clear for commands reading
    587              * data. The actually received data may be shorter than what
    588              * we expect, and due to the unreliable feedback about how much
    589              * data the ioctl actually transferred, it's impossible to
    590              * prevent that. Returning previous buffer contents may cause
    591              * security problems inside the guest OS, if users can issue
    592              * commands to the CDROM device. */
    593             memset(pvBuf, '\0', *pcbBuf);
    594             direction = SCSI_IOCTL_DATA_IN;
    595             break;
    596         case PDMMEDIATXDIR_TO_DEVICE:
    597             direction = SCSI_IOCTL_DATA_OUT;
    598             break;
    599         default:
    600             AssertMsgFailed(("enmTxDir invalid!\n"));
    601             direction = SCSI_IOCTL_DATA_UNSPECIFIED;
    602     }
    603     memset(&Req, '\0', sizeof(Req));
    604     Req.spt.Length = sizeof(Req.spt);
    605     Req.spt.CdbLength = 12;
    606     memcpy(Req.spt.Cdb, pbCmd, Req.spt.CdbLength);
    607     Req.spt.DataBuffer = pvBuf;
    608     Req.spt.DataTransferLength = *pcbBuf;
    609     Req.spt.DataIn = direction;
    610     Req.spt.TimeOutValue = (cTimeoutMillies + 999) / 1000; /* Convert to seconds */
    611     Assert(cbSense <= sizeof(Req.aSense));
    612     Req.spt.SenseInfoLength = (UCHAR)RT_MIN(sizeof(Req.aSense), cbSense);
    613     Req.spt.SenseInfoOffset = RT_OFFSETOF(struct _REQ, aSense);
    614     if (DeviceIoControl((HANDLE)RTFileToNative(pThis->hFileDevice), IOCTL_SCSI_PASS_THROUGH_DIRECT,
    615                         &Req, sizeof(Req), &Req, sizeof(Req), &cbReturned, NULL))
    616     {
    617         if (cbReturned > RT_OFFSETOF(struct _REQ, aSense))
    618             memcpy(pabSense, Req.aSense, cbSense);
    619         else
    620             memset(pabSense, '\0', cbSense);
    621         /* Windows shares the property of not properly reflecting the actually
    622          * transferred data size. See above. Assume that everything worked ok.
    623          * Except if there are sense information. */
    624         rc = (pabSense[2] & 0x0f) == SCSI_SENSE_NONE
    625                  ? VINF_SUCCESS
    626                  : VERR_DEV_IO_ERROR;
    627     }
    628     else
    629         rc = RTErrConvertFromWin32(GetLastError());
    630     Log2(("%s: scsistatus=%d bytes returned=%d tlength=%d\n", __FUNCTION__, Req.spt.ScsiStatus, cbReturned, Req.spt.DataTransferLength));
    631 
    632 #else
    633 # error "Unsupported platform."
    634 #endif
    635446
    636447    if (pbCmd[0] == SCSI_GET_EVENT_STATUS_NOTIFICATION)
     
    645456    return rc;
    646457}
    647 
    648 
    649 #ifdef VBOX_WITH_SUID_WRAPPER
    650 /* These functions would have to go into a separate solaris binary with
    651  * the setuid permission set, which would run the user-SCSI ioctl and
    652  * return the value. BUT... this might be prohibitively slow.
    653  */
    654 # ifdef RT_OS_SOLARIS
    655 
    656 /**
    657  * Checks if the current user is authorized using Solaris' role-based access control.
    658  * Made as a separate function with so that it need not be invoked each time we need
    659  * to gain root access.
    660  *
    661  * @returns VBox error code.
    662  */
    663 static int solarisCheckUserAuth()
    664 {
    665     /* Uses Solaris' role-based access control (RBAC).*/
    666     struct passwd *pPass = getpwuid(getuid());
    667     if (pPass == NULL || chkauthattr("solaris.device.cdrw", pPass->pw_name) == 0)
    668         return VERR_PERMISSION_DENIED;
    669 
    670     return VINF_SUCCESS;
    671 }
    672 
    673 
    674 /**
    675  * Setuid wrapper to gain root access.
    676  *
    677  * @returns VBox error code.
    678  * @param   pEffUserID     Pointer to effective user ID.
    679  */
    680 static int solarisEnterRootMode(uid_t *pEffUserID)
    681 {
    682     /* Increase privilege if required */
    683     if (*pEffUserID != 0)
    684     {
    685         if (seteuid(0) == 0)
    686         {
    687             *pEffUserID = 0;
    688             return VINF_SUCCESS;
    689         }
    690         return VERR_PERMISSION_DENIED;
    691     }
    692     return VINF_SUCCESS;
    693 }
    694 
    695 
    696 /**
    697  * Setuid wrapper to relinquish root access.
    698  *
    699  * @returns VBox error code.
    700  * @param   pEffUserID     Pointer to effective user ID.
    701  */
    702 static int solarisExitRootMode(uid_t *pEffUserID)
    703 {
    704     /* Get back to user mode. */
    705     if (*pEffUserID == 0)
    706     {
    707         uid_t realID = getuid();
    708         if (seteuid(realID) == 0)
    709         {
    710             *pEffUserID = realID;
    711             return VINF_SUCCESS;
    712         }
    713         return VERR_PERMISSION_DENIED;
    714     }
    715     return VINF_SUCCESS;
    716 }
    717 
    718 # endif   /* RT_OS_SOLARIS */
    719 #endif /* VBOX_WITH_SUID_WRAPPER */
    720458
    721459
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