/** * User context entry points * * @remarks fFlags are the flags passed to open() or to ldi_open_by_name. In * the latter case the FKLYR flag is added to indicate that the caller * is a kernel component rather than user land. */ static int vgdrvSolarisOpen(dev_t *pDev, int fFlags, int fType, cred_t *pCred) { int rc; PVBOXGUESTSESSION pSession = NULL; LogFlow(("vgdrvSolarisOpen:\n")); /* * Verify we are being opened as a character device. */ if (fType != OTYP_CHR) return EINVAL; vboxguest_state_t *pState = NULL; unsigned iOpenInstance; for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++) { if ( !ddi_get_soft_state(g_pvgdrvSolarisState, iOpenInstance) /* faster */ && ddi_soft_state_zalloc(g_pvgdrvSolarisState, iOpenInstance) == DDI_SUCCESS) { pState = ddi_get_soft_state(g_pvgdrvSolarisState, iOpenInstance); break; } } if (!pState) { Log(("vgdrvSolarisOpen: too many open instances.")); return ENXIO; } /* * Create a new session. * * Note! The devfs inode with the gid isn't readily available here, so we cannot easily * to the vbox group detection like on linux. Read config instead? */ if (!(fFlags & FKLYR)) { uint32_t fRequestor = VMMDEV_REQUESTOR_USERMODE | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN; if (crgetruid(pCred) == 0) fRequestor |= VMMDEV_REQUESTOR_USR_ROOT; else fRequestor |= VMMDEV_REQUESTOR_USR_USER; if (secpolicy_coreadm(pCred) == 0) fRequestor |= VMMDEV_REQUESTOR_GRP_WHEEL; /** @todo is there any way of detecting that the process belongs to someone on the physical console? * secpolicy_console() [== PRIV_SYS_DEVICES] doesn't look quite right, or does it? */ fRequestor |= VMMDEV_REQUESTOR_CON_DONT_KNOW; fRequestor |= VMMDEV_REQUESTOR_NO_USER_DEVICE; /** @todo implement vboxuser device node. */ rc = VGDrvCommonCreateUserSession(&g_DevExt, fRequestor, &pSession); } else rc = VGDrvCommonCreateKernelSession(&g_DevExt, &pSession); if (RT_SUCCESS(rc)) { if (!(fFlags & FKLYR)) pState->pvProcRef = proc_ref(); else pState->pvProcRef = NULL; pState->pSession = pSession; *pDev = makedevice(getmajor(*pDev), iOpenInstance); Log(("vgdrvSolarisOpen: pSession=%p pState=%p pid=%d\n", pSession, pState, (int)RTProcSelf())); return 0; } /* Failed, clean up. */ ddi_soft_state_free(g_pvgdrvSolarisState, iOpenInstance); LogRel((DEVICE_NAME "::Open: VGDrvCommonCreateUserSession failed. rc=%d\n", rc)); return EFAULT; }
int corectl(int subcode, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) { int error = 0; proc_t *p; refstr_t *rp; size_t size; char *path; core_content_t content = CC_CONTENT_INVALID; struct core_globals *cg; zone_t *zone = curproc->p_zone; cg = zone_getspecific(core_zone_key, zone); ASSERT(cg != NULL); switch (subcode) { case CC_SET_OPTIONS: if ((error = secpolicy_coreadm(CRED())) == 0) { if (arg1 & ~CC_OPTIONS) error = EINVAL; else cg->core_options = (uint32_t)arg1; } break; case CC_GET_OPTIONS: return (cg->core_options); case CC_GET_GLOBAL_PATH: case CC_GET_DEFAULT_PATH: case CC_GET_PROCESS_PATH: if (subcode == CC_GET_GLOBAL_PATH) { mutex_enter(&cg->core_lock); if ((rp = cg->core_file) != NULL) refstr_hold(rp); mutex_exit(&cg->core_lock); } else if (subcode == CC_GET_DEFAULT_PATH) { rp = corectl_path_value(cg->core_default_path); } else { rp = NULL; mutex_enter(&pidlock); if ((p = prfind((pid_t)arg3)) == NULL || p->p_stat == SIDL) { mutex_exit(&pidlock); error = ESRCH; } else { mutex_enter(&p->p_lock); mutex_exit(&pidlock); mutex_enter(&p->p_crlock); if (!hasprocperm(p->p_cred, CRED())) error = EPERM; else if (p->p_corefile != NULL) rp = corectl_path_value(p->p_corefile); mutex_exit(&p->p_crlock); mutex_exit(&p->p_lock); } } if (rp == NULL) { if (error == 0 && suword8((void *)arg1, 0)) error = EFAULT; } else { error = copyoutstr(refstr_value(rp), (char *)arg1, (size_t)arg2, NULL); refstr_rele(rp); } break; case CC_SET_GLOBAL_PATH: case CC_SET_DEFAULT_PATH: if ((error = secpolicy_coreadm(CRED())) != 0) break; /* FALLTHROUGH */ case CC_SET_PROCESS_PATH: if ((size = MIN((size_t)arg2, MAXPATHLEN)) == 0) { error = EINVAL; break; } path = kmem_alloc(size, KM_SLEEP); error = copyinstr((char *)arg1, path, size, NULL); if (error == 0) { if (subcode == CC_SET_PROCESS_PATH) { error = set_proc_info((pid_t)arg3, path, 0); } else if (subcode == CC_SET_DEFAULT_PATH) { corectl_path_set(cg->core_default_path, path); } else if (*path != '\0' && *path != '/') { error = EINVAL; } else { refstr_t *nrp = refstr_alloc(path); mutex_enter(&cg->core_lock); rp = cg->core_file; if (*path == '\0') cg->core_file = NULL; else refstr_hold(cg->core_file = nrp); mutex_exit(&cg->core_lock); if (rp != NULL) refstr_rele(rp); refstr_rele(nrp); } } kmem_free(path, size); break; case CC_SET_GLOBAL_CONTENT: case CC_SET_DEFAULT_CONTENT: if ((error = secpolicy_coreadm(CRED())) != 0) break; /* FALLTHROUGH */ case CC_SET_PROCESS_CONTENT: error = copyin((void *)arg1, &content, sizeof (content)); if (error != 0) break; /* * If any unknown bits are set, don't let this charade * continue. */ if (content & ~CC_CONTENT_ALL) { error = EINVAL; break; } if (subcode == CC_SET_PROCESS_CONTENT) { error = set_proc_info((pid_t)arg2, NULL, content); } else if (subcode == CC_SET_DEFAULT_CONTENT) { corectl_content_set(cg->core_default_content, content); } else { mutex_enter(&cg->core_lock); cg->core_content = content; mutex_exit(&cg->core_lock); } break; case CC_GET_GLOBAL_CONTENT: content = cg->core_content; error = copyout(&content, (void *)arg1, sizeof (content)); break; case CC_GET_DEFAULT_CONTENT: content = corectl_content_value(cg->core_default_content); error = copyout(&content, (void *)arg1, sizeof (content)); break; case CC_GET_PROCESS_CONTENT: mutex_enter(&pidlock); if ((p = prfind((pid_t)arg2)) == NULL || p->p_stat == SIDL) { mutex_exit(&pidlock); error = ESRCH; break; } mutex_enter(&p->p_lock); mutex_exit(&pidlock); mutex_enter(&p->p_crlock); if (!hasprocperm(p->p_cred, CRED())) error = EPERM; else if (p->p_content == NULL) content = CC_CONTENT_NONE; else content = corectl_content_value(p->p_content); mutex_exit(&p->p_crlock); mutex_exit(&p->p_lock); if (error == 0) error = copyout(&content, (void *)arg1, sizeof (content)); break; default: error = EINVAL; break; } if (error) return (set_errno(error)); return (0); }