PM: fix ptrace(T_EXIT) 'exit_proc: not idle' race condition.

This commit is contained in:
David van Moolenbroek 2009-07-11 13:22:56 +00:00
parent 14f3a0e018
commit 1a9e07b0e5
9 changed files with 66 additions and 63 deletions

View file

@ -711,9 +711,6 @@
#define PM_CORE_PROC m1_i1 #define PM_CORE_PROC m1_i1
#define PM_CORE_SEGPTR m1_p1 #define PM_CORE_SEGPTR m1_p1
#define PM_UNPAUSE_TR (PM_BASE + 15) /* interrupted process (for tracing) */ #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 */ /* Replies */
#define PM_EXIT_REPLY (PM_BASE + 20) /* Reply from FS */ #define PM_EXIT_REPLY (PM_BASE + 20) /* Reply from FS */
@ -724,7 +721,6 @@
#define PM_CORE_REPLY (PM_BASE + 23) /* Reply from FS */ #define PM_CORE_REPLY (PM_BASE + 23) /* Reply from FS */
/* PM_CORE_PROC m1_i1 */ /* PM_CORE_PROC m1_i1 */
#define PM_CORE_STATUS m1_i2 /* OK or failure */ #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 */ /* Parameters for the EXEC_NEWMEM call */
#define EXC_NM_PROC m1_i1 /* process that needs new map */ #define EXC_NM_PROC m1_i1 /* process that needs new map */

View file

@ -162,7 +162,7 @@ int result;
/* Use SIGILL signal that something went wrong */ /* Use SIGILL signal that something went wrong */
rmp->mp_sigstatus = SIGILL; rmp->mp_sigstatus = SIGILL;
exit_proc(rmp, 0, PM_EXIT); exit_proc(rmp, 0, FALSE /*dump_core*/);
return; return;
} }
setreply(rmp-mproc, result); setreply(rmp-mproc, result);

View file

@ -183,17 +183,17 @@ PUBLIC int do_exit()
/* Perform the exit(status) system call. The real work is done by exit_proc(), /* 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. * 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 */ return(SUSPEND); /* can't communicate from beyond the grave */
} }
/*===========================================================================* /*===========================================================================*
* exit_proc * * 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 */ register struct mproc *rmp; /* pointer to the process to be terminated */
int exit_status; /* the process' exit status (for parent) */ 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 /* A process is done. Release most of the process' possessions. If its
* parent is waiting, release the rest, else keep the process slot and * 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; clock_t user_time, sys_time;
/* Do not create core files for set uid execution */ /* Do not create core files for set uid execution */
if (exit_type == PM_DUMPCORE && rmp->mp_realuid != rmp->mp_effuid) if (dump_core && rmp->mp_realuid != rmp->mp_effuid)
exit_type = PM_EXIT; dump_core = FALSE;
/* System processes are destroyed before informing FS, meaning that FS can /* 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. * 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)) if (dump_core && (rmp->mp_flags & PRIV_PROC))
exit_type = PM_EXIT; dump_core = FALSE;
proc_nr = (int) (rmp - mproc); /* get process slot number */ proc_nr = (int) (rmp - mproc); /* get process slot number */
proc_nr_e = rmp->mp_endpoint; 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. */ /* Tell FS about the exiting process. */
if (rmp->mp_fs_call != PM_IDLE) if (rmp->mp_fs_call != PM_IDLE)
panic(__FILE__, "exit_proc: not idle", rmp->mp_fs_call); 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); r= notify(FS_PROC_NR);
if (r != OK) panic(__FILE__, "exit_proc: unable to notify FS", r); 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 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. * For core dumps, notify the parent only once the core dump has been made.
*/ */
if (exit_type != PM_DUMPCORE) if (!dump_core)
zombify(rmp); zombify(rmp);
/* If the process has children, disinherit them. INIT is the new parent. */ /* 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 * * 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 */ 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 /* FS replied to our exit or coredump request. Perform the second half of the
* exit code. * exit code.
@ -324,7 +324,7 @@ int reply_type; /* one of PM_EXIT_REPLY(_TR), PM_CORE_REPLY */
int r; int r;
/* For core dumps, now is the right time to try to contact the parent. */ /* 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); zombify(rmp);
if (!(rmp->mp_flags & PRIV_PROC)) 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); 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 */ /* Wake up the parent, completing the ptrace(T_EXIT) call */
mproc[rmp->mp_parent].mp_reply.reply_trace = 0; mproc[rmp->mp_parent].mp_reply.reply_trace = 0;
@ -434,7 +434,7 @@ struct mproc *rmp;
if (rmp->mp_flags & ZOMBIE) if (rmp->mp_flags & ZOMBIE)
panic(__FILE__, "zombify: process was already a zombie", NO_NUM); 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; rmp->mp_flags |= ZOMBIE;
p_mp = &mproc[rmp->mp_parent]; p_mp = &mproc[rmp->mp_parent];

View file

@ -44,6 +44,7 @@ FORWARD _PROTOTYPE( void pm_init, (void) );
FORWARD _PROTOTYPE( int get_nice_value, (int queue) ); FORWARD _PROTOTYPE( int get_nice_value, (int queue) );
FORWARD _PROTOTYPE( void send_work, (void) ); FORWARD _PROTOTYPE( void send_work, (void) );
FORWARD _PROTOTYPE( void handle_fs_reply, (message *m_ptr) ); FORWARD _PROTOTYPE( void handle_fs_reply, (message *m_ptr) );
FORWARD _PROTOTYPE( void restart_sigs, (struct mproc *rmp) );
#define click_to_round_k(n) \ #define click_to_round_k(n) \
((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024)) ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
@ -91,7 +92,6 @@ PUBLIC int main()
case PM_REBOOT_REPLY: case PM_REBOOT_REPLY:
case PM_EXEC_REPLY: case PM_EXEC_REPLY:
case PM_CORE_REPLY: case PM_CORE_REPLY:
case PM_EXIT_REPLY_TR:
if (who_e == FS_PROC_NR) if (who_e == FS_PROC_NR)
{ {
handle_fs_reply(&m_in); handle_fs_reply(&m_in);
@ -379,9 +379,9 @@ void checkme(char *str, int line)
} }
} }
/*=========================================================================* /*===========================================================================*
* send_work * * send_work *
*=========================================================================*/ *===========================================================================*/
PRIVATE void send_work() PRIVATE void send_work()
{ {
int r, call; int r, call;
@ -460,7 +460,6 @@ PRIVATE void send_work()
} }
case PM_EXIT: case PM_EXIT:
case PM_EXIT_TR:
m.m_type= call; m.m_type= call;
m.PM_EXIT_PROC= rmp->mp_endpoint; m.PM_EXIT_PROC= rmp->mp_endpoint;
@ -552,18 +551,7 @@ PRIVATE void send_work()
} }
if (m.m_type != PM_IDLE) if (m.m_type != PM_IDLE)
{ {
if (rmp->mp_fs_call == PM_IDLE && restart_sigs(rmp);
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);
}
}
} }
else if (report_reboot) else if (report_reboot)
{ {
@ -574,6 +562,9 @@ PRIVATE void send_work()
if (r != OK) panic("pm", "send_work: send failed", r); if (r != OK) panic("pm", "send_work: send failed", r);
} }
/*===========================================================================*
* handle_fs_reply *
*===========================================================================*/
PRIVATE void handle_fs_reply(m_ptr) PRIVATE void handle_fs_reply(m_ptr)
message *m_ptr; message *m_ptr;
{ {
@ -583,7 +574,6 @@ message *m_ptr;
switch(m_ptr->m_type) switch(m_ptr->m_type)
{ {
case PM_EXIT_REPLY: case PM_EXIT_REPLY:
case PM_EXIT_REPLY_TR:
proc_e= m_ptr->PM_EXIT_PROC; proc_e= m_ptr->PM_EXIT_PROC;
if (pm_isokendpt(proc_e, &proc_n) != OK) if (pm_isokendpt(proc_e, &proc_n) != OK)
{ {
@ -596,7 +586,7 @@ message *m_ptr;
/* Call is finished */ /* Call is finished */
rmp->mp_fs_call= PM_IDLE; rmp->mp_fs_call= PM_IDLE;
exit_restart(rmp, m_ptr->m_type); exit_restart(rmp, FALSE /*dump_core*/);
break; break;
@ -630,20 +620,8 @@ message *m_ptr;
exec_restart(rmp, m_ptr->PM_EXEC_STATUS); exec_restart(rmp, m_ptr->PM_EXEC_STATUS);
if (rmp->mp_flags & PM_SIG_PENDING) restart_sigs(rmp);
{
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");
}
break; break;
case PM_CORE_REPLY: case PM_CORE_REPLY:
@ -663,7 +641,7 @@ message *m_ptr;
/* Call is finished */ /* Call is finished */
rmp->mp_fs_call= PM_IDLE; rmp->mp_fs_call= PM_IDLE;
exit_restart(rmp, m_ptr->m_type); exit_restart(rmp, TRUE /*dump_core*/);
break; 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);
}
}
}

View file

@ -77,6 +77,7 @@ EXTERN struct mproc {
#define PARTIAL_EXEC 0x8000 /* Process got a new map but no content */ #define PARTIAL_EXEC 0x8000 /* Process got a new map but no content */
#define TOLD_PARENT 0x10000 /* Parent wait() completed, ZOMBIE off */ #define TOLD_PARENT 0x10000 /* Parent wait() completed, ZOMBIE off */
#define EXITING 0x20000 /* set by EXIT, process is now exiting */ #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) #define NIL_MPROC ((struct mproc *) 0)

View file

@ -36,8 +36,8 @@ _PROTOTYPE( int do_fork_nb, (void) );
_PROTOTYPE( int do_exit, (void) ); _PROTOTYPE( int do_exit, (void) );
_PROTOTYPE( int do_waitpid, (void) ); _PROTOTYPE( int do_waitpid, (void) );
_PROTOTYPE( void exit_proc, (struct mproc *rmp, int exit_status, _PROTOTYPE( void exit_proc, (struct mproc *rmp, int exit_status,
int exit_type) ); int dump_core) );
_PROTOTYPE( void exit_restart, (struct mproc *rmp, int reply_type) ); _PROTOTYPE( void exit_restart, (struct mproc *rmp, int dump_core) );
/* getset.c */ /* getset.c */
_PROTOTYPE( int do_getset, (void) ); _PROTOTYPE( int do_getset, (void) );

View file

@ -421,7 +421,6 @@ int signo; /* signal to send to process (1 to _NSIG) */
int s; int s;
int slot; int slot;
int sigflags; int sigflags;
int exit_type;
slot = (int) (rmp - mproc); slot = (int) (rmp - mproc);
if ((rmp->mp_flags & (IN_USE | EXITING)) != IN_USE) { if ((rmp->mp_flags & (IN_USE | EXITING)) != IN_USE) {
@ -518,14 +517,16 @@ doterminate:
return; return;
} }
/* Terminate process */
rmp->mp_sigstatus = (char) signo; rmp->mp_sigstatus = (char) signo;
exit_type = PM_EXIT;
if (sigismember(&core_sset, signo) && slot != FS_PROC_NR) { if (sigismember(&core_sset, signo) && slot != FS_PROC_NR) {
printf("PM: coredump signal %d for %d / %s\n", signo, rmp->mp_pid, printf("PM: coredump signal %d for %d / %s\n", signo, rmp->mp_pid,
rmp->mp_name); 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 */
} }
/*===========================================================================* /*===========================================================================*

View file

@ -112,7 +112,14 @@ PUBLIC int do_trace()
switch (m_in.request) { switch (m_in.request) {
case T_EXIT: /* exit */ 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 /* Do not reply to the caller until FS has processed the exit
* request. * request.
*/ */

View file

@ -533,12 +533,10 @@ PRIVATE void service_pm()
break; break;
case PM_EXIT: case PM_EXIT:
case PM_EXIT_TR:
pm_exit(m.PM_EXIT_PROC); pm_exit(m.PM_EXIT_PROC);
/* Reply dummy status to PM for synchronization */ /* Reply dummy status to PM for synchronization */
m.m_type= (call == PM_EXIT_TR ? PM_EXIT_REPLY_TR : m.m_type= PM_EXIT_REPLY;
PM_EXIT_REPLY);
/* Keep m.PM_EXIT_PROC */ /* Keep m.PM_EXIT_PROC */
r= send(PM_PROC_NR, &m); r= send(PM_PROC_NR, &m);