diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/amd64/amd64/exception.S | 36 | ||||
-rw-r--r-- | sys/amd64/amd64/exception.s | 36 | ||||
-rw-r--r-- | sys/amd64/amd64/locore.S | 11 | ||||
-rw-r--r-- | sys/amd64/amd64/locore.s | 11 | ||||
-rw-r--r-- | sys/amd64/amd64/machdep.c | 186 | ||||
-rw-r--r-- | sys/amd64/amd64/trap.c | 72 | ||||
-rw-r--r-- | sys/amd64/include/psl.h | 37 | ||||
-rw-r--r-- | sys/amd64/include/trap.h | 21 | ||||
-rw-r--r-- | sys/i386/i386/exception.s | 36 | ||||
-rw-r--r-- | sys/i386/i386/locore.s | 11 | ||||
-rw-r--r-- | sys/i386/i386/machdep.c | 186 | ||||
-rw-r--r-- | sys/i386/i386/procfs_machdep.c | 59 | ||||
-rw-r--r-- | sys/i386/i386/trap.c | 72 | ||||
-rw-r--r-- | sys/i386/include/psl.h | 37 | ||||
-rw-r--r-- | sys/i386/include/trap.h | 21 | ||||
-rw-r--r-- | sys/kern/subr_trap.c | 72 | ||||
-rw-r--r-- | sys/kern/sys_process.c | 8 |
17 files changed, 491 insertions, 421 deletions
diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S index e14934b..f6d6115 100644 --- a/sys/amd64/amd64/exception.S +++ b/sys/amd64/amd64/exception.S @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: exception.s,v 1.5 1994/09/28 03:37:49 bde Exp $ + * $Id: exception.s,v 1.6 1994/12/03 10:02:19 bde Exp $ */ #include "npx.h" /* NNPX */ @@ -158,43 +158,15 @@ IDTVEC(fpu) #else /* NNPX > 0 */ pushl $0; TRAP(T_ARITHTRAP) #endif /* NNPX > 0 */ - /* 17 - 31 reserved for future exp */ -IDTVEC(rsvd0) - pushl $0; TRAP(17) -IDTVEC(rsvd1) - pushl $0; TRAP(18) -IDTVEC(rsvd2) - pushl $0; TRAP(19) -IDTVEC(rsvd3) - pushl $0; TRAP(20) -IDTVEC(rsvd4) - pushl $0; TRAP(21) -IDTVEC(rsvd5) - pushl $0; TRAP(22) -IDTVEC(rsvd6) - pushl $0; TRAP(23) -IDTVEC(rsvd7) - pushl $0; TRAP(24) -IDTVEC(rsvd8) - pushl $0; TRAP(25) -IDTVEC(rsvd9) - pushl $0; TRAP(26) -IDTVEC(rsvd10) - pushl $0; TRAP(27) -IDTVEC(rsvd11) - pushl $0; TRAP(28) -IDTVEC(rsvd12) - pushl $0; TRAP(29) -IDTVEC(rsvd13) - pushl $0; TRAP(30) -IDTVEC(rsvd14) - pushl $0; TRAP(31) +IDTVEC(align) + TRAP(T_ALIGNFLT) SUPERALIGN_TEXT _alltraps: pushal pushl %ds pushl %es +alltraps_with_regs_pushed: movl $KDSEL,%eax movl %ax,%ds movl %ax,%es diff --git a/sys/amd64/amd64/exception.s b/sys/amd64/amd64/exception.s index e14934b..f6d6115 100644 --- a/sys/amd64/amd64/exception.s +++ b/sys/amd64/amd64/exception.s @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: exception.s,v 1.5 1994/09/28 03:37:49 bde Exp $ + * $Id: exception.s,v 1.6 1994/12/03 10:02:19 bde Exp $ */ #include "npx.h" /* NNPX */ @@ -158,43 +158,15 @@ IDTVEC(fpu) #else /* NNPX > 0 */ pushl $0; TRAP(T_ARITHTRAP) #endif /* NNPX > 0 */ - /* 17 - 31 reserved for future exp */ -IDTVEC(rsvd0) - pushl $0; TRAP(17) -IDTVEC(rsvd1) - pushl $0; TRAP(18) -IDTVEC(rsvd2) - pushl $0; TRAP(19) -IDTVEC(rsvd3) - pushl $0; TRAP(20) -IDTVEC(rsvd4) - pushl $0; TRAP(21) -IDTVEC(rsvd5) - pushl $0; TRAP(22) -IDTVEC(rsvd6) - pushl $0; TRAP(23) -IDTVEC(rsvd7) - pushl $0; TRAP(24) -IDTVEC(rsvd8) - pushl $0; TRAP(25) -IDTVEC(rsvd9) - pushl $0; TRAP(26) -IDTVEC(rsvd10) - pushl $0; TRAP(27) -IDTVEC(rsvd11) - pushl $0; TRAP(28) -IDTVEC(rsvd12) - pushl $0; TRAP(29) -IDTVEC(rsvd13) - pushl $0; TRAP(30) -IDTVEC(rsvd14) - pushl $0; TRAP(31) +IDTVEC(align) + TRAP(T_ALIGNFLT) SUPERALIGN_TEXT _alltraps: pushal pushl %ds pushl %es +alltraps_with_regs_pushed: movl $KDSEL,%eax movl %ax,%ds movl %ax,%es diff --git a/sys/amd64/amd64/locore.S b/sys/amd64/amd64/locore.S index 7f32a04..e28f065 100644 --- a/sys/amd64/amd64/locore.S +++ b/sys/amd64/amd64/locore.S @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)locore.s 7.3 (Berkeley) 5/13/91 - * $Id: locore.s,v 1.44 1994/11/06 22:18:45 phk Exp $ + * $Id: locore.s,v 1.45 1994/11/18 05:27:34 phk Exp $ */ /* @@ -176,7 +176,7 @@ NON_GPROF_ENTRY(btext) movl %esp, %ebp /* Don't trust what the BIOS gives for eflags. */ - pushl $PSL_MBO + pushl $PSL_KERNEL popfl /* Don't trust what the BIOS gives for %fs and %gs. */ @@ -764,7 +764,7 @@ reloc_gdt: pushl $0 /* unused */ pushl __udatasel /* ss */ pushl $0 /* esp - filled in by execve() */ - pushl $PSL_USERSET /* eflags (ring 0, int enab) */ + pushl $PSL_USER /* eflags (IOPL 0, int enab) */ pushl __ucodesel /* cs */ pushl $0 /* eip - filled in by execve() */ subl $(12*4),%esp /* space for rest of registers */ @@ -776,13 +776,14 @@ reloc_gdt: /* * now we've run main() and determined what cpu-type we are, we can - * enable WP mode on i486 cpus and above. + * enable write protection and alignment checking on i486 cpus and + * above. */ #if defined(I486_CPU) || defined(I586_CPU) cmpl $CPUCLASS_386,_cpu_class je 1f movl %cr0,%eax /* get control word */ - orl $CR0_WP,%eax /* enable write protect for all modes */ + orl $CR0_WP|CR0_AM,%eax /* enable i486 features */ movl %eax,%cr0 /* and do it */ #endif /* diff --git a/sys/amd64/amd64/locore.s b/sys/amd64/amd64/locore.s index 7f32a04..e28f065 100644 --- a/sys/amd64/amd64/locore.s +++ b/sys/amd64/amd64/locore.s @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)locore.s 7.3 (Berkeley) 5/13/91 - * $Id: locore.s,v 1.44 1994/11/06 22:18:45 phk Exp $ + * $Id: locore.s,v 1.45 1994/11/18 05:27:34 phk Exp $ */ /* @@ -176,7 +176,7 @@ NON_GPROF_ENTRY(btext) movl %esp, %ebp /* Don't trust what the BIOS gives for eflags. */ - pushl $PSL_MBO + pushl $PSL_KERNEL popfl /* Don't trust what the BIOS gives for %fs and %gs. */ @@ -764,7 +764,7 @@ reloc_gdt: pushl $0 /* unused */ pushl __udatasel /* ss */ pushl $0 /* esp - filled in by execve() */ - pushl $PSL_USERSET /* eflags (ring 0, int enab) */ + pushl $PSL_USER /* eflags (IOPL 0, int enab) */ pushl __ucodesel /* cs */ pushl $0 /* eip - filled in by execve() */ subl $(12*4),%esp /* space for rest of registers */ @@ -776,13 +776,14 @@ reloc_gdt: /* * now we've run main() and determined what cpu-type we are, we can - * enable WP mode on i486 cpus and above. + * enable write protection and alignment checking on i486 cpus and + * above. */ #if defined(I486_CPU) || defined(I586_CPU) cmpl $CPUCLASS_386,_cpu_class je 1f movl %cr0,%eax /* get control word */ - orl $CR0_WP,%eax /* enable write protect for all modes */ + orl $CR0_WP|CR0_AM,%eax /* enable i486 features */ movl %eax,%cr0 /* and do it */ #endif /* diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index eeba17b..7b59d96 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 - * $Id: machdep.c,v 1.99 1995/01/05 19:51:14 se Exp $ + * $Id: machdep.c,v 1.100 1995/01/09 16:04:37 davidg Exp $ */ #include "npx.h" @@ -459,7 +459,7 @@ vmtime(otime, olbolt, oicr) } #endif -extern int kstack[]; +extern char kstack[]; /* * Send an interrupt to process. @@ -607,48 +607,34 @@ sigreturn(p, uap, retval) if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0) return(EINVAL); + /* + * Don't allow users to change privileged or reserved flags. Let + * the hardware check for changing to excess I/O privilege. + */ +#define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) + eflags = scp->sc_ps; - if ((eflags & PSL_USERCLR) != 0 || - (eflags & PSL_USERSET) != PSL_USERSET || - (eflags & PSL_IOPL) < (regs[tEFLAGS] & PSL_IOPL)) { + if (!EFLAGS_SECURE(eflags, regs[tEFLAGS])) { #ifdef DEBUG - printf("sigreturn: eflags=0x%x\n", eflags); + printf("sigreturn: eflags = 0x%x\n", eflags); #endif return(EINVAL); } /* - * Sanity check the user's selectors and error if they - * are suspect. + * Don't allow users to load a valid privileged %cs. Let the + * hardware check for invalid selectors, excess privilege in + * other selectors, invalid %eip's and invalid %esp's. */ -#define max_ldt_sel(pcb) \ - ((pcb)->pcb_ldt ? (pcb)->pcb_ldt_len : (sizeof(ldt) / sizeof(ldt[0]))) - -#define valid_ldt_sel(sel) \ - (ISLDT(sel) && ISPL(sel) == SEL_UPL && \ - IDXSEL(sel) < max_ldt_sel(&p->p_addr->u_pcb)) - -#define null_sel(sel) \ - (!ISLDT(sel) && IDXSEL(sel) == 0) - - if (((scp->sc_cs&0xffff) != _ucodesel && !valid_ldt_sel(scp->sc_cs)) || - ((scp->sc_ss&0xffff) != _udatasel && !valid_ldt_sel(scp->sc_ss)) || - ((scp->sc_ds&0xffff) != _udatasel && !valid_ldt_sel(scp->sc_ds) && - !null_sel(scp->sc_ds)) || - ((scp->sc_es&0xffff) != _udatasel && !valid_ldt_sel(scp->sc_es) && - !null_sel(scp->sc_es))) { +#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) + if (!CS_SECURE(scp->sc_cs)) { #ifdef DEBUG - printf("sigreturn: cs=0x%x ss=0x%x ds=0x%x es=0x%x\n", - scp->sc_cs, scp->sc_ss, scp->sc_ds, scp->sc_es); + printf("sigreturn: cs = 0x%x\n", scp->sc_cs); #endif trapsignal(p, SIGBUS, T_PROTFLT); return(EINVAL); } -#undef max_ldt_sel -#undef valid_ldt_sel -#undef null_sel - /* restore scratch registers */ regs[tEAX] = scp->sc_eax; regs[tEBX] = scp->sc_ebx; @@ -863,7 +849,7 @@ setregs(p, entry, stack) bzero(regs, sizeof(struct trapframe)); regs[tEIP] = entry; regs[tESP] = stack; - regs[tEFLAGS] = PSL_USERSET | (regs[tEFLAGS] & PSL_T); + regs[tEFLAGS] = PSL_USER | (regs[tEFLAGS] & PSL_T); regs[tSS] = _udatasel; regs[tDS] = _udatasel; regs[tES] = _udatasel; @@ -1106,11 +1092,8 @@ extern inthand_t IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl), IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm), IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), - IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0), - IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4), - IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8), - IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12), - IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(syscall); + IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align), + IDTVEC(syscall); void sdtossd(sd, ssd) @@ -1191,6 +1174,8 @@ init386(first) ssdtosd(&ldt_segs[x], &ldt[x].sd); /* exceptions */ + for (x = 0; x < NIDT; x++) + setidt(x, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL); setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL); setidt(1, &IDTVEC(dbg), SDT_SYS386TGT, SEL_KPL); setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL); @@ -1208,21 +1193,7 @@ init386(first) setidt(14, &IDTVEC(page), SDT_SYS386TGT, SEL_KPL); setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL); setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL); - setidt(17, &IDTVEC(rsvd0), SDT_SYS386TGT, SEL_KPL); - setidt(18, &IDTVEC(rsvd1), SDT_SYS386TGT, SEL_KPL); - setidt(19, &IDTVEC(rsvd2), SDT_SYS386TGT, SEL_KPL); - setidt(20, &IDTVEC(rsvd3), SDT_SYS386TGT, SEL_KPL); - setidt(21, &IDTVEC(rsvd4), SDT_SYS386TGT, SEL_KPL); - setidt(22, &IDTVEC(rsvd5), SDT_SYS386TGT, SEL_KPL); - setidt(23, &IDTVEC(rsvd6), SDT_SYS386TGT, SEL_KPL); - setidt(24, &IDTVEC(rsvd7), SDT_SYS386TGT, SEL_KPL); - setidt(25, &IDTVEC(rsvd8), SDT_SYS386TGT, SEL_KPL); - setidt(26, &IDTVEC(rsvd9), SDT_SYS386TGT, SEL_KPL); - setidt(27, &IDTVEC(rsvd10), SDT_SYS386TGT, SEL_KPL); - setidt(28, &IDTVEC(rsvd11), SDT_SYS386TGT, SEL_KPL); - setidt(29, &IDTVEC(rsvd12), SDT_SYS386TGT, SEL_KPL); - setidt(30, &IDTVEC(rsvd13), SDT_SYS386TGT, SEL_KPL); - setidt(31, &IDTVEC(rsvd14), SDT_SYS386TGT, SEL_KPL); + setidt(17, &IDTVEC(align), SDT_SYS386TGT, SEL_KPL); #include "isa.h" #if NISA >0 @@ -1445,60 +1416,95 @@ test_page(address, pattern) * index into the user block. Don't you just *love* virtual memory? * (I'm starting to think seymour is right...) */ +#define TF_REGP(p) ((struct trapframe *) \ + ((char *)(p)->p_addr \ + + ((char *)(p)->p_md.md_regs - kstack))) int -ptrace_set_pc (struct proc *p, unsigned int addr) { - void *regs = (char*)p->p_addr + - ((char*) p->p_md.md_regs - (char*) kstack); - - ((struct trapframe *)regs)->tf_eip = addr; - return 0; +ptrace_set_pc(p, addr) + struct proc *p; + unsigned int addr; +{ + TF_REGP(p)->tf_eip = addr; + return (0); } int -ptrace_single_step (struct proc *p) { - void *regs = (char*)p->p_addr + - ((char*) p->p_md.md_regs - (char*) kstack); - - ((struct trapframe *)regs)->tf_eflags |= PSL_T; - return 0; +ptrace_single_step(p) + struct proc *p; +{ + TF_REGP(p)->tf_eflags |= PSL_T; + return (0); } -/* - * Copy the registers to user-space. - */ - int -ptrace_getregs (struct proc *p, unsigned int *addr) { +ptrace_getregs(p, addr) + struct proc *p; + unsigned int *addr; +{ int error; - struct reg regs = {0}; + struct reg regs; - error = fill_regs (p, ®s); + error = fill_regs(p, ®s); if (error) - return error; - - return copyout (®s, addr, sizeof (regs)); + return (error); + return (copyout(®s, addr, sizeof regs)); } int -ptrace_setregs (struct proc *p, unsigned int *addr) { +ptrace_setregs(p, addr) + struct proc *p; + unsigned int *addr; +{ int error; - struct reg regs = {0}; + struct reg regs; - error = copyin (addr, ®s, sizeof(regs)); + error = copyin(addr, ®s, sizeof regs); if (error) - return error; + return (error); + return (set_regs(p, ®s)); +} + +int ptrace_write_u(p, off, data) + struct proc *p; + vm_offset_t off; + int data; +{ + struct trapframe frame_copy; + vm_offset_t min; + struct trapframe *tp; - return set_regs (p, ®s); + /* + * Privileged kernel state is scattered all over the user area. + * Only allow write access to parts of regs and to fpregs. + */ + min = (char *)p->p_md.md_regs - kstack; + if (off >= min && off <= min + sizeof(struct trapframe) - sizeof(int)) { + tp = TF_REGP(p); + frame_copy = *tp; + *(int *)((char *)&frame_copy + (off - min)) = data; + if (!EFLAGS_SECURE(frame_copy.tf_eflags, tp->tf_eflags) || + !CS_SECURE(frame_copy.tf_cs)) + return (EINVAL); + *(int*)((char *)p->p_addr + off) = data; + return (0); + } + min = offsetof(struct user, u_pcb) + offsetof(struct pcb, pcb_savefpu); + if (off >= min && off <= min + sizeof(struct save87) - sizeof(int)) { + *(int*)((char *)p->p_addr + off) = data; + return (0); + } + return (EFAULT); } int -fill_regs(struct proc *p, struct reg *regs) { +fill_regs(p, regs) + struct proc *p; + struct reg *regs; +{ struct trapframe *tp; - void *ptr = (char*)p->p_addr + - ((char*) p->p_md.md_regs - (char*) kstack); - tp = ptr; + tp = TF_REGP(p); regs->r_es = tp->tf_es; regs->r_ds = tp->tf_ds; regs->r_edi = tp->tf_edi; @@ -1513,16 +1519,20 @@ fill_regs(struct proc *p, struct reg *regs) { regs->r_eflags = tp->tf_eflags; regs->r_esp = tp->tf_esp; regs->r_ss = tp->tf_ss; - return 0; + return (0); } int -set_regs (struct proc *p, struct reg *regs) { +set_regs(p, regs) + struct proc *p; + struct reg *regs; +{ struct trapframe *tp; - void *ptr = (char*)p->p_addr + - ((char*) p->p_md.md_regs - (char*) kstack); - tp = ptr; + tp = TF_REGP(p); + if (!EFLAGS_SECURE(regs->r_eflags, tp->tf_eflags) || + !CS_SECURE(regs->r_cs)) + return (EINVAL); tp->tf_es = regs->r_es; tp->tf_ds = regs->r_ds; tp->tf_edi = regs->r_edi; @@ -1537,7 +1547,7 @@ set_regs (struct proc *p, struct reg *regs) { tp->tf_eflags = regs->r_eflags; tp->tf_esp = regs->r_esp; tp->tf_ss = regs->r_ss; - return 0; + return (0); } #ifndef DDB diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 0b4946f..57d586a 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 - * $Id: trap.c,v 1.42 1994/12/24 07:22:58 bde Exp $ + * $Id: trap.c,v 1.43 1995/01/09 16:04:39 davidg Exp $ */ /* @@ -73,24 +73,24 @@ void trap_fatal __P((struct trapframe *)); #define MAX_TRAP_MSG 27 char *trap_msg[] = { - "reserved addressing fault", /* 0 T_RESADFLT */ + "", /* 0 unused */ "privileged instruction fault", /* 1 T_PRIVINFLT */ - "reserved operand fault", /* 2 T_RESOPFLT */ + "", /* 2 unused */ "breakpoint instruction fault", /* 3 T_BPTFLT */ "", /* 4 unused */ - "system call trap", /* 5 T_SYSCALL */ + "", /* 5 unused */ "arithmetic trap", /* 6 T_ARITHTRAP */ "system forced exception", /* 7 T_ASTFLT */ - "segmentation (limit) fault", /* 8 T_SEGFLT */ + "", /* 8 unused */ "general protection fault", /* 9 T_PROTFLT */ "trace trap", /* 10 T_TRCTRAP */ "", /* 11 unused */ "page fault", /* 12 T_PAGEFLT */ - "page table fault", /* 13 T_TABLEFLT */ + "", /* 13 unused */ "alignment fault", /* 14 T_ALIGNFLT */ - "kernel stack pointer not valid", /* 15 T_KSPNOTVAL */ - "bus error", /* 16 T_BUSERR */ - "kernel debugger fault", /* 17 T_KDBTRAP */ + "", /* 15 unused */ + "", /* 16 unused */ + "", /* 17 unused */ "integer divide fault", /* 18 T_DIVIDE */ "non-maskable interrupt trap", /* 19 T_NMI */ "overflow trap", /* 20 T_OFLOW */ @@ -167,7 +167,6 @@ trap(frame) u_long eva; #endif - frame.tf_eflags &= ~PSL_NT; /* clear nested trap XXX */ type = frame.tf_trapno; code = frame.tf_err; @@ -178,9 +177,7 @@ trap(frame) p->p_md.md_regs = (int *)&frame; switch (type) { - case T_RESADFLT: /* reserved addressing fault */ case T_PRIVINFLT: /* privileged instruction fault */ - case T_RESOPFLT: /* reserved operand fault */ ucode = type; i = SIGILL; break; @@ -208,6 +205,9 @@ trap(frame) case T_PROTFLT: /* general protection fault */ case T_SEGNPFLT: /* segment not present fault */ case T_STKFLT: /* stack fault */ + case T_TSSFLT: /* invalid TSS fault */ + case T_DOUBLEFLT: /* double fault */ + default: ucode = code + BUS_SEGM_FAULT ; i = SIGBUS; break; @@ -276,10 +276,6 @@ trap(frame) ucode = T_FPOPFLT; i = SIGILL; break; - - default: - trap_fatal(&frame); - return; } } else { /* kernel trap */ @@ -291,12 +287,56 @@ trap(frame) case T_PROTFLT: /* general protection fault */ case T_SEGNPFLT: /* segment not present fault */ + /* + * Invalid segment selectors and out of bounds + * %eip's and %esp's can be set up in user mode. + * This causes a fault in kernel mode when the + * kernel tries to return to user mode. We want + * to get this fault so that we can fix the + * problem here and not have to check all the + * selectors and pointers when the user changes + * them. + */ +#define MAYBE_DORETI_FAULT(where, whereto) \ + do { \ + extern void where(void) __asm(__STRING(where)); \ + extern void whereto(void) __asm(__STRING(whereto)); \ + if (frame.tf_eip == (int)where) { \ + frame.tf_eip = (int)whereto; \ + return; \ + } \ + } while (0) + + if (intr_nesting_level == 0) { + MAYBE_DORETI_FAULT(doreti_iret, + doreti_iret_fault); + MAYBE_DORETI_FAULT(doreti_popl_ds, + doreti_popl_ds_fault); + MAYBE_DORETI_FAULT(doreti_popl_es, + doreti_popl_es_fault); + } if (curpcb && curpcb->pcb_onfault) { frame.tf_eip = (int)curpcb->pcb_onfault; return; } break; + case T_TSSFLT: + /* + * PSL_NT can be set in user mode and isn't cleared + * automatically when the kernel is entered. This + * causes a TSS fault when the kernel attempts to + * `iret' because the TSS link is uninitialized. We + * want to get this fault so that we can fix the + * problem here and not every time the kernel is + * entered. + */ + if (frame.tf_eflags & PSL_NT) { + frame.tf_eflags &= ~PSL_NT; + return; + } + break; + #ifdef DDB case T_BPTFLT: case T_TRCTRAP: diff --git a/sys/amd64/include/psl.h b/sys/amd64/include/psl.h index 906acd4..3d96dbc 100644 --- a/sys/amd64/include/psl.h +++ b/sys/amd64/include/psl.h @@ -34,11 +34,11 @@ * SUCH DAMAGE. * * from: @(#)psl.h 5.2 (Berkeley) 1/18/91 - * $Id: psl.h,v 1.4 1994/02/24 00:21:12 hsu Exp $ + * $Id: psl.h,v 1.5 1994/08/10 03:51:18 wollman Exp $ */ #ifndef _MACHINE_PSL_H_ -#define _MACHINE_PSL_H_ 1 +#define _MACHINE_PSL_H_ /* * 386 processor status longword. @@ -52,18 +52,37 @@ #define PSL_I 0x00000200 /* interrupt enable bit */ #define PSL_D 0x00000400 /* string instruction direction bit */ #define PSL_V 0x00000800 /* overflow bit */ -#define PSL_IOPL 0x00003000 /* i/o priviledge level enable */ +#define PSL_IOPL 0x00003000 /* i/o privilege level */ #define PSL_NT 0x00004000 /* nested task bit */ -#define PSL_RF 0x00010000 /* restart flag bit */ +#define PSL_RF 0x00010000 /* resume flag bit */ #define PSL_VM 0x00020000 /* virtual 8086 mode bit */ #define PSL_AC 0x00040000 /* alignment checking */ #define PSL_VIF 0x00080000 /* virtual interrupt enable */ #define PSL_VIP 0x00100000 /* virtual interrupt pending */ #define PSL_ID 0x00200000 /* identification bit */ -#define PSL_MBZ 0xffc08028 /* must be zero bits */ -#define PSL_MBO 0x00000002 /* must be one bits */ +/* + * The i486 manual says that we are not supposed to change reserved flags, + * but this is too much trouble since the reserved flags depend on the cpu + * and setting them to their historical values works in practice. + */ +#define PSL_RESERVED_DEFAULT 0x00000002 + +/* + * Initial flags for kernel and user mode. The kernel later inherits + * PSL_I and some other flags from user mode. + */ +#define PSL_KERNEL PSL_RESERVED_DEFAULT +#define PSL_USER (PSL_RESERVED_DEFAULT | PSL_I) + +/* + * Bits that can be changed in user mode on 486's. We allow these bits + * to be changed using ptrace(), sigreturn() and procfs. Setting PS_NT + * is undesireable but it may as well be allowed since users can inflict + * it on the kernel directly. Changes to PSL_AC are silently ignored on + * 386's. + */ +#define PSL_USERCHANGE (PSL_C | PSL_PF | PSL_AF | PSL_Z | PSL_N | PSL_T \ + | PSL_D | PSL_V | PSL_NT | PSL_AC) -#define PSL_USERSET (PSL_MBO | PSL_I) -#define PSL_USERCLR (PSL_MBZ | PSL_NT) -#endif /* _MACHINE_PSL_H_ */ +#endif /* !_MACHINE_PSL_H_ */ diff --git a/sys/amd64/include/trap.h b/sys/amd64/include/trap.h index aa832ff..e1ead77 100644 --- a/sys/amd64/include/trap.h +++ b/sys/amd64/include/trap.h @@ -34,33 +34,25 @@ * SUCH DAMAGE. * * from: @(#)trap.h 5.4 (Berkeley) 5/9/91 - * $Id: trap.h,v 1.2 1993/10/16 14:39:37 rgrimes Exp $ + * $Id: trap.h,v 1.3 1993/11/07 17:43:15 wollman Exp $ */ #ifndef _MACHINE_TRAP_H_ -#define _MACHINE_TRAP_H_ 1 +#define _MACHINE_TRAP_H_ /* * Trap type values * also known in trap.c for name strings */ -#define T_RESADFLT 0 /* reserved addressing */ #define T_PRIVINFLT 1 /* privileged instruction */ -#define T_RESOPFLT 2 /* reserved operand */ #define T_BPTFLT 3 /* breakpoint instruction */ -#define T_SYSCALL 5 /* system call (kcall) */ #define T_ARITHTRAP 6 /* arithmetic trap */ #define T_ASTFLT 7 /* system forced exception */ -#define T_SEGFLT 8 /* segmentation (limit) fault */ #define T_PROTFLT 9 /* protection fault */ -#define T_TRCTRAP 10 /* trace trap */ +#define T_TRCTRAP 10 /* debug exception (sic) */ #define T_PAGEFLT 12 /* page fault */ -#define T_TABLEFLT 13 /* page table fault */ #define T_ALIGNFLT 14 /* alignment fault */ -#define T_KSPNOTVAL 15 /* kernel stack pointer not valid */ -#define T_BUSERR 16 /* bus error */ -#define T_KDBTRAP 17 /* kernel debugger trap */ #define T_DIVIDE 18 /* integer divide fault */ #define T_NMI 19 /* non-maskable trap */ @@ -72,7 +64,9 @@ #define T_TSSFLT 25 /* invalid tss fault */ #define T_SEGNPFLT 26 /* segment not present fault */ #define T_STKFLT 27 /* stack fault */ -#define T_RESERVED 28 /* reserved fault base */ +#define T_RESERVED 28 /* reserved (unknown) */ + +/* XXX most of the following codes aren't used, but could be. */ /* definitions for <sys/signal.h> */ #define ILL_RESAD_FAULT T_RESADFLT @@ -98,4 +92,5 @@ /* Trap's coming from user mode */ #define T_USER 0x100 -#endif /* _MACHINE_TRAP_H_ */ + +#endif /* !_MACHINE_TRAP_H_ */ diff --git a/sys/i386/i386/exception.s b/sys/i386/i386/exception.s index e14934b..f6d6115 100644 --- a/sys/i386/i386/exception.s +++ b/sys/i386/i386/exception.s @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: exception.s,v 1.5 1994/09/28 03:37:49 bde Exp $ + * $Id: exception.s,v 1.6 1994/12/03 10:02:19 bde Exp $ */ #include "npx.h" /* NNPX */ @@ -158,43 +158,15 @@ IDTVEC(fpu) #else /* NNPX > 0 */ pushl $0; TRAP(T_ARITHTRAP) #endif /* NNPX > 0 */ - /* 17 - 31 reserved for future exp */ -IDTVEC(rsvd0) - pushl $0; TRAP(17) -IDTVEC(rsvd1) - pushl $0; TRAP(18) -IDTVEC(rsvd2) - pushl $0; TRAP(19) -IDTVEC(rsvd3) - pushl $0; TRAP(20) -IDTVEC(rsvd4) - pushl $0; TRAP(21) -IDTVEC(rsvd5) - pushl $0; TRAP(22) -IDTVEC(rsvd6) - pushl $0; TRAP(23) -IDTVEC(rsvd7) - pushl $0; TRAP(24) -IDTVEC(rsvd8) - pushl $0; TRAP(25) -IDTVEC(rsvd9) - pushl $0; TRAP(26) -IDTVEC(rsvd10) - pushl $0; TRAP(27) -IDTVEC(rsvd11) - pushl $0; TRAP(28) -IDTVEC(rsvd12) - pushl $0; TRAP(29) -IDTVEC(rsvd13) - pushl $0; TRAP(30) -IDTVEC(rsvd14) - pushl $0; TRAP(31) +IDTVEC(align) + TRAP(T_ALIGNFLT) SUPERALIGN_TEXT _alltraps: pushal pushl %ds pushl %es +alltraps_with_regs_pushed: movl $KDSEL,%eax movl %ax,%ds movl %ax,%es diff --git a/sys/i386/i386/locore.s b/sys/i386/i386/locore.s index 7f32a04..e28f065 100644 --- a/sys/i386/i386/locore.s +++ b/sys/i386/i386/locore.s @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)locore.s 7.3 (Berkeley) 5/13/91 - * $Id: locore.s,v 1.44 1994/11/06 22:18:45 phk Exp $ + * $Id: locore.s,v 1.45 1994/11/18 05:27:34 phk Exp $ */ /* @@ -176,7 +176,7 @@ NON_GPROF_ENTRY(btext) movl %esp, %ebp /* Don't trust what the BIOS gives for eflags. */ - pushl $PSL_MBO + pushl $PSL_KERNEL popfl /* Don't trust what the BIOS gives for %fs and %gs. */ @@ -764,7 +764,7 @@ reloc_gdt: pushl $0 /* unused */ pushl __udatasel /* ss */ pushl $0 /* esp - filled in by execve() */ - pushl $PSL_USERSET /* eflags (ring 0, int enab) */ + pushl $PSL_USER /* eflags (IOPL 0, int enab) */ pushl __ucodesel /* cs */ pushl $0 /* eip - filled in by execve() */ subl $(12*4),%esp /* space for rest of registers */ @@ -776,13 +776,14 @@ reloc_gdt: /* * now we've run main() and determined what cpu-type we are, we can - * enable WP mode on i486 cpus and above. + * enable write protection and alignment checking on i486 cpus and + * above. */ #if defined(I486_CPU) || defined(I586_CPU) cmpl $CPUCLASS_386,_cpu_class je 1f movl %cr0,%eax /* get control word */ - orl $CR0_WP,%eax /* enable write protect for all modes */ + orl $CR0_WP|CR0_AM,%eax /* enable i486 features */ movl %eax,%cr0 /* and do it */ #endif /* diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index eeba17b..7b59d96 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 - * $Id: machdep.c,v 1.99 1995/01/05 19:51:14 se Exp $ + * $Id: machdep.c,v 1.100 1995/01/09 16:04:37 davidg Exp $ */ #include "npx.h" @@ -459,7 +459,7 @@ vmtime(otime, olbolt, oicr) } #endif -extern int kstack[]; +extern char kstack[]; /* * Send an interrupt to process. @@ -607,48 +607,34 @@ sigreturn(p, uap, retval) if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0) return(EINVAL); + /* + * Don't allow users to change privileged or reserved flags. Let + * the hardware check for changing to excess I/O privilege. + */ +#define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) + eflags = scp->sc_ps; - if ((eflags & PSL_USERCLR) != 0 || - (eflags & PSL_USERSET) != PSL_USERSET || - (eflags & PSL_IOPL) < (regs[tEFLAGS] & PSL_IOPL)) { + if (!EFLAGS_SECURE(eflags, regs[tEFLAGS])) { #ifdef DEBUG - printf("sigreturn: eflags=0x%x\n", eflags); + printf("sigreturn: eflags = 0x%x\n", eflags); #endif return(EINVAL); } /* - * Sanity check the user's selectors and error if they - * are suspect. + * Don't allow users to load a valid privileged %cs. Let the + * hardware check for invalid selectors, excess privilege in + * other selectors, invalid %eip's and invalid %esp's. */ -#define max_ldt_sel(pcb) \ - ((pcb)->pcb_ldt ? (pcb)->pcb_ldt_len : (sizeof(ldt) / sizeof(ldt[0]))) - -#define valid_ldt_sel(sel) \ - (ISLDT(sel) && ISPL(sel) == SEL_UPL && \ - IDXSEL(sel) < max_ldt_sel(&p->p_addr->u_pcb)) - -#define null_sel(sel) \ - (!ISLDT(sel) && IDXSEL(sel) == 0) - - if (((scp->sc_cs&0xffff) != _ucodesel && !valid_ldt_sel(scp->sc_cs)) || - ((scp->sc_ss&0xffff) != _udatasel && !valid_ldt_sel(scp->sc_ss)) || - ((scp->sc_ds&0xffff) != _udatasel && !valid_ldt_sel(scp->sc_ds) && - !null_sel(scp->sc_ds)) || - ((scp->sc_es&0xffff) != _udatasel && !valid_ldt_sel(scp->sc_es) && - !null_sel(scp->sc_es))) { +#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) + if (!CS_SECURE(scp->sc_cs)) { #ifdef DEBUG - printf("sigreturn: cs=0x%x ss=0x%x ds=0x%x es=0x%x\n", - scp->sc_cs, scp->sc_ss, scp->sc_ds, scp->sc_es); + printf("sigreturn: cs = 0x%x\n", scp->sc_cs); #endif trapsignal(p, SIGBUS, T_PROTFLT); return(EINVAL); } -#undef max_ldt_sel -#undef valid_ldt_sel -#undef null_sel - /* restore scratch registers */ regs[tEAX] = scp->sc_eax; regs[tEBX] = scp->sc_ebx; @@ -863,7 +849,7 @@ setregs(p, entry, stack) bzero(regs, sizeof(struct trapframe)); regs[tEIP] = entry; regs[tESP] = stack; - regs[tEFLAGS] = PSL_USERSET | (regs[tEFLAGS] & PSL_T); + regs[tEFLAGS] = PSL_USER | (regs[tEFLAGS] & PSL_T); regs[tSS] = _udatasel; regs[tDS] = _udatasel; regs[tES] = _udatasel; @@ -1106,11 +1092,8 @@ extern inthand_t IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl), IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm), IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), - IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0), - IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4), - IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8), - IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12), - IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(syscall); + IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align), + IDTVEC(syscall); void sdtossd(sd, ssd) @@ -1191,6 +1174,8 @@ init386(first) ssdtosd(&ldt_segs[x], &ldt[x].sd); /* exceptions */ + for (x = 0; x < NIDT; x++) + setidt(x, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL); setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL); setidt(1, &IDTVEC(dbg), SDT_SYS386TGT, SEL_KPL); setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL); @@ -1208,21 +1193,7 @@ init386(first) setidt(14, &IDTVEC(page), SDT_SYS386TGT, SEL_KPL); setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL); setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL); - setidt(17, &IDTVEC(rsvd0), SDT_SYS386TGT, SEL_KPL); - setidt(18, &IDTVEC(rsvd1), SDT_SYS386TGT, SEL_KPL); - setidt(19, &IDTVEC(rsvd2), SDT_SYS386TGT, SEL_KPL); - setidt(20, &IDTVEC(rsvd3), SDT_SYS386TGT, SEL_KPL); - setidt(21, &IDTVEC(rsvd4), SDT_SYS386TGT, SEL_KPL); - setidt(22, &IDTVEC(rsvd5), SDT_SYS386TGT, SEL_KPL); - setidt(23, &IDTVEC(rsvd6), SDT_SYS386TGT, SEL_KPL); - setidt(24, &IDTVEC(rsvd7), SDT_SYS386TGT, SEL_KPL); - setidt(25, &IDTVEC(rsvd8), SDT_SYS386TGT, SEL_KPL); - setidt(26, &IDTVEC(rsvd9), SDT_SYS386TGT, SEL_KPL); - setidt(27, &IDTVEC(rsvd10), SDT_SYS386TGT, SEL_KPL); - setidt(28, &IDTVEC(rsvd11), SDT_SYS386TGT, SEL_KPL); - setidt(29, &IDTVEC(rsvd12), SDT_SYS386TGT, SEL_KPL); - setidt(30, &IDTVEC(rsvd13), SDT_SYS386TGT, SEL_KPL); - setidt(31, &IDTVEC(rsvd14), SDT_SYS386TGT, SEL_KPL); + setidt(17, &IDTVEC(align), SDT_SYS386TGT, SEL_KPL); #include "isa.h" #if NISA >0 @@ -1445,60 +1416,95 @@ test_page(address, pattern) * index into the user block. Don't you just *love* virtual memory? * (I'm starting to think seymour is right...) */ +#define TF_REGP(p) ((struct trapframe *) \ + ((char *)(p)->p_addr \ + + ((char *)(p)->p_md.md_regs - kstack))) int -ptrace_set_pc (struct proc *p, unsigned int addr) { - void *regs = (char*)p->p_addr + - ((char*) p->p_md.md_regs - (char*) kstack); - - ((struct trapframe *)regs)->tf_eip = addr; - return 0; +ptrace_set_pc(p, addr) + struct proc *p; + unsigned int addr; +{ + TF_REGP(p)->tf_eip = addr; + return (0); } int -ptrace_single_step (struct proc *p) { - void *regs = (char*)p->p_addr + - ((char*) p->p_md.md_regs - (char*) kstack); - - ((struct trapframe *)regs)->tf_eflags |= PSL_T; - return 0; +ptrace_single_step(p) + struct proc *p; +{ + TF_REGP(p)->tf_eflags |= PSL_T; + return (0); } -/* - * Copy the registers to user-space. - */ - int -ptrace_getregs (struct proc *p, unsigned int *addr) { +ptrace_getregs(p, addr) + struct proc *p; + unsigned int *addr; +{ int error; - struct reg regs = {0}; + struct reg regs; - error = fill_regs (p, ®s); + error = fill_regs(p, ®s); if (error) - return error; - - return copyout (®s, addr, sizeof (regs)); + return (error); + return (copyout(®s, addr, sizeof regs)); } int -ptrace_setregs (struct proc *p, unsigned int *addr) { +ptrace_setregs(p, addr) + struct proc *p; + unsigned int *addr; +{ int error; - struct reg regs = {0}; + struct reg regs; - error = copyin (addr, ®s, sizeof(regs)); + error = copyin(addr, ®s, sizeof regs); if (error) - return error; + return (error); + return (set_regs(p, ®s)); +} + +int ptrace_write_u(p, off, data) + struct proc *p; + vm_offset_t off; + int data; +{ + struct trapframe frame_copy; + vm_offset_t min; + struct trapframe *tp; - return set_regs (p, ®s); + /* + * Privileged kernel state is scattered all over the user area. + * Only allow write access to parts of regs and to fpregs. + */ + min = (char *)p->p_md.md_regs - kstack; + if (off >= min && off <= min + sizeof(struct trapframe) - sizeof(int)) { + tp = TF_REGP(p); + frame_copy = *tp; + *(int *)((char *)&frame_copy + (off - min)) = data; + if (!EFLAGS_SECURE(frame_copy.tf_eflags, tp->tf_eflags) || + !CS_SECURE(frame_copy.tf_cs)) + return (EINVAL); + *(int*)((char *)p->p_addr + off) = data; + return (0); + } + min = offsetof(struct user, u_pcb) + offsetof(struct pcb, pcb_savefpu); + if (off >= min && off <= min + sizeof(struct save87) - sizeof(int)) { + *(int*)((char *)p->p_addr + off) = data; + return (0); + } + return (EFAULT); } int -fill_regs(struct proc *p, struct reg *regs) { +fill_regs(p, regs) + struct proc *p; + struct reg *regs; +{ struct trapframe *tp; - void *ptr = (char*)p->p_addr + - ((char*) p->p_md.md_regs - (char*) kstack); - tp = ptr; + tp = TF_REGP(p); regs->r_es = tp->tf_es; regs->r_ds = tp->tf_ds; regs->r_edi = tp->tf_edi; @@ -1513,16 +1519,20 @@ fill_regs(struct proc *p, struct reg *regs) { regs->r_eflags = tp->tf_eflags; regs->r_esp = tp->tf_esp; regs->r_ss = tp->tf_ss; - return 0; + return (0); } int -set_regs (struct proc *p, struct reg *regs) { +set_regs(p, regs) + struct proc *p; + struct reg *regs; +{ struct trapframe *tp; - void *ptr = (char*)p->p_addr + - ((char*) p->p_md.md_regs - (char*) kstack); - tp = ptr; + tp = TF_REGP(p); + if (!EFLAGS_SECURE(regs->r_eflags, tp->tf_eflags) || + !CS_SECURE(regs->r_cs)) + return (EINVAL); tp->tf_es = regs->r_es; tp->tf_ds = regs->r_ds; tp->tf_edi = regs->r_edi; @@ -1537,7 +1547,7 @@ set_regs (struct proc *p, struct reg *regs) { tp->tf_eflags = regs->r_eflags; tp->tf_esp = regs->r_esp; tp->tf_ss = regs->r_ss; - return 0; + return (0); } #ifndef DDB diff --git a/sys/i386/i386/procfs_machdep.c b/sys/i386/i386/procfs_machdep.c index d122fc6..b22eef5 100644 --- a/sys/i386/i386/procfs_machdep.c +++ b/sys/i386/i386/procfs_machdep.c @@ -37,7 +37,7 @@ * @(#)procfs_machdep.c 8.3 (Berkeley) 1/27/94 * * From: - * $Id: procfs_i386.c,v 3.2 1993/12/15 09:40:17 jsp Exp $ + * $Id: procfs_machdep.c,v 1.2 1994/05/25 08:54:48 rgrimes Exp $ */ /* @@ -52,6 +52,8 @@ * Update the current register set from the passed in regs * structure. Take care to avoid clobbering special CPU * registers or privileged bits in the PSL. + * Depending on the architecture this may have fix-up work to do, + * especially if the IAR or PCW are modified. * The process is stopped at the time write_regs is called. * * procfs_read_fpregs, procfs_write_fpregs @@ -76,51 +78,42 @@ #include <machine/frame.h> #include <miscfs/procfs/procfs.h> +extern char kstack[]; /* XXX */ + int procfs_read_regs(p, regs) struct proc *p; struct reg *regs; { - struct trapframe *f; - if ((p->p_flag & P_INMEM) == 0) return (EIO); - - f = (struct trapframe *) p->p_md.md_regs; - bcopy((void *) f, (void *) regs, sizeof(*regs)); - - return (0); + return (fill_regs(p, regs)); } -/* - * Update the process's current register - * set. Depending on the architecture this - * may have fix-up work to do, especially - * if the IAR or PCW are modified. - */ int procfs_write_regs(p, regs) struct proc *p; struct reg *regs; { - struct trapframe *f; - if ((p->p_flag & P_INMEM) == 0) return (EIO); - - f = (struct trapframe *) p->p_md.md_regs; - bcopy((void *) regs, (void *) f, sizeof(*regs)); - - return (0); + return (set_regs(p, regs)); } +/* + * Ptrace doesn't support fpregs at all, and there are no security holes + * or translations for fpregs, so we can just copy them. + */ + int procfs_read_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { - - return (EOPNOTSUPP); + if ((p->p_flag & P_INMEM) == 0) + return (EIO); + bcopy(&p->p_addr->u_pcb.pcb_savefpu, fpregs, sizeof *fpregs); + return (0); } int @@ -128,25 +121,19 @@ procfs_write_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { - - return (EOPNOTSUPP); + if ((p->p_flag & P_INMEM) == 0) + return (EIO); + bcopy(fpregs, &p->p_addr->u_pcb.pcb_savefpu, sizeof *fpregs); + return (0); } - int procfs_sstep(p) struct proc *p; { - int error; - struct reg r; - - error = procfs_read_regs(p, &r); - if (error == 0) { - r.r_eflags |= PSL_T; - error = procfs_write_regs(p, &r); - } - - return (error); + if ((p->p_flag & P_INMEM) == 0) + return (EIO); + return (ptrace_single_step(p)); } void diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index 0b4946f..57d586a 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 - * $Id: trap.c,v 1.42 1994/12/24 07:22:58 bde Exp $ + * $Id: trap.c,v 1.43 1995/01/09 16:04:39 davidg Exp $ */ /* @@ -73,24 +73,24 @@ void trap_fatal __P((struct trapframe *)); #define MAX_TRAP_MSG 27 char *trap_msg[] = { - "reserved addressing fault", /* 0 T_RESADFLT */ + "", /* 0 unused */ "privileged instruction fault", /* 1 T_PRIVINFLT */ - "reserved operand fault", /* 2 T_RESOPFLT */ + "", /* 2 unused */ "breakpoint instruction fault", /* 3 T_BPTFLT */ "", /* 4 unused */ - "system call trap", /* 5 T_SYSCALL */ + "", /* 5 unused */ "arithmetic trap", /* 6 T_ARITHTRAP */ "system forced exception", /* 7 T_ASTFLT */ - "segmentation (limit) fault", /* 8 T_SEGFLT */ + "", /* 8 unused */ "general protection fault", /* 9 T_PROTFLT */ "trace trap", /* 10 T_TRCTRAP */ "", /* 11 unused */ "page fault", /* 12 T_PAGEFLT */ - "page table fault", /* 13 T_TABLEFLT */ + "", /* 13 unused */ "alignment fault", /* 14 T_ALIGNFLT */ - "kernel stack pointer not valid", /* 15 T_KSPNOTVAL */ - "bus error", /* 16 T_BUSERR */ - "kernel debugger fault", /* 17 T_KDBTRAP */ + "", /* 15 unused */ + "", /* 16 unused */ + "", /* 17 unused */ "integer divide fault", /* 18 T_DIVIDE */ "non-maskable interrupt trap", /* 19 T_NMI */ "overflow trap", /* 20 T_OFLOW */ @@ -167,7 +167,6 @@ trap(frame) u_long eva; #endif - frame.tf_eflags &= ~PSL_NT; /* clear nested trap XXX */ type = frame.tf_trapno; code = frame.tf_err; @@ -178,9 +177,7 @@ trap(frame) p->p_md.md_regs = (int *)&frame; switch (type) { - case T_RESADFLT: /* reserved addressing fault */ case T_PRIVINFLT: /* privileged instruction fault */ - case T_RESOPFLT: /* reserved operand fault */ ucode = type; i = SIGILL; break; @@ -208,6 +205,9 @@ trap(frame) case T_PROTFLT: /* general protection fault */ case T_SEGNPFLT: /* segment not present fault */ case T_STKFLT: /* stack fault */ + case T_TSSFLT: /* invalid TSS fault */ + case T_DOUBLEFLT: /* double fault */ + default: ucode = code + BUS_SEGM_FAULT ; i = SIGBUS; break; @@ -276,10 +276,6 @@ trap(frame) ucode = T_FPOPFLT; i = SIGILL; break; - - default: - trap_fatal(&frame); - return; } } else { /* kernel trap */ @@ -291,12 +287,56 @@ trap(frame) case T_PROTFLT: /* general protection fault */ case T_SEGNPFLT: /* segment not present fault */ + /* + * Invalid segment selectors and out of bounds + * %eip's and %esp's can be set up in user mode. + * This causes a fault in kernel mode when the + * kernel tries to return to user mode. We want + * to get this fault so that we can fix the + * problem here and not have to check all the + * selectors and pointers when the user changes + * them. + */ +#define MAYBE_DORETI_FAULT(where, whereto) \ + do { \ + extern void where(void) __asm(__STRING(where)); \ + extern void whereto(void) __asm(__STRING(whereto)); \ + if (frame.tf_eip == (int)where) { \ + frame.tf_eip = (int)whereto; \ + return; \ + } \ + } while (0) + + if (intr_nesting_level == 0) { + MAYBE_DORETI_FAULT(doreti_iret, + doreti_iret_fault); + MAYBE_DORETI_FAULT(doreti_popl_ds, + doreti_popl_ds_fault); + MAYBE_DORETI_FAULT(doreti_popl_es, + doreti_popl_es_fault); + } if (curpcb && curpcb->pcb_onfault) { frame.tf_eip = (int)curpcb->pcb_onfault; return; } break; + case T_TSSFLT: + /* + * PSL_NT can be set in user mode and isn't cleared + * automatically when the kernel is entered. This + * causes a TSS fault when the kernel attempts to + * `iret' because the TSS link is uninitialized. We + * want to get this fault so that we can fix the + * problem here and not every time the kernel is + * entered. + */ + if (frame.tf_eflags & PSL_NT) { + frame.tf_eflags &= ~PSL_NT; + return; + } + break; + #ifdef DDB case T_BPTFLT: case T_TRCTRAP: diff --git a/sys/i386/include/psl.h b/sys/i386/include/psl.h index 906acd4..3d96dbc 100644 --- a/sys/i386/include/psl.h +++ b/sys/i386/include/psl.h @@ -34,11 +34,11 @@ * SUCH DAMAGE. * * from: @(#)psl.h 5.2 (Berkeley) 1/18/91 - * $Id: psl.h,v 1.4 1994/02/24 00:21:12 hsu Exp $ + * $Id: psl.h,v 1.5 1994/08/10 03:51:18 wollman Exp $ */ #ifndef _MACHINE_PSL_H_ -#define _MACHINE_PSL_H_ 1 +#define _MACHINE_PSL_H_ /* * 386 processor status longword. @@ -52,18 +52,37 @@ #define PSL_I 0x00000200 /* interrupt enable bit */ #define PSL_D 0x00000400 /* string instruction direction bit */ #define PSL_V 0x00000800 /* overflow bit */ -#define PSL_IOPL 0x00003000 /* i/o priviledge level enable */ +#define PSL_IOPL 0x00003000 /* i/o privilege level */ #define PSL_NT 0x00004000 /* nested task bit */ -#define PSL_RF 0x00010000 /* restart flag bit */ +#define PSL_RF 0x00010000 /* resume flag bit */ #define PSL_VM 0x00020000 /* virtual 8086 mode bit */ #define PSL_AC 0x00040000 /* alignment checking */ #define PSL_VIF 0x00080000 /* virtual interrupt enable */ #define PSL_VIP 0x00100000 /* virtual interrupt pending */ #define PSL_ID 0x00200000 /* identification bit */ -#define PSL_MBZ 0xffc08028 /* must be zero bits */ -#define PSL_MBO 0x00000002 /* must be one bits */ +/* + * The i486 manual says that we are not supposed to change reserved flags, + * but this is too much trouble since the reserved flags depend on the cpu + * and setting them to their historical values works in practice. + */ +#define PSL_RESERVED_DEFAULT 0x00000002 + +/* + * Initial flags for kernel and user mode. The kernel later inherits + * PSL_I and some other flags from user mode. + */ +#define PSL_KERNEL PSL_RESERVED_DEFAULT +#define PSL_USER (PSL_RESERVED_DEFAULT | PSL_I) + +/* + * Bits that can be changed in user mode on 486's. We allow these bits + * to be changed using ptrace(), sigreturn() and procfs. Setting PS_NT + * is undesireable but it may as well be allowed since users can inflict + * it on the kernel directly. Changes to PSL_AC are silently ignored on + * 386's. + */ +#define PSL_USERCHANGE (PSL_C | PSL_PF | PSL_AF | PSL_Z | PSL_N | PSL_T \ + | PSL_D | PSL_V | PSL_NT | PSL_AC) -#define PSL_USERSET (PSL_MBO | PSL_I) -#define PSL_USERCLR (PSL_MBZ | PSL_NT) -#endif /* _MACHINE_PSL_H_ */ +#endif /* !_MACHINE_PSL_H_ */ diff --git a/sys/i386/include/trap.h b/sys/i386/include/trap.h index aa832ff..e1ead77 100644 --- a/sys/i386/include/trap.h +++ b/sys/i386/include/trap.h @@ -34,33 +34,25 @@ * SUCH DAMAGE. * * from: @(#)trap.h 5.4 (Berkeley) 5/9/91 - * $Id: trap.h,v 1.2 1993/10/16 14:39:37 rgrimes Exp $ + * $Id: trap.h,v 1.3 1993/11/07 17:43:15 wollman Exp $ */ #ifndef _MACHINE_TRAP_H_ -#define _MACHINE_TRAP_H_ 1 +#define _MACHINE_TRAP_H_ /* * Trap type values * also known in trap.c for name strings */ -#define T_RESADFLT 0 /* reserved addressing */ #define T_PRIVINFLT 1 /* privileged instruction */ -#define T_RESOPFLT 2 /* reserved operand */ #define T_BPTFLT 3 /* breakpoint instruction */ -#define T_SYSCALL 5 /* system call (kcall) */ #define T_ARITHTRAP 6 /* arithmetic trap */ #define T_ASTFLT 7 /* system forced exception */ -#define T_SEGFLT 8 /* segmentation (limit) fault */ #define T_PROTFLT 9 /* protection fault */ -#define T_TRCTRAP 10 /* trace trap */ +#define T_TRCTRAP 10 /* debug exception (sic) */ #define T_PAGEFLT 12 /* page fault */ -#define T_TABLEFLT 13 /* page table fault */ #define T_ALIGNFLT 14 /* alignment fault */ -#define T_KSPNOTVAL 15 /* kernel stack pointer not valid */ -#define T_BUSERR 16 /* bus error */ -#define T_KDBTRAP 17 /* kernel debugger trap */ #define T_DIVIDE 18 /* integer divide fault */ #define T_NMI 19 /* non-maskable trap */ @@ -72,7 +64,9 @@ #define T_TSSFLT 25 /* invalid tss fault */ #define T_SEGNPFLT 26 /* segment not present fault */ #define T_STKFLT 27 /* stack fault */ -#define T_RESERVED 28 /* reserved fault base */ +#define T_RESERVED 28 /* reserved (unknown) */ + +/* XXX most of the following codes aren't used, but could be. */ /* definitions for <sys/signal.h> */ #define ILL_RESAD_FAULT T_RESADFLT @@ -98,4 +92,5 @@ /* Trap's coming from user mode */ #define T_USER 0x100 -#endif /* _MACHINE_TRAP_H_ */ + +#endif /* !_MACHINE_TRAP_H_ */ diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 0b4946f..57d586a 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 - * $Id: trap.c,v 1.42 1994/12/24 07:22:58 bde Exp $ + * $Id: trap.c,v 1.43 1995/01/09 16:04:39 davidg Exp $ */ /* @@ -73,24 +73,24 @@ void trap_fatal __P((struct trapframe *)); #define MAX_TRAP_MSG 27 char *trap_msg[] = { - "reserved addressing fault", /* 0 T_RESADFLT */ + "", /* 0 unused */ "privileged instruction fault", /* 1 T_PRIVINFLT */ - "reserved operand fault", /* 2 T_RESOPFLT */ + "", /* 2 unused */ "breakpoint instruction fault", /* 3 T_BPTFLT */ "", /* 4 unused */ - "system call trap", /* 5 T_SYSCALL */ + "", /* 5 unused */ "arithmetic trap", /* 6 T_ARITHTRAP */ "system forced exception", /* 7 T_ASTFLT */ - "segmentation (limit) fault", /* 8 T_SEGFLT */ + "", /* 8 unused */ "general protection fault", /* 9 T_PROTFLT */ "trace trap", /* 10 T_TRCTRAP */ "", /* 11 unused */ "page fault", /* 12 T_PAGEFLT */ - "page table fault", /* 13 T_TABLEFLT */ + "", /* 13 unused */ "alignment fault", /* 14 T_ALIGNFLT */ - "kernel stack pointer not valid", /* 15 T_KSPNOTVAL */ - "bus error", /* 16 T_BUSERR */ - "kernel debugger fault", /* 17 T_KDBTRAP */ + "", /* 15 unused */ + "", /* 16 unused */ + "", /* 17 unused */ "integer divide fault", /* 18 T_DIVIDE */ "non-maskable interrupt trap", /* 19 T_NMI */ "overflow trap", /* 20 T_OFLOW */ @@ -167,7 +167,6 @@ trap(frame) u_long eva; #endif - frame.tf_eflags &= ~PSL_NT; /* clear nested trap XXX */ type = frame.tf_trapno; code = frame.tf_err; @@ -178,9 +177,7 @@ trap(frame) p->p_md.md_regs = (int *)&frame; switch (type) { - case T_RESADFLT: /* reserved addressing fault */ case T_PRIVINFLT: /* privileged instruction fault */ - case T_RESOPFLT: /* reserved operand fault */ ucode = type; i = SIGILL; break; @@ -208,6 +205,9 @@ trap(frame) case T_PROTFLT: /* general protection fault */ case T_SEGNPFLT: /* segment not present fault */ case T_STKFLT: /* stack fault */ + case T_TSSFLT: /* invalid TSS fault */ + case T_DOUBLEFLT: /* double fault */ + default: ucode = code + BUS_SEGM_FAULT ; i = SIGBUS; break; @@ -276,10 +276,6 @@ trap(frame) ucode = T_FPOPFLT; i = SIGILL; break; - - default: - trap_fatal(&frame); - return; } } else { /* kernel trap */ @@ -291,12 +287,56 @@ trap(frame) case T_PROTFLT: /* general protection fault */ case T_SEGNPFLT: /* segment not present fault */ + /* + * Invalid segment selectors and out of bounds + * %eip's and %esp's can be set up in user mode. + * This causes a fault in kernel mode when the + * kernel tries to return to user mode. We want + * to get this fault so that we can fix the + * problem here and not have to check all the + * selectors and pointers when the user changes + * them. + */ +#define MAYBE_DORETI_FAULT(where, whereto) \ + do { \ + extern void where(void) __asm(__STRING(where)); \ + extern void whereto(void) __asm(__STRING(whereto)); \ + if (frame.tf_eip == (int)where) { \ + frame.tf_eip = (int)whereto; \ + return; \ + } \ + } while (0) + + if (intr_nesting_level == 0) { + MAYBE_DORETI_FAULT(doreti_iret, + doreti_iret_fault); + MAYBE_DORETI_FAULT(doreti_popl_ds, + doreti_popl_ds_fault); + MAYBE_DORETI_FAULT(doreti_popl_es, + doreti_popl_es_fault); + } if (curpcb && curpcb->pcb_onfault) { frame.tf_eip = (int)curpcb->pcb_onfault; return; } break; + case T_TSSFLT: + /* + * PSL_NT can be set in user mode and isn't cleared + * automatically when the kernel is entered. This + * causes a TSS fault when the kernel attempts to + * `iret' because the TSS link is uninitialized. We + * want to get this fault so that we can fix the + * problem here and not every time the kernel is + * entered. + */ + if (frame.tf_eflags & PSL_NT) { + frame.tf_eflags &= ~PSL_NT; + return; + } + break; + #ifdef DDB case T_BPTFLT: case T_TRCTRAP: diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 63537bd..692f2c5 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: sys_process.c,v 1.6 1994/08/18 22:35:05 wollman Exp $ + * $Id: sys_process.c,v 1.7 1994/09/25 19:33:49 phk Exp $ */ #include <sys/param.h> @@ -326,13 +326,9 @@ ptrace(curp, uap, retval) *retval = *(int*)((u_int)p->p_addr + (u_int)uap->addr); return 0; case PT_WRITE_U: - if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) { - return EFAULT; - } p->p_addr->u_kproc.kp_proc = *p; fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); - *(int*)((u_int)p->p_addr + (u_int)uap->addr) = uap->data; - return 0; + return ptrace_write_u(p, (vm_offset_t)uap->addr, uap->data); case PT_KILL: p->p_xstat = SIGKILL; setrunnable(p); |