- Timestamp:
- Oct 13, 2016 12:35:30 PM (8 years ago)
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Makefile.kmk
r64239 r64240 201 201 Storage/DrvHostBase-freebsd.cpp 202 202 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 203 212 #VBoxDD_SOURCES.win += Storage/HBDMgmt-win.cpp #Disabled until remaining issues are sorted out 204 213 -
trunk/src/VBox/Devices/Storage/DrvHostBase.h
r64239 r64240 189 189 void DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis); 190 190 DECLCALLBACK(void) DRVHostBaseDestruct(PPDMDRVINS pDrvIns); 191 #if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) 191 192 192 DECLHIDDEN(int) drvHostBaseScsiCmdOs(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMMEDIATXDIR enmTxDir, 193 193 void *pvBuf, uint32_t *pcbBuf, uint8_t *pbSense, size_t cbSense, uint32_t cTimeoutMillies); 194 #endif195 194 196 195 -
trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp
r64239 r64240 118 118 *********************************************************************************************************************************/ 119 119 static DECLCALLBACK(int) drvHostDvdDoLock(PDRVHOSTBASE pThis, bool fLock); 120 120 121 #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 */ 129 static 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 126 139 127 140 /** @interface_method_impl{PDMIMOUNT,pfnUnmount} */ … … 421 434 LogFlow(("%s: cmd[0]=%#04x txdir=%d pcbBuf=%d timeout=%d\n", __FUNCTION__, pbCmd[0], enmTxDir, *pcbBuf, cTimeoutMillies)); 422 435 423 #if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)424 436 /* 425 437 * Pass the request on to the internal scsi command interface. … … 428 440 if (enmTxDir == PDMMEDIATXDIR_FROM_DEVICE) 429 441 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); 431 443 if (rc == VERR_UNRESOLVED_ERROR) 432 444 /* sense information set */ 433 445 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 reading449 * data. The actually received data may be shorter than what450 * we expect, and due to the unreliable feedback about how much451 * data the ioctl actually transferred, it's impossible to452 * prevent that. Returning previous buffer contents may cause453 * security problems inside the guest OS, if users can issue454 * 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 else486 {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 amount503 * of data transferred (for packet commands with little data transfer504 * 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 reading523 * data. The actually received data may be shorter than what524 * we expect, and due to the unreliable feedback about how much525 * data the ioctl actually transferred, it's impossible to526 * prevent that. Returning previous buffer contents may cause527 * security problems inside the guest OS, if users can issue528 * 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_WRAPPER551 uid_t effUserID = geteuid();552 solarisEnterRootMode(&effUserID); /** @todo check return code when this really works. */553 #endif554 rc = ioctl(RTFileToNative(pThis->hFileRawDevice), USCSICMD, &usc);555 #ifdef VBOX_WITH_SUID_WRAPPER556 solarisExitRootMode(&effUserID);557 #endif558 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 _REQ573 {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 reading587 * data. The actually received data may be shorter than what588 * we expect, and due to the unreliable feedback about how much589 * data the ioctl actually transferred, it's impossible to590 * prevent that. Returning previous buffer contents may cause591 * security problems inside the guest OS, if users can issue592 * 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 else620 memset(pabSense, '\0', cbSense);621 /* Windows shares the property of not properly reflecting the actually622 * transferred data size. See above. Assume that everything worked ok.623 * Except if there are sense information. */624 rc = (pabSense[2] & 0x0f) == SCSI_SENSE_NONE625 ? VINF_SUCCESS626 : VERR_DEV_IO_ERROR;627 }628 else629 rc = RTErrConvertFromWin32(GetLastError());630 Log2(("%s: scsistatus=%d bytes returned=%d tlength=%d\n", __FUNCTION__, Req.spt.ScsiStatus, cbReturned, Req.spt.DataTransferLength));631 632 #else633 # error "Unsupported platform."634 #endif635 446 636 447 if (pbCmd[0] == SCSI_GET_EVENT_STATUS_NOTIFICATION) … … 645 456 return rc; 646 457 } 647 648 649 #ifdef VBOX_WITH_SUID_WRAPPER650 /* These functions would have to go into a separate solaris binary with651 * the setuid permission set, which would run the user-SCSI ioctl and652 * return the value. BUT... this might be prohibitively slow.653 */654 # ifdef RT_OS_SOLARIS655 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 need659 * 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 */720 458 721 459
Note:
See TracChangeset
for help on using the changeset viewer.