signals: fix signal leak by pushing back a pending signal when we recalc
authorAlan Cox <alan@linux.intel.com>
Mon, 2 Apr 2018 22:01:15 +0000 (23:01 +0100)
committerAlan Cox <alan@linux.intel.com>
Mon, 2 Apr 2018 22:01:15 +0000 (23:01 +0100)
Kernel/include/kernel.h
Kernel/process.c
Kernel/syscall_proc.c

index 889a6c0..ec54b02 100644 (file)
@@ -920,6 +920,7 @@ extern ptptr getproc(void);
 extern void newproc(ptptr p);
 extern ptptr ptab_alloc(void);
 extern void ssig(ptptr proc, uint8_t sig);
+extern void recalc_cursig(void);
 extern uint8_t chksigs(void);
 extern void program_vectors(uint16_t *pageptr);
 extern void sgrpsig(uint16_t pgrp, uint8_t sig);
index 6728bed..051f5d7 100644 (file)
@@ -550,8 +550,22 @@ static const uint16_t clear =
        SIGBIT(SIGCHLD) | SIGBIT(SIGURG) | SIGBIT(SIGWINCH) | SIGBIT(SIGIO) |
        SIGBIT(SIGCONT);
 
-/* Process a block of 16 signals so we can avoid using longs */
+/* Put back a computed signal so that we can recalculate what needs to be
+   serviced correctly */
+void recalc_cursig(void)
+{
+       if (udata.u_cursig) {
+               struct sigbits *sb = udata.u_ptab->p_sig;
+               if (udata.u_cursig & 16) {
+                       sb++;
+                       udata.u_cursig &= ~16;
+               }
+               sb->s_pending |= 1 << udata.u_cursig;
+               udata.u_cursig = 0;
+       }
+}
 
+/* Process a block of 16 signals so we can avoid using longs */
 static uint8_t chksigset(struct sigbits *sb, uint8_t b)
 {
        uint8_t j = 1;
@@ -641,8 +655,10 @@ uint8_t chksigs(void)
        /* Sleeping without signals allowed. We rely upon the fact that
           P_IOWAIT is never pre-empted or returns to user space so
           udata.u_cursig is not consulted until it is safe to do so */
-       if (udata.u_ptab->p_status == P_IOWAIT)
+       if (udata.u_ptab->p_status == P_IOWAIT) {
+               recalc_cursig();
                return 0;
+       }
 
        /* Fast path - no signals pending means no work.
           Cursig being set means we've already worked out what to do.
index 441fb57..de24649 100644 (file)
@@ -479,7 +479,7 @@ arg_t _signal(void)
        if (sig != SIGKILL && sig != SIGSTOP)
                udata.u_sigvec[sig] = func;
        /* Force recalculation of signal pending in the syscall return path */
-       udata.u_cursig = 0;
+       recalc_cursig();;
        irqrestore(irq);
        
        return (retval);
@@ -514,7 +514,7 @@ arg_t _sigdisp(void)
        else
                sb->s_held &= ~sigmask(sig);
        /* Force recalculation of signal pending in the syscall return path */
-       udata.u_cursig = 0;
+       recalc_cursig();
        return 0;
 }