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_signal.h"
15 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
16 : #include "native_client/src/trusted/service_runtime/sel_rt.h"
17 :
18 :
19 : /*
20 : * This test case checks for an obscure gotcha in the Linux kernel.
21 : *
22 : * Some kernels do not assign to the top 2 bytes of the REG_CS array
23 : * entry when writing %cs to the stack. If NaCl's signal handler does
24 : * not disregard the top 16 bits of REG_CS, it will incorrectly treat
25 : * a fault in trusted code as coming from untrusted code, and it will
26 : * crash while attempting to restore %gs.
27 : *
28 : * Specifically, this happens in 32-bit processes on the 64-bit kernel
29 : * from Ubuntu Hardy.
30 : *
31 : * See http://code.google.com/p/nativeclient/issues/detail?id=1486
32 : */
33 :
34 1 : int main() {
35 1 : size_t stack_size = SIGSTKSZ;
36 : char *stack;
37 : stack_t st;
38 : int rc;
39 :
40 1 : NaClLogModuleInit();
41 1 : NaClInitGlobals();
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 : }
|