Subject: 2nd review of fixes to sig_return() and LDT's
To: None <port-i386@sun-lamp.cs.berkeley.edu>
From: John Brezak <brezak@apollo.hp.com>
List: port-i386
Date: 01/07/1994 23:27:14
Here are the context diffs to scrutinize selectors that a user returns
in sig_return(). Also included are changes to allow > 512 LDT entries
(upto 8192 - the max on the 386).

There is a general change in sig_return(). When ever a process has
something wrong in the returned sigcontext, a SIGBUS is sent instead
of a "quiet" process exit.

Have a look and comment. I intend to commit these changes on Sunday.

*** machdep.c.orig	Fri Jan  7 05:49:35 1994
--- machdep.c	Fri Jan  7 23:01:45 1994
***************
*** 380,385 ****
--- 380,403 ----
  #endif
  
  /*
+  * Force a signal to a process
+  */
+ void
+ force_signal(p, signal)
+ 	struct proc *p;
+ 	int signal;
+ {
+ 	int sig;
+ 
+ 	SIGACTION(p, signal) = SIG_DFL;
+ 	sig = sigmask(signal);
+ 	p->p_sigignore &= ~sig;
+ 	p->p_sigcatch &= ~sig;
+ 	p->p_sigmask &= ~sig;
+ 	psignal(p, signal);
+ }
+ 
+ /*
   * Send an interrupt to process.
   *
   * Stack is set up to allow sigcode stored
***************
*** 427,438 ****
  		 * Process has trashed its stack; give it an illegal
  		 * instruction to halt it in its tracks.
  		 */
! 		SIGACTION(p, SIGILL) = SIG_DFL;
! 		sig = sigmask(SIGILL);
! 		p->p_sigignore &= ~sig;
! 		p->p_sigcatch &= ~sig;
! 		p->p_sigmask &= ~sig;
! 		psignal(p, SIGILL);
  		return;
  	}
  
--- 445,451 ----
  		 * Process has trashed its stack; give it an illegal
  		 * instruction to halt it in its tracks.
  		 */
!                 force_signal(p, SIGILL);
  		return;
  	}
  
***************
*** 511,534 ****
  	fp = (struct sigframe *)
  	     ((caddr_t)scp - offsetof(struct sigframe, sf_sc));
  
! 	if (useracc((caddr_t)fp, sizeof(*fp), 0) == 0)
  		return(EINVAL);
  
! 	if (useracc((caddr_t)scp, sizeof(*scp), 0) == 0)
  		return(EINVAL);
  
  	/* make sure they aren't trying to do anything funny */
! 	if ((scp->sc_ps & PSL_MBZ) != 0 || (scp->sc_ps & PSL_MBO) != PSL_MBO)
  		return(EINVAL);
  
  	/* compare IOPL; we can't insist that it's always 3 or the X server
  	   will fail */
! 	if ((tf->tf_eflags & PSL_IOPL) < (scp->sc_efl & PSL_IOPL))
  		return(EINVAL);
  
  	p->p_sigacts->ps_onstack = scp->sc_onstack & 01;
  	p->p_sigmask = scp->sc_mask &~
  	    (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
  
  	/*
  	 * Restore signal context.
--- 524,579 ----
  	fp = (struct sigframe *)
  	     ((caddr_t)scp - offsetof(struct sigframe, sf_sc));
  
! 	if (useracc((caddr_t)fp, sizeof(*fp), 0) == 0) {
! 		force_signal(p, SIGBUS);
  		return(EINVAL);
+ 	}
  
! 	if (useracc((caddr_t)scp, sizeof(*scp), 0) == 0) {
! 		force_signal(p, SIGBUS);
  		return(EINVAL);
+ 	}
  
  	/* make sure they aren't trying to do anything funny */
! 	if ((scp->sc_ps & PSL_MBZ) != 0 || (scp->sc_ps & PSL_MBO) != PSL_MBO) {
! 		force_signal(p, SIGBUS);
  		return(EINVAL);
+ 	}
  
  	/* compare IOPL; we can't insist that it's always 3 or the X server
  	   will fail */
! 	if ((tf->tf_eflags & PSL_IOPL) < (scp->sc_efl & PSL_IOPL)) {
! 		force_signal(p, SIGBUS);
  		return(EINVAL);
+ 	}
  
  	p->p_sigacts->ps_onstack = scp->sc_onstack & 01;
  	p->p_sigmask = scp->sc_mask &~
  	    (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
+ 
+ 	/*
+ 	 * Sanity check the user's selectors and error if they
+ 	 * are suspect.
+ 	 */
+ #define max_ldt_sel(pcb) \
+ 	((((pcb)->pcb_ldt)? \
+ 	    (gdt_segs[GUSERLDT_SEL].ssd_limit + 1) : \
+ 		sizeof(ldt))/sizeof(union descriptor))
+ 
+ #define valid_sel(sel) \
+ 	(((sel) == 0) || \
+ 	  (ISPL((sel)) == SEL_UPL && ISLDT((sel))) || \
+ 	  (ISLDT((sel)) && IDXSEL((sel)) < max_ldt_sel((struct pcb *)(p->p_addr))))
+ 
+ 	if (scp->sc_cs&0xffff != _ucodesel || scp->sc_ss&0xffff != _udatasel ||
+ 	    scp->sc_ds&0xffff != _udatasel || scp->sc_es&0xffff != _udatasel) {
+ 		if (!valid_sel(scp->sc_cs) || !valid_sel(scp->sc_ss) ||
+ 		    !valid_sel(scp->sc_ds) || !valid_sel(scp->sc_es)) {
+ 		    force_signal(p, SIGBUS);
+ 		    return(EINVAL);
+ 		}
+ 	}
+ #undef valid_sel
  
  	/*
  	 * Restore signal context.
*** vm_machdep.c.orig	Tue Jan  4 06:19:23 1994
--- vm_machdep.c	Fri Jan  7 14:20:18 1994
***************
*** 195,201 ****
--- 195,203 ----
          if (pcb->pcb_ldt) {
                  kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt,
                            (pcb->pcb_ldt_len * sizeof(union descriptor)));
+                 /* null old refs; prob not needed, but feels good */
                  pcb->pcb_ldt = NULL;
+                 pcb->pcb_ldt_len = 0;
          }
  #endif
  	kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
*** sys_machdep.c.orig	Wed Jan  5 07:33:13 1994
--- sys_machdep.c	Fri Jan  7 22:42:06 1994
***************
*** 35,41 ****
   * SUCH DAMAGE.
   *
   *	from: @(#)sys_machdep.c	5.5 (Berkeley) 1/19/91
!  *	$Id: sys_machdep.c,v 1.6 1994/01/05 03:18:25 mycroft Exp $
   */
  
  #include "npx.h"
--- 35,41 ----
   * SUCH DAMAGE.
   *
   *	from: @(#)sys_machdep.c	5.5 (Berkeley) 1/19/91
!  *	$Id: sys_machdep.c,v 1.2 1994/01/08 03:41:56 brezak Exp $
   */
  
  #include "npx.h"
***************
*** 138,143 ****
--- 138,144 ----
          int num;
  };
  
+ 
  i386_get_ldt(p, args, retval)
  	struct proc *p;
  	char *args;
***************
*** 215,234 ****
          if (uap->start < 0 || uap->num < 0)
                  return(EINVAL);
          
!         /* XXX Should be 8192 ! */
!         if (uap->start > 512 ||
!             (uap->start + uap->num) > 512)
                  return(EINVAL);
  
          /* allocate user ldt */
!         if (!pcb->pcb_ldt) {
!                 union descriptor *new_ldt =
!                         (union descriptor *)kmem_alloc(kernel_map, 512*sizeof(union descriptor));
!                 bcopy(ldt, new_ldt, sizeof(ldt));
                  pcb->pcb_ldt = (caddr_t)new_ldt;
!                 pcb->pcb_ldt_len = 512;		/* XXX need to grow */
  #ifdef DEBUG
!                 printf("i386_set_ldt(%d): new_ldt=%x\n", p->p_pid, new_ldt);
  #endif
          }
  
--- 216,254 ----
          if (uap->start < 0 || uap->num < 0)
                  return(EINVAL);
          
! #define NUM_LDT 8192
! 
!         if (uap->start > NUM_LDT ||
!             (uap->start + uap->num) > NUM_LDT)
                  return(EINVAL);
  
+         n = uap->start + uap->num;
+         
          /* allocate user ldt */
!         if (!pcb->pcb_ldt || pcb->pcb_ldt_len < n) {
! 		union descriptor *old_ldt = ldt, *new_ldt;
! 
!                 n = round_page(n*sizeof(union descriptor)) / sizeof(union descriptor);
!                 
!                 new_ldt = (union descriptor *)kmem_alloc(kernel_map, n*sizeof(union descriptor));
!                 i = sizeof(ldt);
!                 
!                 bzero(new_ldt, n*sizeof(union descriptor));
!                 if (pcb->pcb_ldt) {
! #ifdef DEBUG
!                     printf("i386_set_ldt(%d): growing pcb LDT to %d\n", p->p_pid, n);
! #endif                    
!                     old_ldt = (union descriptor *)pcb->pcb_ldt;
!                     i = pcb->pcb_ldt_len * sizeof(union descriptor);
!                 }
!                 bcopy(old_ldt, new_ldt, i);
!                 if (pcb->pcb_ldt)
!                     kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt,
!                               (pcb->pcb_ldt_len * sizeof(union descriptor)));
                  pcb->pcb_ldt = (caddr_t)new_ldt;
!                 pcb->pcb_ldt_len = n;
  #ifdef DEBUG
!                 printf("i386_set_ldt(%d): ldt_len=%d new_ldt=%x old_ldt=%x\n", p->p_pid, n, new_ldt, old_ldt);
  #endif
          }
  

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 John Brezak                    UUCP:     uunet!apollo.hp!brezak
 Hewlett Packard/Apollo         Internet: brezak@ch.hp.com
 300 Apollo Drive               Phone:    (508) 436-4915
 Chelmsford, Massachusetts      Fax:      (508) 436-5103

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 John Brezak                    UUCP:     uunet!apollo.hp!brezak
 Hewlett Packard/Apollo         Internet: brezak@ch.hp.com
 300 Apollo Drive               Phone:    (508) 436-4915
 Chelmsford, Massachusetts      Fax:      (508) 436-5103


------------------------------------------------------------------------------