diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
---|---|---|
committer | <> | 2014-05-08 15:03:54 +0000 |
commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c | |
parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
download | VirtualBox-master.tar.gz |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c')
-rw-r--r-- | src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c | 219 |
1 files changed, 156 insertions, 63 deletions
diff --git a/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c index 80066ce8..6000e9d4 100644 --- a/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c +++ b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c @@ -1,10 +1,10 @@ -/* $Rev: 77635 $ */ +/* $Rev: 87729 $ */ /** @file * VBoxDrv - The VirtualBox Support Driver - Linux specifics. */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -95,14 +95,15 @@ *******************************************************************************/ static int VBoxDrvLinuxInit(void); static void VBoxDrvLinuxUnload(void); -static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp); +static int VBoxDrvLinuxCreateSys(struct inode *pInode, struct file *pFilp); +static int VBoxDrvLinuxCreateUsr(struct inode *pInode, struct file *pFilp); static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp); #ifdef HAVE_UNLOCKED_IOCTL static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg); #else static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg); #endif -static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg); +static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession); static int VBoxDrvLinuxErr2LinuxErr(int); #ifdef VBOX_WITH_SUSPEND_NOTIFICATION static int VBoxDrvProbe(struct platform_device *pDev); @@ -126,20 +127,26 @@ static void VBoxDevRelease(struct device *pDev); static SUPDRVDEVEXT g_DevExt; #ifndef CONFIG_VBOXDRV_AS_MISC -/** Module major number */ -#define DEVICE_MAJOR 234 -/** Saved major device number */ -static int g_iModuleMajor; +/** Module major number for vboxdrv. */ +#define DEVICE_MAJOR_SYS 234 +/** Saved major device number for vboxdrv. */ +static int g_iModuleMajorSys; +/** Module major number for vboxdrvu. */ +#define DEVICE_MAJOR_USR 235 +/** Saved major device number for vboxdrvu. */ +static int g_iModuleMajorUsr; #endif /* !CONFIG_VBOXDRV_AS_MISC */ /** Module parameter. * Not prefixed because the name is used by macros and the end of this file. */ static int force_async_tsc = 0; -/** The module name. */ -#define DEVICE_NAME "vboxdrv" +/** The system device name. */ +#define DEVICE_NAME_SYS "vboxdrv" +/** The user device name. */ +#define DEVICE_NAME_USR "vboxdrvu" -#if defined(RT_ARCH_AMD64) && !defined(CONFIG_DEBUG_SET_MODULE_RONX) +#if defined(RT_ARCH_AMD64) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) /** * Memory for the executable memory heap (in IPRT). */ @@ -155,10 +162,23 @@ __asm__(".section execmemory, \"awx\", @progbits\n\t" #endif /** The file_operations structure. */ -static struct file_operations gFileOpsVBoxDrv = +static struct file_operations gFileOpsVBoxDrvSys = +{ + owner: THIS_MODULE, + open: VBoxDrvLinuxCreateSys, + release: VBoxDrvLinuxClose, +#ifdef HAVE_UNLOCKED_IOCTL + unlocked_ioctl: VBoxDrvLinuxIOCtl, +#else + ioctl: VBoxDrvLinuxIOCtl, +#endif +}; + +/** The file_operations structure. */ +static struct file_operations gFileOpsVBoxDrvUsr = { owner: THIS_MODULE, - open: VBoxDrvLinuxCreate, + open: VBoxDrvLinuxCreateUsr, release: VBoxDrvLinuxClose, #ifdef HAVE_UNLOCKED_IOCTL unlocked_ioctl: VBoxDrvLinuxIOCtl, @@ -168,14 +188,24 @@ static struct file_operations gFileOpsVBoxDrv = }; #ifdef CONFIG_VBOXDRV_AS_MISC -/** The miscdevice structure. */ -static struct miscdevice gMiscDevice = +/** The miscdevice structure for vboxdrv. */ +static struct miscdevice gMiscDeviceSys = { minor: MISC_DYNAMIC_MINOR, - name: DEVICE_NAME, - fops: &gFileOpsVBoxDrv, + name: DEVICE_NAME_SYS, + fops: &gFileOpsVBoxDrvSys, # if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17) - devfs_name: DEVICE_NAME, + devfs_name: DEVICE_NAME_SYS, +# endif +}; +/** The miscdevice structure for vboxdrvu. */ +static struct miscdevice gMiscDeviceUsr = +{ + minor: MISC_DYNAMIC_MINOR, + name: DEVICE_NAME_USR, + fops: &gFileOpsVBoxDrvUsr, +# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17) + devfs_name: DEVICE_NAME_USR, # endif }; #endif @@ -223,7 +253,11 @@ static struct platform_device gPlatformDevice = DECLINLINE(RTUID) vboxdrvLinuxUid(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) + return from_kuid(current_user_ns(), current->cred->uid); +# else return current->cred->uid; +# endif #else return current->uid; #endif @@ -232,7 +266,11 @@ DECLINLINE(RTUID) vboxdrvLinuxUid(void) DECLINLINE(RTGID) vboxdrvLinuxGid(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) + return from_kgid(current_user_ns(), current->cred->gid); +# else return current->cred->gid; +# endif #else return current->gid; #endif @@ -241,7 +279,11 @@ DECLINLINE(RTGID) vboxdrvLinuxGid(void) DECLINLINE(RTUID) vboxdrvLinuxEuid(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) + return from_kuid(current_user_ns(), current->cred->euid); +# else return current->cred->euid; +# endif #else return current->euid; #endif @@ -259,40 +301,60 @@ static int __init VBoxDrvLinuxInit(void) /* * Check for synchronous/asynchronous TSC mode. */ - printk(KERN_DEBUG DEVICE_NAME ": Found %u processor cores.\n", (unsigned)RTMpGetOnlineCount()); + printk(KERN_DEBUG "vboxdrv: Found %u processor cores.\n", (unsigned)RTMpGetOnlineCount()); #ifdef CONFIG_VBOXDRV_AS_MISC - rc = misc_register(&gMiscDevice); + rc = misc_register(&gMiscDeviceSys); + if (rc) + { + printk(KERN_ERR "vboxdrv: Can't register system misc device! rc=%d\n", rc); + return rc; + } + rc = misc_register(&gMiscDeviceUsr); if (rc) { - printk(KERN_ERR DEVICE_NAME ": Can't register misc device! rc=%d\n", rc); + printk(KERN_ERR "vboxdrv: Can't register user misc device! rc=%d\n", rc); + misc_deregister(&gMiscDeviceSys); return rc; } #else /* !CONFIG_VBOXDRV_AS_MISC */ /* - * Register character device. + * Register character devices and save the returned major numbers. */ - g_iModuleMajor = DEVICE_MAJOR; - rc = register_chrdev((dev_t)g_iModuleMajor, DEVICE_NAME, &gFileOpsVBoxDrv); + /* /dev/vboxdrv */ + g_iModuleMajorSys = DEVICE_MAJOR_SYS; + rc = register_chrdev((dev_t)g_iModuleMajorSys, DEVICE_NAME_SYS, &gFileOpsVBoxDrvSys); if (rc < 0) { - Log(("register_chrdev() failed with rc=%#x!\n", rc)); + Log(("register_chrdev() failed with rc=%#x for vboxdrv!\n", rc)); return rc; } + if (DEVICE_MAJOR_SYS != 0) + g_iModuleMajorSys = DEVICE_MAJOR_SYS; + else + g_iModuleMajorSys = rc; - /* - * Save returned module major number - */ - if (DEVICE_MAJOR != 0) - g_iModuleMajor = DEVICE_MAJOR; + /* /dev/vboxdrvu */ + /** @todo Use a minor number of this bugger (not sure if this code is used + * though, so not bothering right now.) */ + g_iModuleMajorUsr = DEVICE_MAJOR_USR; + rc = register_chrdev((dev_t)g_iModuleMajorUsr, DEVICE_NAME_USR, &gFileOpsVBoxDrvUsr); + if (rc < 0) + { + Log(("register_chrdev() failed with rc=%#x for vboxdrv!\n", rc)); + return rc; + } + if (DEVICE_MAJOR_USR != 0) + g_iModuleMajorUsr = DEVICE_MAJOR_USR; else - g_iModuleMajor = rc; + g_iModuleMajorUsr = rc; rc = 0; # ifdef CONFIG_DEVFS_FS /* * Register a device entry */ - if (devfs_mk_cdev(MKDEV(DEVICE_MAJOR, 0), S_IFCHR | VBOX_DEV_FMASK, DEVICE_NAME) != 0) + if ( devfs_mk_cdev(MKDEV(DEVICE_MAJOR_SYS, 0), S_IFCHR | VBOX_DEV_FMASK, DEVICE_NAME_SYS) != 0 + || devfs_mk_cdev(MKDEV(DEVICE_MAJOR_USR, 0), S_IFCHR | VBOX_DEV_FMASK, DEVICE_NAME_USR) != 0) { Log(("devfs_register failed!\n")); rc = -EINVAL; @@ -329,10 +391,10 @@ static int __init VBoxDrvLinuxInit(void) if (rc == 0) #endif { - printk(KERN_INFO DEVICE_NAME ": TSC mode is %s, kernel timer mode is 'normal'.\n", + printk(KERN_INFO "vboxdrv: TSC mode is %s, kernel timer mode is 'normal'.\n", g_DevExt.pGip->u32Mode == SUPGIPMODE_SYNC_TSC ? "'synchronous'" : "'asynchronous'"); LogFlow(("VBoxDrv::ModuleInit returning %#x\n", rc)); - printk(KERN_DEBUG DEVICE_NAME ": Successfully loaded version " + printk(KERN_DEBUG "vboxdrv: Successfully loaded version " VBOX_VERSION_STRING " (interface " RT_XSTR(SUPDRV_IOC_VERSION) ").\n"); return rc; } @@ -353,15 +415,18 @@ static int __init VBoxDrvLinuxInit(void) * Failed, cleanup and return the error code. */ #if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC) - devfs_remove(DEVICE_NAME); + devfs_remove(DEVICE_NAME_SYS); + devfs_remove(DEVICE_NAME_USR); #endif } #ifdef CONFIG_VBOXDRV_AS_MISC - misc_deregister(&gMiscDevice); - Log(("VBoxDrv::ModuleInit returning %#x (minor:%d)\n", rc, gMiscDevice.minor)); + misc_deregister(&gMiscDeviceSys); + misc_deregister(&gMiscDeviceUsr); + Log(("VBoxDrv::ModuleInit returning %#x (minor:%d & %d)\n", rc, gMiscDeviceSys.minor, gMiscDeviceUsr.minor)); #else - unregister_chrdev(g_iModuleMajor, DEVICE_NAME); - Log(("VBoxDrv::ModuleInit returning %#x (major:%d)\n", rc, g_iModuleMajor)); + unregister_chrdev(g_iModuleMajorUsr, DEVICE_NAME_USR); + unregister_chrdev(g_iModuleMajorSys, DEVICE_NAME_SYS); + Log(("VBoxDrv::ModuleInit returning %#x (major:%d & %d)\n", rc, g_iModuleMajorSys, g_iModuleMajorUsr)); #endif return rc; } @@ -386,19 +451,26 @@ static void __exit VBoxDrvLinuxUnload(void) * opened, at least we'll blindly assume that here. */ #ifdef CONFIG_VBOXDRV_AS_MISC - rc = misc_deregister(&gMiscDevice); + rc = misc_deregister(&gMiscDeviceUsr); + if (rc < 0) + { + Log(("misc_deregister failed with rc=%#x on vboxdrvu\n", rc)); + } + rc = misc_deregister(&gMiscDeviceSys); if (rc < 0) { - Log(("misc_deregister failed with rc=%#x\n", rc)); + Log(("misc_deregister failed with rc=%#x on vboxdrv\n", rc)); } #else /* !CONFIG_VBOXDRV_AS_MISC */ # ifdef CONFIG_DEVFS_FS /* * Unregister a device entry */ - devfs_remove(DEVICE_NAME); + devfs_remove(DEVICE_NAME_USR); + devfs_remove(DEVICE_NAME_SYS); # endif /* devfs */ - unregister_chrdev(g_iModuleMajor, DEVICE_NAME); + unregister_chrdev(g_iModuleMajorUsr, DEVICE_NAME_USR); + unregister_chrdev(g_iModuleMajorSys, DEVICE_NAME_SYS); #endif /* !CONFIG_VBOXDRV_AS_MISC */ /* @@ -410,12 +482,13 @@ static void __exit VBoxDrvLinuxUnload(void) /** - * Device open. Called on open /dev/vboxdrv + * Common open code. * - * @param pInode Pointer to inode info structure. - * @param pFilp Associated file pointer. + * @param pInode Pointer to inode info structure. + * @param pFilp Associated file pointer. + * @param fUnrestricted Indicates which device node which was opened. */ -static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp) +static int vboxdrvLinuxCreateCommon(struct inode *pInode, struct file *pFilp, bool fUnrestricted) { int rc; PSUPDRVSESSION pSession; @@ -423,9 +496,10 @@ static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp) #ifdef VBOX_WITH_HARDENING /* - * Only root is allowed to access the device, enforce it! + * Only root is allowed to access the unrestricted device, enforce it! */ - if (vboxdrvLinuxEuid() != 0 /* root */ ) + if ( fUnrestricted + && vboxdrvLinuxEuid() != 0 /* root */ ) { Log(("VBoxDrvLinuxCreate: euid=%d, expected 0 (root)\n", vboxdrvLinuxEuid())); return -EPERM; @@ -435,7 +509,7 @@ static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp) /* * Call common code for the rest. */ - rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession); + rc = supdrvCreateSession(&g_DevExt, true /* fUser */, fUnrestricted, &pSession); if (!rc) { pSession->Uid = vboxdrvLinuxUid(); @@ -451,6 +525,20 @@ static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp) } +/** /dev/vboxdrv. */ +static int VBoxDrvLinuxCreateSys(struct inode *pInode, struct file *pFilp) +{ + return vboxdrvLinuxCreateCommon(pInode, pFilp, true); +} + + +/** /dev/vboxdrvu. */ +static int VBoxDrvLinuxCreateUsr(struct inode *pInode, struct file *pFilp) +{ + return vboxdrvLinuxCreateCommon(pInode, pFilp, false); +} + + /** * Close device. * @@ -461,7 +549,7 @@ static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp) { Log(("VBoxDrvLinuxClose: pFilp=%p pSession=%p pid=%d/%d %s\n", pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm)); - supdrvCloseSession(&g_DevExt, (PSUPDRVSESSION)pFilp->private_data); + supdrvSessionRelease((PSUPDRVSESSION)pFilp->private_data); pFilp->private_data = NULL; return 0; } @@ -533,27 +621,31 @@ static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned lo static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg) #endif { + PSUPDRVSESSION pSession = (PSUPDRVSESSION)pFilp->private_data; + /* * Deal with the two high-speed IOCtl that takes it's arguments from * the session and iCmd, and only returns a VBox status code. */ #ifdef HAVE_UNLOCKED_IOCTL - if (RT_LIKELY( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN - || uCmd == SUP_IOCTL_FAST_DO_HWACC_RUN - || uCmd == SUP_IOCTL_FAST_DO_NOP)) - return supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data); - return VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg); + if (RT_LIKELY( ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN + || uCmd == SUP_IOCTL_FAST_DO_HM_RUN + || uCmd == SUP_IOCTL_FAST_DO_NOP) + && pSession->fUnrestricted == true)) + return supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, pSession); + return VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession); #else /* !HAVE_UNLOCKED_IOCTL */ int rc; unlock_kernel(); - if (RT_LIKELY( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN - || uCmd == SUP_IOCTL_FAST_DO_HWACC_RUN - || uCmd == SUP_IOCTL_FAST_DO_NOP)) - rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data); + if (RT_LIKELY( ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN + || uCmd == SUP_IOCTL_FAST_DO_HM_RUN + || uCmd == SUP_IOCTL_FAST_DO_NOP) + && pSession->fUnrestricted == true)) + rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, pSession); else - rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg); + rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession); lock_kernel(); return rc; #endif /* !HAVE_UNLOCKED_IOCTL */ @@ -566,8 +658,9 @@ static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned * @param pFilp Associated file pointer. * @param uCmd The function specified to ioctl(). * @param ulArg The argument specified to ioctl(). + * @param pSession The session instance. */ -static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg) +static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession) { int rc; SUPREQHDR Hdr; @@ -620,7 +713,7 @@ static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned /* * Process the IOCtl. */ - rc = supdrvIOCtl(uCmd, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data, pHdr); + rc = supdrvIOCtl(uCmd, &g_DevExt, pSession, pHdr); /* * Copy ioctl data and output buffer back to user space. |