/* * 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); }
/* * 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); }