]> Zhao Yanbai Git Server - minix.git/commitdiff
PM: fix ptrace(T_EXIT) 'exit_proc: not idle' race condition.
authorDavid van Moolenbroek <david@minix3.org>
Sat, 11 Jul 2009 13:22:56 +0000 (13:22 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Sat, 11 Jul 2009 13:22:56 +0000 (13:22 +0000)
include/minix/com.h
servers/pm/exec.c
servers/pm/forkexit.c
servers/pm/main.c
servers/pm/mproc.h
servers/pm/proto.h
servers/pm/signal.c
servers/pm/trace.c
servers/vfs/main.c

index 267c187343f823a7aaa43bc3bf7d27fae6e3757f..b640c046d6cde2499acaa885f350b82875d544a9 100755 (executable)
 #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 */
 #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 */
index 7e7ff087a37b0e4c38a23b9a1749ea7f466abec0..5d702bca18e9e44e918459fd077c08d436c07a19 100644 (file)
@@ -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);
index 26ddebb84b8c79626f79eeb0b01fed0bf2fb1632..11a96061dbe51f4c3b40c12f2aca4fc794a5c01a 100644 (file)
@@ -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];
index bd083e532ec05c490fd2e6c457f7ee26c2efc31e..508a469e9a474691d219a8b15c0b2224c7850acf 100644 (file)
@@ -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);
+               }
+       }
+}
index 2dce02e0258ec071a626593c89ff7e4d9982a72c..a9d5362201c2f417617d75da47adf610c9df23d1 100644 (file)
@@ -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)
 
index 8504b00765e1ac8ce55e79ef6b9472b433a38be9..ceaeccfc1a5bf03d50ca119c96ec0cf622e9a596 100644 (file)
@@ -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)                                      );
index 21d8d31c632e6d03e6ab4ca9687101e3aa197eca..f3a49baf8313c5bdb30bfa95e569780b1d69bd58 100644 (file)
@@ -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 */
 }
 
 /*===========================================================================*
index 3a0e1c7a2fe1ef8de5afc0d4352030337e2851ed..fb3fc656d56c21cccbfa67c03a2ac9013545d9a8 100644 (file)
@@ -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.
         */
index 43912b6cce1b7fd4d1a47a64d02bb2ab1857b809..49bb67408a300853f517cd8daa0e0ab33a4ec792 100644 (file)
@@ -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);