Exemple #1
0
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;
}
Exemple #3
0
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);
}
Exemple #4
0
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;
}