Kernel: pass FPU restore exception to user process
Previously, user processes could cause a kernel panic upon FPU state restore, by passing bogus FPU state to the kernel (through e.g. sigreturn). With this patch, the process is now sent a SIGFPE signal instead.
This commit is contained in:
@@ -10,6 +10,7 @@ OBJ= test1 test2 test3 test4 test5 test6 test7 test8 test9 \
|
||||
test30 test31 test32 test34 test35 test36 test37 test38 test39 \
|
||||
test40 test41 test42 test45 test47 test48 test49 \
|
||||
test50 test53 test54 test55 test58 \
|
||||
test62 \
|
||||
t10a t11a t11b t40a t40b t40c t40d t40e t40f t60a t60b \
|
||||
|
||||
ROOTOBJ= test11 test33 test43 test44 test46 test56 test60 test61
|
||||
@@ -113,3 +114,4 @@ test60: test60.c
|
||||
t60a: t60a.c
|
||||
t60b: t60b.c
|
||||
test61: test61.c
|
||||
test62: test62.c
|
||||
|
||||
2
test/run
2
test/run
@@ -14,7 +14,7 @@ badones= # list of tests that failed
|
||||
tests=" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
|
||||
61 \
|
||||
61 62 \
|
||||
sh1.sh sh2.sh interp.sh"
|
||||
tests_no=`expr 0`
|
||||
|
||||
|
||||
72
test/test62.c
Normal file
72
test/test62.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/* FPU state corruption test. This used to be able to crash the kernel. */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <machine/fpu.h>
|
||||
|
||||
#define MAX_ERROR 1
|
||||
#include "common.c"
|
||||
|
||||
double state = 2.0;
|
||||
static int count;
|
||||
|
||||
static void use_fpu(int n)
|
||||
{
|
||||
state += (double) n * 0.5;
|
||||
}
|
||||
|
||||
static void crashed(int sig)
|
||||
{
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void handler(int sig, int code, struct sigcontext *sc)
|
||||
{
|
||||
memset(&sc->sc_fpu_state, count, sizeof(sc->sc_fpu_state));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
start(62);
|
||||
subtest = 0;
|
||||
|
||||
signal(SIGUSR1, (void (*)(int)) handler);
|
||||
|
||||
/* Initialize the FPU state. This state is inherited, too. */
|
||||
use_fpu(-1);
|
||||
|
||||
for (count = 0; count <= 255; count++) {
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
e(1);
|
||||
|
||||
break;
|
||||
|
||||
case 0:
|
||||
signal(SIGFPE, crashed);
|
||||
|
||||
/* Load bad state into the kernel. */
|
||||
if (kill(getpid(), SIGUSR1)) e(2);
|
||||
|
||||
/* Let the kernel restore the state. */
|
||||
use_fpu(count);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
default:
|
||||
/* We cannot tell exactly whether what happened is correct or
|
||||
* not -- certainly not in a platform-independent way. However,
|
||||
* if the whole system keeps running, that's good enough.
|
||||
*/
|
||||
(void) wait(&status);
|
||||
}
|
||||
}
|
||||
|
||||
if (state <= 1.4 || state >= 1.6) e(3);
|
||||
|
||||
quit();
|
||||
}
|
||||
Reference in New Issue
Block a user