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
------------------------------------------------------------------------------