From: David van Moolenbroek Date: Sat, 11 Jul 2009 13:22:56 +0000 (+0000) Subject: PM: fix ptrace(T_EXIT) 'exit_proc: not idle' race condition. X-Git-Tag: v3.1.5~220 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/zpipe.c?a=commitdiff_plain;h=1a9e07b0e514e6e6fa20c6fa7690e88e7449b74a;p=minix.git PM: fix ptrace(T_EXIT) 'exit_proc: not idle' race condition. --- diff --git a/include/minix/com.h b/include/minix/com.h index 267c18734..b640c046d 100755 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -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 */ diff --git a/servers/pm/exec.c b/servers/pm/exec.c index 7e7ff087a..5d702bca1 100644 --- a/servers/pm/exec.c +++ b/servers/pm/exec.c @@ -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); diff --git a/servers/pm/forkexit.c b/servers/pm/forkexit.c index 26ddebb84..11a96061d 100644 --- a/servers/pm/forkexit.c +++ b/servers/pm/forkexit.c @@ -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]; diff --git a/servers/pm/main.c b/servers/pm/main.c index bd083e532..508a469e9 100644 --- a/servers/pm/main.c +++ b/servers/pm/main.c @@ -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); + } + } +} diff --git a/servers/pm/mproc.h b/servers/pm/mproc.h index 2dce02e02..a9d536220 100644 --- a/servers/pm/mproc.h +++ b/servers/pm/mproc.h @@ -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) diff --git a/servers/pm/proto.h b/servers/pm/proto.h index 8504b0076..ceaeccfc1 100644 --- a/servers/pm/proto.h +++ b/servers/pm/proto.h @@ -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) ); diff --git a/servers/pm/signal.c b/servers/pm/signal.c index 21d8d31c6..f3a49baf8 100644 --- a/servers/pm/signal.c +++ b/servers/pm/signal.c @@ -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 */ } /*===========================================================================* diff --git a/servers/pm/trace.c b/servers/pm/trace.c index 3a0e1c7a2..fb3fc656d 100644 --- a/servers/pm/trace.c +++ b/servers/pm/trace.c @@ -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. */ diff --git a/servers/vfs/main.c b/servers/vfs/main.c index 43912b6cc..49bb67408 100644 --- a/servers/vfs/main.c +++ b/servers/vfs/main.c @@ -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);