struct buf * geteblk_special(size_t size, uint32_t control) { struct proc_info * proc = proc_ref(0); const uintptr_t kvaddr = get_ksect_addr(size); struct buf * buf; int err; KASSERT(proc, "Can't get the PCB of pid 0"); proc_unref(proc); if (kvaddr == 0) { KERROR_DBG("Returned kvaddr is NULL\n"); return NULL; } buf = vm_newsect(kvaddr, size, VM_PROT_READ | VM_PROT_WRITE); if (!buf) { KERROR_DBG("vm_newsect() failed\n"); return NULL; } buf->b_mmu.control = control; err = vm_insert_region(proc, buf, VM_INSOP_MAP_REG); if (err < 0) { panic("Mapping a kernel special buffer failed"); } buf->b_data = buf->b_mmu.vaddr; /* Should be same as kvaddr */ return buf; }
/** * 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. */ if (!(fFlags & FKLYR)) rc = VGDrvCommonCreateUserSession(&g_DevExt, &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; }
static void mount_tmp_rootfs(void) { const char failed[] = "Failed to mount rootfs"; vnode_t * tmp = NULL; struct proc_info * kernel_proc; int ret; kernel_proc = proc_ref(0); if (!kernel_proc) { panic(failed); } /* No need to keep the ref because it won't go away. */ proc_unref(kernel_proc); /* Root dir */ tmp = kzalloc_crit(sizeof(vnode_t)); kernel_proc->croot = tmp; kernel_proc->croot->vn_next_mountpoint = kernel_proc->croot; kernel_proc->croot->vn_prev_mountpoint = kernel_proc->croot; mtx_init(&tmp->vn_lock, MTX_TYPE_SPIN, 0); vrefset(kernel_proc->croot, 2); ret = fs_mount(kernel_proc->croot, "", "ramfs", 0, "", 1); if (ret) { KERROR(KERROR_ERR, "%s : %i\n", failed, ret); goto out; } kernel_proc->croot->vn_next_mountpoint->vn_prev_mountpoint = kernel_proc->croot->vn_next_mountpoint; kernel_proc->croot = kernel_proc->croot->vn_next_mountpoint; kernel_proc->cwd = kernel_proc->croot; out: kfree(tmp); }
static pthread_t create_uinit_main(void * stack_addr) { struct _sched_pthread_create_args init_ds = { .param.sched_policy = SCHED_OTHER, .param.sched_priority = NZERO, .stack_addr = stack_addr, .stack_size = configUSRINIT_SSIZE, .flags = 0, .start = uinit, /* We have to first get into user space to use exec * and mount the rootfs. */ .arg1 = (uintptr_t)rootfs, .del_thread = (void (*)(void *))uinit_exit, }; return thread_create(&init_ds, THREAD_MODE_PRIV); } /** * Map vmstack to proc. */ static void map_vmstack2proc(struct proc_info * proc, struct buf * vmstack) { struct vm_pt * vpt; (*proc->mm.regions)[MM_STACK_REGION] = vmstack; vm_updateusr_ap(vmstack); vpt = ptlist_get_pt(&proc->mm, vmstack->b_mmu.vaddr, MMU_PGSIZE_COARSE, VM_PT_CREAT); if (vpt == 0) panic("Couldn't get vpt for init stack"); vmstack->b_mmu.pt = &(vpt->pt); vm_map_region(vmstack, vpt); } /** * Create init process. */ int __kinit__ kinit(void) { SUBSYS_DEP(sched_init); SUBSYS_DEP(proc_init); SUBSYS_DEP(ramfs_init); SUBSYS_DEP(sysctl_init); SUBSYS_INIT("kinit"); char strbuf[80]; /* Buffer for panic messages. */ struct buf * init_vmstack; pthread_t tid; pid_t pid; struct thread_info * init_thread; struct proc_info * init_proc; /* * FIXME Memory allocation, protection or manipulation bug! * There is a critical bug causing random crashes in userland. I suspect * something is overwriting user space allocation from the kernel space. * Allocating some memory before init is executed seems to fix this issue, * however naturally this is not the proper way to fix the bug. * Without the allocation here the issue is sometimes seen in init or * usually after couple of fork + exec + exit cycles. The usual symptom is * that the userland app first calls some 0:0 syscalls and then tries to * execute undefined instruction, which probably means that either some * jump table in the heap or some part of the executable code is modified * by a bad access in kernel mode just before this happens. */ (void)geteblk(MMU_PGSIZE_COARSE * 10); mount_tmp_rootfs(); /* * User stack for init */ init_vmstack = create_vmstack(); if (!init_vmstack) panic("Can't allocate a stack for init"); /* * Create a thread for init */ tid = create_uinit_main((void *)(init_vmstack->b_mmu.paddr)); if (tid < 0) { ksprintf(strbuf, sizeof(strbuf), "Can't create a thread for init. %i", tid); panic(strbuf); } /* * pid of init */ pid = proc_fork(); if (pid <= 0) { ksprintf(strbuf, sizeof(strbuf), "Can't fork a process for init. %i", pid); panic(strbuf); } init_thread = thread_lookup(tid); if (!init_thread) { panic("Can't get thread descriptor of init_thread!"); } init_proc = proc_ref(pid); if (!init_proc || (init_proc->state == PROC_STATE_INITIAL)) { panic("Failed to get proc struct or invalid struct"); } init_thread->pid_owner = pid; init_thread->curr_mpt = &init_proc->mm.mpt; /* * Map the previously created user stack with init process page table. */ map_vmstack2proc(init_proc, init_vmstack); /* * Map tkstack of init with vm_pagetable_system. */ mmu_map_region(&init_thread->kstack_region->b_mmu); init_proc->main_thread = init_thread; KERROR_DBG("Init created with pid: %u, tid: %u, stack: %p\n", pid, tid, (void *)init_vmstack->b_mmu.vaddr); proc_unref(init_proc); return 0; }
/** * 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; }