Esempio n. 1
0
/*
 * continue the child until the run time linker has loaded in all
 * the loadobjects (rtld sync point)
 */
static prb_status_t
sync_child(int childpid, volatile shmem_msg_t *smp, prb_proc_ctl_t **proc_pp)
{
    prb_proc_ctl_t		*proc_p, *oldproc_p;
    prb_status_t		prbstat = PRB_STATUS_OK;
    prb_status_t		tempstat;
    prb_proc_state_t	pstate;

    prbstat = prb_proc_open(childpid, proc_pp);
    if (prbstat)
        return (prbstat);

    proc_p = *proc_pp;

    prbstat = prb_proc_stop(proc_p);
    if (prbstat)
        goto ret_failure;

    /*
     * default is to kill-on-last-close.  In case we cannot sync with
     * target, we don't want the target to continue.
     */
    prbstat = prb_proc_setrlc(proc_p, B_FALSE);
    if (prbstat)
        goto ret_failure;

    prbstat = prb_proc_setklc(proc_p, B_TRUE);
    if (prbstat)
        goto ret_failure;

    /* REMIND: do we have to wait on SYS_exec also ? */
    prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_ADD);
    if (prbstat)
        goto ret_failure;

    prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_ADD);
    if (prbstat)
        goto ret_failure;

    prbstat = prb_shmem_clear(smp);
    if (prbstat)
        goto ret_failure;

    prbstat = prb_proc_cont(proc_p);
    if (prbstat)
        goto ret_failure;

    prbstat = prb_proc_wait(proc_p, B_FALSE, NULL);
    switch (prbstat) {
    case PRB_STATUS_OK:
        break;
    case EAGAIN:
        /*
         * If we had exec'ed a setuid/setgid program PIOCWSTOP
         * will return EAGAIN.  Reopen the 'fd' and try again.
         * Read the last section of /proc man page - we reopen first
         * and then close the old fd.
         */
        oldproc_p = proc_p;
        tempstat = prb_proc_reopen(childpid, proc_pp);
        proc_p = *proc_pp;
        if (tempstat) {
            /* here EACCES means exec'ed a setuid/setgid program */
            (void) prb_proc_close(oldproc_p);
            return (tempstat);
        }

        (void) prb_proc_close(oldproc_p);
        break;
    default:
        goto ret_failure;
    }

    prbstat = prb_shmem_free(smp);
    if (prbstat)
        goto ret_failure;

    prbstat = prb_proc_state(proc_p, &pstate);
    if (prbstat)
        goto ret_failure;

    if (pstate.ps_issysexit && (pstate.ps_syscallnum == SYS_execve)) {
        /* expected condition */
        prbstat = PRB_STATUS_OK;
    } else {
        prbstat = prb_status_map(ENOENT);
        goto ret_failure;
    }

    /* clear old interest mask */
    prbstat = prb_proc_exit(proc_p, 0, PRB_SYS_NONE);
    if (prbstat)
        goto ret_failure;

    prbstat = prb_proc_entry(proc_p, 0, PRB_SYS_NONE);
    if (prbstat)
        goto ret_failure;

    /* Successful return */
    return (PRB_STATUS_OK);

ret_failure:
    (void) prb_proc_close(proc_p);
    return (prbstat);
}
Esempio n. 2
0
/*
 * prb_rtld_wait() - waits on target to execute getpid()
 */
static prb_status_t
prb_rtld_wait(prb_proc_ctl_t *proc_p)
{
	prb_proc_state_t pstate;
	prb_status_t	prbstat;

	DBG_TNF_PROBE_0(prb_rtld_wait_1, "libtnfctl", "sunw%verbosity 2");

	/* stop on exit of getpid() */
	prbstat = prb_proc_exit(proc_p, SYS_getpid, PRB_SYS_ADD);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't set up child to stop on "
			"exit of getpid(): %s\n", prb_status_str(prbstat)));
		return (prbstat);
	}
	/* stop on entry of exit() - i.e. exec failed */
	prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_ADD);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't set up child to stop on "
			"entry of exit(): %s\n", prb_status_str(prbstat)));
		return (prbstat);
	}
	/* continue target and wait for it to stop */
	prbstat = prb_proc_cont(proc_p);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't continue target process: %s\n",
				prb_status_str(prbstat)));
		return (prbstat);
	}
	/* wait for target to stop */
	prbstat = prb_proc_wait(proc_p, B_FALSE, NULL);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't wait on target process: %s\n",
			prb_status_str(prbstat)));
		return (prbstat);
	}
	/* make sure it did stop on getpid() */
	prbstat = prb_proc_state(proc_p, &pstate);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't get state of target: %s\n",
				prb_status_str(prbstat)));
		return (prbstat);
	}
	if (pstate.ps_issysentry && (pstate.ps_syscallnum == SYS_exit)) {
		DBG((void) fprintf(stderr, "prb_rtld_wait: target exited\n"));
		return (prb_status_map(EACCES));
	}
	/* catch any other errors */
	if (!(pstate.ps_issysexit && (pstate.ps_syscallnum == SYS_getpid))) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: target didn't stop on getpid\n"));
		return (PRB_STATUS_BADSYNC);
	}
	/* clear wait on getpid */
	prbstat = prb_proc_exit(proc_p, SYS_getpid, PRB_SYS_DEL);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't clear child to stop on "
			"exit of getpid(): %s\n", prb_status_str(prbstat)));
		return (prbstat);
	}
	/* clear wait on exit */
	prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_DEL);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't clear child to stop on "
			"entry of exit(): %s\n", prb_status_str(prbstat)));
		return (prbstat);
	}
	/* start-stop the process to clear it out of the system call */
	prbstat = prb_proc_prstop(proc_p);
	if (prbstat) {
		DBG((void) fprintf(stderr,
			"prb_rtld_wait: couldn't prstop child: %s\n",
			prb_status_str(prbstat)));
		return (prbstat);
	}
	return (PRB_STATUS_OK);
}