PM: fix ptrace(T_EXIT) 'exit_proc: not idle' race condition.
This commit is contained in:
parent
14f3a0e018
commit
1a9e07b0e5
9 changed files with 66 additions and 63 deletions
|
@ -711,9 +711,6 @@
|
|||
#define PM_CORE_PROC m1_i1
|
||||
#define PM_CORE_SEGPTR m1_p1
|
||||
#define PM_UNPAUSE_TR (PM_BASE + 15) /* interrupted process (for tracing) */
|
||||
#define PM_EXIT_TR (PM_BASE + 16) /* Tell FS about the exiting process
|
||||
* (for tracing)
|
||||
*/
|
||||
|
||||
/* Replies */
|
||||
#define PM_EXIT_REPLY (PM_BASE + 20) /* Reply from FS */
|
||||
|
@ -724,7 +721,6 @@
|
|||
#define PM_CORE_REPLY (PM_BASE + 23) /* Reply from FS */
|
||||
/* PM_CORE_PROC m1_i1 */
|
||||
#define PM_CORE_STATUS m1_i2 /* OK or failure */
|
||||
#define PM_EXIT_REPLY_TR (PM_BASE + 24) /* Reply from FS */
|
||||
|
||||
/* Parameters for the EXEC_NEWMEM call */
|
||||
#define EXC_NM_PROC m1_i1 /* process that needs new map */
|
||||
|
|
|
@ -162,7 +162,7 @@ int result;
|
|||
|
||||
/* Use SIGILL signal that something went wrong */
|
||||
rmp->mp_sigstatus = SIGILL;
|
||||
exit_proc(rmp, 0, PM_EXIT);
|
||||
exit_proc(rmp, 0, FALSE /*dump_core*/);
|
||||
return;
|
||||
}
|
||||
setreply(rmp-mproc, result);
|
||||
|
|
|
@ -183,17 +183,17 @@ PUBLIC int do_exit()
|
|||
/* Perform the exit(status) system call. The real work is done by exit_proc(),
|
||||
* which is also called when a process is killed by a signal.
|
||||
*/
|
||||
exit_proc(mp, m_in.status, PM_EXIT);
|
||||
exit_proc(mp, m_in.status, FALSE /*dump_core*/);
|
||||
return(SUSPEND); /* can't communicate from beyond the grave */
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* exit_proc *
|
||||
*===========================================================================*/
|
||||
PUBLIC void exit_proc(rmp, exit_status, exit_type)
|
||||
PUBLIC void exit_proc(rmp, exit_status, dump_core)
|
||||
register struct mproc *rmp; /* pointer to the process to be terminated */
|
||||
int exit_status; /* the process' exit status (for parent) */
|
||||
int exit_type; /* one of PM_EXIT, PM_EXIT_TR, PM_DUMPCORE */
|
||||
int dump_core; /* flag indicating whether to dump core */
|
||||
{
|
||||
/* A process is done. Release most of the process' possessions. If its
|
||||
* parent is waiting, release the rest, else keep the process slot and
|
||||
|
@ -206,14 +206,14 @@ int exit_type; /* one of PM_EXIT, PM_EXIT_TR, PM_DUMPCORE */
|
|||
clock_t user_time, sys_time;
|
||||
|
||||
/* Do not create core files for set uid execution */
|
||||
if (exit_type == PM_DUMPCORE && rmp->mp_realuid != rmp->mp_effuid)
|
||||
exit_type = PM_EXIT;
|
||||
if (dump_core && rmp->mp_realuid != rmp->mp_effuid)
|
||||
dump_core = FALSE;
|
||||
|
||||
/* System processes are destroyed before informing FS, meaning that FS can
|
||||
* not get their CPU state, so we can't generate a coredump for them either.
|
||||
*/
|
||||
if (exit_type == PM_DUMPCORE && (rmp->mp_flags & PRIV_PROC))
|
||||
exit_type = PM_EXIT;
|
||||
if (dump_core && (rmp->mp_flags & PRIV_PROC))
|
||||
dump_core = FALSE;
|
||||
|
||||
proc_nr = (int) (rmp - mproc); /* get process slot number */
|
||||
proc_nr_e = rmp->mp_endpoint;
|
||||
|
@ -254,7 +254,7 @@ int exit_type; /* one of PM_EXIT, PM_EXIT_TR, PM_DUMPCORE */
|
|||
/* Tell FS about the exiting process. */
|
||||
if (rmp->mp_fs_call != PM_IDLE)
|
||||
panic(__FILE__, "exit_proc: not idle", rmp->mp_fs_call);
|
||||
rmp->mp_fs_call= exit_type;
|
||||
rmp->mp_fs_call= dump_core ? PM_DUMPCORE : PM_EXIT;
|
||||
r= notify(FS_PROC_NR);
|
||||
if (r != OK) panic(__FILE__, "exit_proc: unable to notify FS", r);
|
||||
|
||||
|
@ -289,7 +289,7 @@ int exit_type; /* one of PM_EXIT, PM_EXIT_TR, PM_DUMPCORE */
|
|||
/* For normal exits, try to notify the parent as soon as possible.
|
||||
* For core dumps, notify the parent only once the core dump has been made.
|
||||
*/
|
||||
if (exit_type != PM_DUMPCORE)
|
||||
if (!dump_core)
|
||||
zombify(rmp);
|
||||
|
||||
/* If the process has children, disinherit them. INIT is the new parent. */
|
||||
|
@ -314,9 +314,9 @@ int exit_type; /* one of PM_EXIT, PM_EXIT_TR, PM_DUMPCORE */
|
|||
/*===========================================================================*
|
||||
* exit_restart *
|
||||
*===========================================================================*/
|
||||
PUBLIC void exit_restart(rmp, reply_type)
|
||||
PUBLIC void exit_restart(rmp, dump_core)
|
||||
struct mproc *rmp; /* pointer to the process being terminated */
|
||||
int reply_type; /* one of PM_EXIT_REPLY(_TR), PM_CORE_REPLY */
|
||||
int dump_core; /* flag indicating whether to dump core */
|
||||
{
|
||||
/* FS replied to our exit or coredump request. Perform the second half of the
|
||||
* exit code.
|
||||
|
@ -324,7 +324,7 @@ int reply_type; /* one of PM_EXIT_REPLY(_TR), PM_CORE_REPLY */
|
|||
int r;
|
||||
|
||||
/* For core dumps, now is the right time to try to contact the parent. */
|
||||
if (reply_type == PM_CORE_REPLY)
|
||||
if (dump_core)
|
||||
zombify(rmp);
|
||||
|
||||
if (!(rmp->mp_flags & PRIV_PROC))
|
||||
|
@ -339,7 +339,7 @@ int reply_type; /* one of PM_EXIT_REPLY(_TR), PM_CORE_REPLY */
|
|||
panic(__FILE__, "exit_restart: vm_exit failed", r);
|
||||
}
|
||||
|
||||
if (reply_type == PM_EXIT_REPLY_TR && rmp->mp_parent != INIT_PROC_NR)
|
||||
if ((rmp->mp_flags & TRACE_EXIT) && rmp->mp_parent != INIT_PROC_NR)
|
||||
{
|
||||
/* Wake up the parent, completing the ptrace(T_EXIT) call */
|
||||
mproc[rmp->mp_parent].mp_reply.reply_trace = 0;
|
||||
|
@ -434,7 +434,7 @@ struct mproc *rmp;
|
|||
if (rmp->mp_flags & ZOMBIE)
|
||||
panic(__FILE__, "zombify: process was already a zombie", NO_NUM);
|
||||
|
||||
rmp->mp_flags &= (IN_USE|PRIV_PROC|EXITING);
|
||||
rmp->mp_flags &= (IN_USE|PRIV_PROC|EXITING|TRACE_EXIT);
|
||||
rmp->mp_flags |= ZOMBIE;
|
||||
|
||||
p_mp = &mproc[rmp->mp_parent];
|
||||
|
|
|
@ -44,6 +44,7 @@ FORWARD _PROTOTYPE( void pm_init, (void) );
|
|||
FORWARD _PROTOTYPE( int get_nice_value, (int queue) );
|
||||
FORWARD _PROTOTYPE( void send_work, (void) );
|
||||
FORWARD _PROTOTYPE( void handle_fs_reply, (message *m_ptr) );
|
||||
FORWARD _PROTOTYPE( void restart_sigs, (struct mproc *rmp) );
|
||||
|
||||
#define click_to_round_k(n) \
|
||||
((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
|
||||
|
@ -91,7 +92,6 @@ PUBLIC int main()
|
|||
case PM_REBOOT_REPLY:
|
||||
case PM_EXEC_REPLY:
|
||||
case PM_CORE_REPLY:
|
||||
case PM_EXIT_REPLY_TR:
|
||||
if (who_e == FS_PROC_NR)
|
||||
{
|
||||
handle_fs_reply(&m_in);
|
||||
|
@ -379,9 +379,9 @@ void checkme(char *str, int line)
|
|||
}
|
||||
}
|
||||
|
||||
/*=========================================================================*
|
||||
* send_work *
|
||||
*=========================================================================*/
|
||||
/*===========================================================================*
|
||||
* send_work *
|
||||
*===========================================================================*/
|
||||
PRIVATE void send_work()
|
||||
{
|
||||
int r, call;
|
||||
|
@ -460,7 +460,6 @@ PRIVATE void send_work()
|
|||
}
|
||||
|
||||
case PM_EXIT:
|
||||
case PM_EXIT_TR:
|
||||
m.m_type= call;
|
||||
m.PM_EXIT_PROC= rmp->mp_endpoint;
|
||||
|
||||
|
@ -552,18 +551,7 @@ PRIVATE void send_work()
|
|||
}
|
||||
if (m.m_type != PM_IDLE)
|
||||
{
|
||||
if (rmp->mp_fs_call == PM_IDLE &&
|
||||
rmp->mp_fs_call2 == PM_IDLE &&
|
||||
(rmp->mp_flags & PM_SIG_PENDING))
|
||||
{
|
||||
rmp->mp_flags &= ~PM_SIG_PENDING;
|
||||
check_pending(rmp);
|
||||
if (!(rmp->mp_flags & PM_SIG_PENDING))
|
||||
{
|
||||
/* Allow the process to be scheduled */
|
||||
sys_nice(rmp->mp_endpoint, rmp->mp_nice);
|
||||
}
|
||||
}
|
||||
restart_sigs(rmp);
|
||||
}
|
||||
else if (report_reboot)
|
||||
{
|
||||
|
@ -574,6 +562,9 @@ PRIVATE void send_work()
|
|||
if (r != OK) panic("pm", "send_work: send failed", r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* handle_fs_reply *
|
||||
*===========================================================================*/
|
||||
PRIVATE void handle_fs_reply(m_ptr)
|
||||
message *m_ptr;
|
||||
{
|
||||
|
@ -583,7 +574,6 @@ message *m_ptr;
|
|||
switch(m_ptr->m_type)
|
||||
{
|
||||
case PM_EXIT_REPLY:
|
||||
case PM_EXIT_REPLY_TR:
|
||||
proc_e= m_ptr->PM_EXIT_PROC;
|
||||
if (pm_isokendpt(proc_e, &proc_n) != OK)
|
||||
{
|
||||
|
@ -596,7 +586,7 @@ message *m_ptr;
|
|||
/* Call is finished */
|
||||
rmp->mp_fs_call= PM_IDLE;
|
||||
|
||||
exit_restart(rmp, m_ptr->m_type);
|
||||
exit_restart(rmp, FALSE /*dump_core*/);
|
||||
|
||||
break;
|
||||
|
||||
|
@ -630,20 +620,8 @@ message *m_ptr;
|
|||
|
||||
exec_restart(rmp, m_ptr->PM_EXEC_STATUS);
|
||||
|
||||
if (rmp->mp_flags & PM_SIG_PENDING)
|
||||
{
|
||||
printf("handle_fs_reply: restarting signals\n");
|
||||
rmp->mp_flags &= ~PM_SIG_PENDING;
|
||||
check_pending(rmp);
|
||||
if (!(rmp->mp_flags & PM_SIG_PENDING))
|
||||
{
|
||||
printf("handle_fs_reply: calling sys_nice\n");
|
||||
/* Allow the process to be scheduled */
|
||||
sys_nice(rmp->mp_endpoint, rmp->mp_nice);
|
||||
}
|
||||
else
|
||||
printf("handle_fs_reply: more signals\n");
|
||||
}
|
||||
restart_sigs(rmp);
|
||||
|
||||
break;
|
||||
|
||||
case PM_CORE_REPLY:
|
||||
|
@ -663,7 +641,7 @@ message *m_ptr;
|
|||
/* Call is finished */
|
||||
rmp->mp_fs_call= PM_IDLE;
|
||||
|
||||
exit_restart(rmp, m_ptr->m_type);
|
||||
exit_restart(rmp, TRUE /*dump_core*/);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -675,3 +653,25 @@ message *m_ptr;
|
|||
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* restart_sigs *
|
||||
*===========================================================================*/
|
||||
PRIVATE void restart_sigs(rmp)
|
||||
struct mproc *rmp;
|
||||
{
|
||||
|
||||
if (rmp->mp_fs_call != PM_IDLE || rmp->mp_fs_call2 != PM_IDLE)
|
||||
return;
|
||||
|
||||
if (rmp->mp_flags & TRACE_EXIT) {
|
||||
exit_proc(rmp, rmp->mp_exitstatus, FALSE /*dump_core*/);
|
||||
}
|
||||
else if (rmp->mp_flags & PM_SIG_PENDING) {
|
||||
rmp->mp_flags &= ~PM_SIG_PENDING;
|
||||
check_pending(rmp);
|
||||
if (!(rmp->mp_flags & PM_SIG_PENDING)) {
|
||||
/* Allow the process to be scheduled */
|
||||
sys_nice(rmp->mp_endpoint, rmp->mp_nice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ EXTERN struct mproc {
|
|||
#define PARTIAL_EXEC 0x8000 /* Process got a new map but no content */
|
||||
#define TOLD_PARENT 0x10000 /* Parent wait() completed, ZOMBIE off */
|
||||
#define EXITING 0x20000 /* set by EXIT, process is now exiting */
|
||||
#define TRACE_EXIT 0x40000 /* tracer is forcing this process to exit */
|
||||
|
||||
#define NIL_MPROC ((struct mproc *) 0)
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ _PROTOTYPE( int do_fork_nb, (void) );
|
|||
_PROTOTYPE( int do_exit, (void) );
|
||||
_PROTOTYPE( int do_waitpid, (void) );
|
||||
_PROTOTYPE( void exit_proc, (struct mproc *rmp, int exit_status,
|
||||
int exit_type) );
|
||||
_PROTOTYPE( void exit_restart, (struct mproc *rmp, int reply_type) );
|
||||
int dump_core) );
|
||||
_PROTOTYPE( void exit_restart, (struct mproc *rmp, int dump_core) );
|
||||
|
||||
/* getset.c */
|
||||
_PROTOTYPE( int do_getset, (void) );
|
||||
|
|
|
@ -421,7 +421,6 @@ int signo; /* signal to send to process (1 to _NSIG) */
|
|||
int s;
|
||||
int slot;
|
||||
int sigflags;
|
||||
int exit_type;
|
||||
|
||||
slot = (int) (rmp - mproc);
|
||||
if ((rmp->mp_flags & (IN_USE | EXITING)) != IN_USE) {
|
||||
|
@ -518,14 +517,16 @@ doterminate:
|
|||
return;
|
||||
}
|
||||
|
||||
/* Terminate process */
|
||||
rmp->mp_sigstatus = (char) signo;
|
||||
exit_type = PM_EXIT;
|
||||
if (sigismember(&core_sset, signo) && slot != FS_PROC_NR) {
|
||||
printf("PM: coredump signal %d for %d / %s\n", signo, rmp->mp_pid,
|
||||
rmp->mp_name);
|
||||
exit_type = PM_DUMPCORE;
|
||||
exit_proc(rmp, 0, TRUE /*dump_core*/);
|
||||
}
|
||||
else {
|
||||
exit_proc(rmp, 0, FALSE /*dump_core*/);
|
||||
}
|
||||
exit_proc(rmp, 0, exit_type); /* terminate process */
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
|
@ -112,7 +112,14 @@ PUBLIC int do_trace()
|
|||
|
||||
switch (m_in.request) {
|
||||
case T_EXIT: /* exit */
|
||||
exit_proc(child, (int) m_in.data, PM_EXIT_TR);
|
||||
child->mp_flags |= TRACE_EXIT;
|
||||
|
||||
/* Defer the exit if the traced process has an FS call pending. */
|
||||
if (child->mp_fs_call != PM_IDLE || child->mp_fs_call2 != PM_IDLE)
|
||||
child->mp_exitstatus = (int) m_in.data; /* save for later */
|
||||
else
|
||||
exit_proc(child, (int) m_in.data, FALSE /*dump_core*/);
|
||||
|
||||
/* Do not reply to the caller until FS has processed the exit
|
||||
* request.
|
||||
*/
|
||||
|
|
|
@ -533,12 +533,10 @@ PRIVATE void service_pm()
|
|||
break;
|
||||
|
||||
case PM_EXIT:
|
||||
case PM_EXIT_TR:
|
||||
pm_exit(m.PM_EXIT_PROC);
|
||||
|
||||
/* Reply dummy status to PM for synchronization */
|
||||
m.m_type= (call == PM_EXIT_TR ? PM_EXIT_REPLY_TR :
|
||||
PM_EXIT_REPLY);
|
||||
m.m_type= PM_EXIT_REPLY;
|
||||
/* Keep m.PM_EXIT_PROC */
|
||||
|
||||
r= send(PM_PROC_NR, &m);
|
||||
|
|
Loading…
Reference in a new issue