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:
David van Moolenbroek
2012-03-03 19:25:57 +01:00
parent 4b6a98de5f
commit 0a8a2ecfb5
10 changed files with 125 additions and 13 deletions

View File

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

View File

@@ -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
View 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();
}