Beispiel #1
0
static void
kerext_process_startup(void *data) {
	struct kerargs_process_startup *kap = data;
	THREAD						*act = actives[KERNCPU];
	PROCESS						*prp;
	struct _cred_info			info;
	void						*lcp;
	
	if((prp = lookup_pid(kap->pid)) == NULL || (prp->flags & _NTO_PF_LOADING) == 0) {
		kererr(act, ESRCH);
		return;
	}

	lcp = prp->lcp;

	if(kap->start) {
		int							status;
		uintptr_t					start_ip;
		THREAD						*thp;

		status = procmgr.process_start ? procmgr.process_start(prp, &start_ip) : ENOSYS;
		if(status != EOK) {
			kererr(act, status);
			return;
		}

		lock_kernel();

		info = prp->cred->info;
		info.suid = info.euid;
		info.sgid = info.egid;
		cred_set(&prp->cred, &info);
		thp = prp->valid_thp;
		if(!(prp->flags & _NTO_PF_FORKED)) {
			SETKIP_FUNC(thp, start_ip);
			SETKSP(thp, prp->initial_esp);
		}
		cpu_process_startup(thp, prp->flags & _NTO_PF_FORKED);
		_TRACE_NOARGS(thp);

		/* @@@ This should be examined in more detail later!!! */
		prp->boundry_addr = WITHIN_BOUNDRY(prp->initial_esp, prp->initial_esp, user_boundry_addr) ? user_boundry_addr : VM_KERN_SPACE_BOUNDRY;
		prp->flags &= ~(_NTO_PF_LOADING | _NTO_PF_RING0);
		prp->lcp = 0;
		_TRACE_PR_EMIT_CREATE_NAME(prp);
	}

	lock_kernel();
	SETKSTATUS(act, lcp);
}
Beispiel #2
0
static void
kerext_process_create(void *data) {
	struct kerargs_process_create *kap = data;
	pid_t							pid;
	PROCESS							*prp, *parent;
	THREAD							*act = actives[KERNCPU];
	int								status, i;
	struct _cred_info				info;

	if((parent = lookup_pid(kap->parent_pid)) == NULL) {
		kererr(act, ESRCH);
		return;
	}

	if (parent->num_processes >= parent->rlimit_vals_soft[RLIMIT_NPROC]) {
		kererr(act, EAGAIN);
		return;
	}

	lock_kernel();

	// Check that we haven't run out of process vector entries
	// The process index & PID_MASK should never be all zeros
	// or all ones. All ones could cause SYNC_*() to return
	// valid looking numbers from an uninitialized sync.
	if((process_vector.nentries - process_vector.nfree) >= PID_MASK - 1) {
		kererr(act, EAGAIN);
		return;
	}

	// Alloc a process entry.
	if((prp = object_alloc(NULL, &process_souls)) == NULL) {
		kererr(act, ENOMEM);
		return;
	}

	if(kap->parent_pid) {
		prp->flags = _NTO_PF_LOADING | _NTO_PF_NOZOMBIE | _NTO_PF_RING0;
		prp->lcp = kap->lcp;
	}
	snap_time(&prp->start_time, 1);

	MUTEX_INIT(prp, &prp->mpartlist_lock);
	MUTEX_INIT(prp, &prp->spartlist_lock);

	CRASHCHECK((kap->extra == NULL) || (kap->extra->mpart_list == NULL) || 
				((kap->extra->spart_list == NULL) && SCHEDPART_INSTALLED()));
	{
		part_list_t  *mpart_list = kap->extra->mpart_list;
		part_list_t  *spart_list = kap->extra->spart_list;

		/* first thing is to associate with all specified partitions */
		for (i=0; i<mpart_list->num_entries; i++)
		{
			if ((status = MEMPART_ASSOCIATE(prp, mpart_list->i[i].id, mpart_list->i[i].flags)) != EOK)
			{
				(void)MEMPART_DISASSOCIATE(prp, part_id_t_INVALID);
				(void)MUTEX_DESTROY(prp, &prp->mpartlist_lock);
				(void)MUTEX_DESTROY(prp, &prp->spartlist_lock);
				object_free(NULL, &process_souls, prp);
				kererr(act, status);
				return;
			}
		}
		if (SCHEDPART_INSTALLED())
		{
			for (i=0; i<spart_list->num_entries; i++)
			{
				if ((status = SCHEDPART_ASSOCIATE(prp, spart_list->i[i].id, spart_list->i[i].flags)) != EOK)
				{
					(void)MEMPART_DISASSOCIATE(prp, part_id_t_INVALID);
					(void)MUTEX_DESTROY(prp, &prp->mpartlist_lock);
					(void)MUTEX_DESTROY(prp, &prp->spartlist_lock);
					object_free(NULL, &process_souls, prp);
					kererr(act, status);
					return;
				}
			}
		}
	}

	// Allocate a vector for 1 thread but don't get a thread entry.
	if(vector_add(&prp->threads, NULL, 1) == -1) {
		(void)SCHEDPART_DISASSOCIATE(prp, part_id_t_INVALID);
		(void)MEMPART_DISASSOCIATE(prp, part_id_t_INVALID);
		(void)MUTEX_DESTROY(prp, &prp->mpartlist_lock);
		(void)MUTEX_DESTROY(prp, &prp->spartlist_lock);
		object_free(NULL, &process_souls, prp);
		kererr(act, ENOMEM);
		return;
	}

	// Add process to the process table vector.
	if((pid = vector_add(&process_vector, prp, 0)) == -1) {
		(void)SCHEDPART_DISASSOCIATE(prp, part_id_t_INVALID);
		(void)MEMPART_DISASSOCIATE(prp, part_id_t_INVALID);
		(void)MUTEX_DESTROY(prp, &prp->mpartlist_lock);
		(void)MUTEX_DESTROY(prp, &prp->spartlist_lock);
		vector_free(&prp->threads);
		object_free(NULL, &process_souls, prp);
		kererr(act, ENOMEM);
		return;
	}

	prp->boundry_addr = VM_KERN_SPACE_BOUNDRY;
	prp->pid = pid | pid_unique; 	// adjust pid_unique during process destroy
	SIGMASK_SPECIAL(&prp->sig_queue);

	// Call out to allow memory manager to initialize the address space
	if((status = memmgr.mcreate(prp)) != EOK) {
		(void)SCHEDPART_DISASSOCIATE(prp, part_id_t_INVALID);
		(void)MEMPART_DISASSOCIATE(prp, part_id_t_INVALID);
		(void)MUTEX_DESTROY(prp, &prp->mpartlist_lock);
		(void)MUTEX_DESTROY(prp, &prp->spartlist_lock);
		vector_rem(&process_vector, PINDEX(pid));
		vector_free(&prp->threads);
		object_free(NULL, &process_souls, prp);
		kererr(act, status);
		return;
	}

	// Inherit parents information
	info = parent->cred->info;
	info.sgid = parent->cred->info.egid;
	info.suid = 0;			// The loader will set to euid after loading...
	cred_set(&prp->cred, &info);
	prp->seq = 1;

	// inherit setrlimit/getrlimit settings 
	for(i=0; i < RLIM_NLIMITS; i++) {
		prp->rlimit_vals_soft[i] = parent->rlimit_vals_soft[i];
		prp->rlimit_vals_hard[i] = parent->rlimit_vals_hard[i];
	}
	prp->max_cpu_time = parent->max_cpu_time;

	// stop core file generation if RLIMIT_CORE is 0
	if (prp->rlimit_vals_soft[RLIMIT_CORE] == 0) {
		prp->flags |= _NTO_PF_NOCOREDUMP;
	}

	// Inherit default scheduling partition
	// from creating thread.
	prp->default_dpp = SELECT_DPP(act, prp, schedpart_getid(prp));

	prp->pgrp = parent->pgrp;
	prp->umask = parent->umask;
	prp->sig_ignore = parent->sig_ignore;
	SIGMASK_NO_KILLSTOP(&prp->sig_ignore);

	if((prp->limits = lookup_limits(parent->cred->info.euid))  ||
	   (prp->limits = parent->limits)) {
		prp->limits->links++;
	}

	if((prp->session = parent->session)) {
		atomic_add(&prp->session->links, 1);
	}

	// Link the new process in as a child of its creator.
	prp->child = NULL;
	prp->parent = parent;
	prp->sibling = parent->child;
	parent->child = prp;
	++parent->num_processes;
	_TRACE_PR_EMIT_CREATE(prp);
	SETKSTATUS(act, prp);
}
Beispiel #3
0
static void
kerext_process_destroy(void *data) {
	PROCESS		*prp, *parent, *child;
	pid_t		pid = (pid_t)data;
	THREAD		*act = actives[KERNCPU];

	lock_kernel();

	if(!(prp = vector_lookup(&process_vector, PINDEX(pid)))) {
		kererr(act, ESRCH);
		return;
	}

	if(prp->querying) {
		// Some proc thread is looking at the process fields
		// (a QueryOject() has been done on it). We have to wait
		// before we can destroy the process and free the memory
		SETKSTATUS(act, 0);
		return;
	}

	_TRACE_PR_EMIT_DESTROY(prp, pid);

	// retarget all children to PROC
	if((child = prp->child)) {
		PROCESS		*proc = sysmgr_prp;

		do {
			//Loop might take a while - give intr queue a chance to drain.
			KEREXT_PREEMPT(act);

			prp->child = child->sibling;
			if(procmgr.process_threads_destroyed) {
				if (((child->flags & (_NTO_PF_LOADING | _NTO_PF_TERMING | _NTO_PF_ZOMBIE)) == _NTO_PF_ZOMBIE) || (child->flags & _NTO_PF_NOZOMBIE)) {
				struct sigevent		ev;

				child->flags &= ~(_NTO_PF_ZOMBIE | _NTO_PF_WAITINFO);
				(*procmgr.process_threads_destroyed)(child, &ev);
				sigevent_proc(&ev);
				}
			}
			child->parent = proc;
			child->sibling = proc->child;
			proc->child = child;
			--prp->num_processes; ++proc->num_processes;
		} while((child = prp->child));
	}

	vector_rem(&process_vector, PINDEX(pid));

	// Remove the thread vector
	if(prp->threads.nentries && prp->threads.nentries == prp->threads.nfree)
		vector_free(&prp->threads);

	// Remove the timer vector
	if(prp->timers.nentries && prp->timers.nentries == prp->timers.nfree)
		vector_free(&prp->timers);

	// Remove the fd vector
	if(prp->fdcons.nentries && prp->fdcons.nentries == prp->fdcons.nfree)
		vector_free(&prp->fdcons);

	// Remove the channel vector
	if(prp->chancons.nentries && prp->chancons.nentries == prp->chancons.nfree)
		vector_free(&prp->chancons);

	// Unlink the credential
	if(prp->cred) {
		cred_set(&prp->cred, NULL);
	}

	// undo all session stuff
	if(prp->session && atomic_sub_value(&prp->session->links, 1) == 1) {
		_sfree(prp->session, sizeof *prp->session);
	}
	prp->session = 0;

	// Unlink the limits
	if(prp->limits  &&  --prp->limits->links == 0) {
		LINK1_REM(limits_list, prp->limits, LIMITS);
		object_free(NULL, &limits_souls, prp->limits);
	}

	if(prp->limits  &&  prp->limits->links == ~0U) crash();
	if(prp->pid)				crash();
	if(prp->cred)				crash();
	if(prp->alarm)				crash();
	if(pril_first(&prp->sig_pending))		crash();
	if(prp->sig_table)			crash();
	if(prp->nfds)				crash();
	if(prp->chancons.vector)	crash();
	if(prp->fdcons.vector)		crash();
	if(prp->threads.vector)		crash();
	if(prp->timers.vector)		crash();
	if(prp->memory)				crash();
	if(prp->join_queue)			crash();
//	if(prp->session)			crash();
	if(prp->debugger)			crash();
	if(prp->lock)				crash();
	if(prp->num_active_threads)	crash();
	if(prp->vfork_info)			crash();
// FIX ME - this is not NULL now ... why?	if(prp->rsrc_list)			crash();
	if(prp->conf_table)			crash();

	// Unlink from parent
	parent = prp->parent;
	--parent->num_processes;
	if(prp == parent->child) {
		parent->child = prp->sibling;
	} else {
		for(parent = parent->child ; parent ; parent = parent->sibling) {
			if(parent->sibling == prp) {
				parent->sibling = prp->sibling;
				break;
			}
		}
	}

	//Keep pids as positive numbers
	pid_unique = (pid_unique + (PID_MASK + 1)) & INT_MAX;

	/* diassociate prp from all partitions */
/*
	apparently prp->pid gets looked at even though we are about to
	object_free(prp).
	prp->pid = pid;	// stick it back in so we have the info for the disassociate event
*/
	(void)SCHEDPART_DISASSOCIATE(prp, part_id_t_INVALID);
	(void)MEMPART_DISASSOCIATE(prp, part_id_t_INVALID);
	(void)MUTEX_DESTROY(prp, &prp->mpartlist_lock);
	(void)MUTEX_DESTROY(prp, &prp->spartlist_lock);
		
	CRASHCHECK(prp->mpart_list.vector != NULL);
	CRASHCHECK(prp->spart_list != NULL);	// no vector for sched partitions since only 1

	object_free(NULL, &process_souls, prp);
	SETKSTATUS(act, 1);
}
Beispiel #4
0
/*
 * Enact a scenario by looping through the four test cases for the scenario,
 * spawning off pairs of processes with the desired credentials, and
 * reporting results to stdout.
 */
static int
enact_scenario(int scenario)
{
    pid_t pid1, pid2;
    char *name, *tracefile;
    int error, desirederror, loop;

    for (loop = 0; loop < LOOP_MAX+1; loop++) {
        /*
         * Spawn the first child, target of the operation.
         */
        pid1 = fork();
        switch (pid1) {
        case -1:
            return (-1);
        case 0:
            /* child */
            error = cred_set(scenarios[scenario].sc_cred2);
            if (error) {
                perror("cred_set");
                return (error);
            }
            /* 200 seconds should be plenty of time. */
            sleep(200);
            exit(0);
        default:
            /* parent */
            break;
        }

        /*
         * XXX
         * This really isn't ideal -- give proc 1 a chance to set
         * its credentials, or we may get spurious errors.  Really,
         * some for of IPC should be used to allow the parent to
         * wait for the first child to be ready before spawning
         * the second child.
         */
        sleep(1);

        /*
         * Spawn the second child, source of the operation.
         */
        pid2 = fork();
        switch (pid2) {
        case -1:
            return (-1);

        case 0:
            /* child */
            error = cred_set(scenarios[scenario].sc_cred1);
            if (error) {
                perror("cred_set");
                return (error);
            }

            /*
             * Initialize errno to zero so as to catch any
             * generated errors.  In each case, perform the
             * operation.  Preserve the error number for later
             * use so it doesn't get stomped on by any I/O.
             * Determine the desired error for the given case
             * by extracting it from the scenario table.
             * Initialize a function name string for output
             * prettiness.
             */
            errno = 0;
            switch (loop) {
            case LOOP_PTRACE:
                error = ptrace(PT_ATTACH, pid1, NULL, 0);
                error = errno;
                name = "ptrace";
                desirederror =
                    scenarios[scenario].sc_canptrace_errno;
                break;
            case LOOP_KTRACE:
                tracefile = mktemp("/tmp/testuid_ktrace.XXXXXX");
                if (tracefile == NULL) {
                    error = errno;
                    perror("mktemp");
                    break;
                }
                error = ktrace(tracefile, KTROP_SET,
                               KTRFAC_SYSCALL, pid1);
                error = errno;
                name = "ktrace";
                desirederror =
                    scenarios[scenario].sc_canktrace_errno;
                unlink(tracefile);
                break;
            case LOOP_SIGHUP:
                error = kill(pid1, SIGHUP);
                error = errno;
                name = "sighup";
                desirederror =
                    scenarios[scenario].sc_cansighup_errno;
                break;
            case LOOP_SIGSEGV:
                error = kill(pid1, SIGSEGV);
                error = errno;
                name = "sigsegv";
                desirederror =
                    scenarios[scenario].sc_cansigsegv_errno;
                break;
            case LOOP_SEE:
                getpriority(PRIO_PROCESS, pid1);
                error = errno;
                name = "see";
                desirederror =
                    scenarios[scenario].sc_cansee_errno;
                break;
            case LOOP_SCHED:
                error = setpriority(PRIO_PROCESS, pid1,
                                    0);
                error = errno;
                name = "sched";
                desirederror =
                    scenarios[scenario].sc_cansched_errno;
                break;
            default:
                name = "broken";
            }

            if (error != desirederror) {
                fprintf(stdout,
                        "[%s].%s: expected %s, got %s\n  ",
                        scenarios[scenario].sc_name, name,
                        errno_to_string(desirederror),
                        errno_to_string(error));
                cred_print(stdout,
                           scenarios[scenario].sc_cred1);
                cred_print(stdout,
                           scenarios[scenario].sc_cred2);
                fprintf(stdout, "\n");
            }

            exit(0);

        default:
            /* parent */
            break;
        }

        error = waitpid(pid2, NULL, 0);
        /*
         * Once pid2 has died, it's safe to kill pid1, if it's still
         * alive.  Mask signal failure in case the test actually
         * killed pid1 (not unlikely: can occur in both signal and
         * ptrace cases).
         */
        kill(pid1, SIGKILL);
        error = waitpid(pid2, NULL, 0);
    }

    return (0);
}