Skip to content

Commit

Permalink
alpha: fix FEN fault handling
Browse files Browse the repository at this point in the history
Type 3 instruction fault (FPU insn with FPU disabled) is handled
by quietly enabling FPU and returning.  Which is fine, except that
we need to do that both for fault in userland and in the kernel;
the latter *can* legitimately happen - all it takes is this:

.global _start
_start:
	call_pal 0xae
	lda $0, 0
	ldq $0, 0($0)

- call_pal CLRFEN to clear "FPU enabled" flag and arrange for
a signal delivery (SIGSEGV in this case).

Fixed by moving the handling of type 3 into the common part of
do_entIF(), before we check for kernel vs. user mode.

Incidentally, check for kernel mode is unidiomatic; the normal
way to do that is !user_mode(regs).  The difference is that
the open-coded variant treats any of bits 63..3 of regs->ps being
set as "it's user mode" while the normal approach is to check just
the bit 3.  PS is a 4-bit register and regs->ps always will have
bits 63..4 clear, so the open-code variant here is actually equivalent
to !user_mode(regs).  Harder to follow, though...

Reproducer above will crash any box where CLRFEN is not ignored by
PAL (== any actual hardware, AFAICS; PAL used in qemu doesn't
bother implementing that crap).

Cc: [email protected] # all way back...
Reviewed-by: Richard Henderson <[email protected]>
Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Matt Turner <[email protected]>
  • Loading branch information
Al Viro authored and mattst88 committed Feb 25, 2023
1 parent 4da2bd3 commit d3c51b7
Showing 1 changed file with 15 additions and 15 deletions.
30 changes: 15 additions & 15 deletions arch/alpha/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,21 @@ do_entIF(unsigned long type, struct pt_regs *regs)
{
int signo, code;

if ((regs->ps & ~IPL_MAX) == 0) {
if (type == 3) { /* FEN fault */
/* Irritating users can call PAL_clrfen to disable the
FPU for the process. The kernel will then trap in
do_switch_stack and undo_switch_stack when we try
to save and restore the FP registers.
Given that GCC by default generates code that uses the
FP registers, PAL_clrfen is not useful except for DoS
attacks. So turn the bleeding FPU back on and be done
with it. */
current_thread_info()->pcb.flags |= 1;
__reload_thread(&current_thread_info()->pcb);
return;
}
if (!user_mode(regs)) {
if (type == 1) {
const unsigned int *data
= (const unsigned int *) regs->pc;
Expand Down Expand Up @@ -366,20 +380,6 @@ do_entIF(unsigned long type, struct pt_regs *regs)
}
break;

case 3: /* FEN fault */
/* Irritating users can call PAL_clrfen to disable the
FPU for the process. The kernel will then trap in
do_switch_stack and undo_switch_stack when we try
to save and restore the FP registers.
Given that GCC by default generates code that uses the
FP registers, PAL_clrfen is not useful except for DoS
attacks. So turn the bleeding FPU back on and be done
with it. */
current_thread_info()->pcb.flags |= 1;
__reload_thread(&current_thread_info()->pcb);
return;

case 5: /* illoc */
default: /* unexpected instruction-fault type */
;
Expand Down

0 comments on commit d3c51b7

Please sign in to comment.