1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include <signal.h>
8 : #include <stdio.h>
9 : #include <stdlib.h>
10 : #include <string.h>
11 :
12 : #include "native_client/src/shared/platform/nacl_check.h"
13 : #include "native_client/src/shared/platform/nacl_log.h"
14 : #include "native_client/src/trusted/service_runtime/nacl_all_modules.h"
15 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
16 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
17 : #include "native_client/src/trusted/service_runtime/sel_rt.h"
18 :
19 :
20 : /*
21 : * This test case checks for an obscure gotcha in the Linux kernel.
22 : *
23 : * Some kernels do not assign to the top 2 bytes of the REG_CS array
24 : * entry when writing %cs to the stack. If NaCl's signal handler does
25 : * not disregard the top 16 bits of REG_CS, it will incorrectly treat
26 : * a fault in trusted code as coming from untrusted code, and it will
27 : * crash while attempting to restore %gs.
28 : *
29 : * Specifically, this happens in 32-bit processes on the 64-bit kernel
30 : * from Ubuntu Hardy.
31 : *
32 : * See http://code.google.com/p/nativeclient/issues/detail?id=1486
33 : */
34 :
35 1 : int main(void) {
36 1 : size_t stack_size = SIGSTKSZ;
37 : char *stack;
38 : stack_t st;
39 : int rc;
40 :
41 1 : NaClAllModulesInit();
42 1 : NaClSignalHandlerInit();
43 :
44 : /*
45 : * Allocate and register a signal stack, and ensure that it is
46 : * filled with non-zero bytes.
47 : */
48 1 : stack = malloc(stack_size);
49 1 : CHECK(stack != NULL);
50 1 : memset(stack, 0xff, stack_size);
51 1 : st.ss_size = stack_size;
52 1 : st.ss_sp = stack;
53 1 : st.ss_flags = 0;
54 1 : rc = sigaltstack(&st, NULL);
55 1 : CHECK(rc == 0);
56 :
57 : /*
58 : * Trigger a signal. This should produce a "** Signal X from
59 : * trusted code" message, which the test runner checks for.
60 : */
61 1 : fprintf(stderr, "** intended_exit_status=trusted_segfault\n");
62 :
63 : /*
64 : * Clang transmutes a NULL pointer reference into a generic "undefined"
65 : * case. That code crashes with a different signal than an actual bad
66 : * pointer reference, violating the tests' expectations. A pointer that
67 : * is known bad but is not literally NULL does not get this treatment.
68 : */
69 1 : *(volatile int *) 1 = 0;
70 :
71 1 : fprintf(stderr, "Should never reach here.\n");
72 0 : return 1;
73 : }
|