1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright 2018, Michael Ellerman, IBM Corp.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Test that an out-of-bounds branch to counter behaves as expected.
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <setjmp.h>
9*4882a593Smuzhiyun #include <stdio.h>
10*4882a593Smuzhiyun #include <stdlib.h>
11*4882a593Smuzhiyun #include <string.h>
12*4882a593Smuzhiyun #include <sys/mman.h>
13*4882a593Smuzhiyun #include <sys/types.h>
14*4882a593Smuzhiyun #include <sys/wait.h>
15*4882a593Smuzhiyun #include <ucontext.h>
16*4882a593Smuzhiyun #include <unistd.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include "utils.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define BAD_NIP 0x788c545a18000000ull
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun static struct pt_regs signal_regs;
24*4882a593Smuzhiyun static jmp_buf setjmp_env;
25*4882a593Smuzhiyun
save_regs(ucontext_t * ctxt)26*4882a593Smuzhiyun static void save_regs(ucontext_t *ctxt)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun struct pt_regs *regs = ctxt->uc_mcontext.regs;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun memcpy(&signal_regs, regs, sizeof(signal_regs));
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun
segv_handler(int signum,siginfo_t * info,void * ctxt_v)33*4882a593Smuzhiyun static void segv_handler(int signum, siginfo_t *info, void *ctxt_v)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun save_regs(ctxt_v);
36*4882a593Smuzhiyun longjmp(setjmp_env, 1);
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun
usr2_handler(int signum,siginfo_t * info,void * ctxt_v)39*4882a593Smuzhiyun static void usr2_handler(int signum, siginfo_t *info, void *ctxt_v)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun save_regs(ctxt_v);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
ok(void)44*4882a593Smuzhiyun static int ok(void)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun printf("Everything is OK in here.\n");
47*4882a593Smuzhiyun return 0;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun #define REG_POISON 0x5a5a
51*4882a593Smuzhiyun #define POISONED_REG(n) ((((unsigned long)REG_POISON) << 48) | ((n) << 32) | \
52*4882a593Smuzhiyun (((unsigned long)REG_POISON) << 16) | (n))
53*4882a593Smuzhiyun
poison_regs(void)54*4882a593Smuzhiyun static inline void poison_regs(void)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun #define POISON_REG(n) \
57*4882a593Smuzhiyun "lis " __stringify(n) "," __stringify(REG_POISON) ";" \
58*4882a593Smuzhiyun "addi " __stringify(n) "," __stringify(n) "," __stringify(n) ";" \
59*4882a593Smuzhiyun "sldi " __stringify(n) "," __stringify(n) ", 32 ;" \
60*4882a593Smuzhiyun "oris " __stringify(n) "," __stringify(n) "," __stringify(REG_POISON) ";" \
61*4882a593Smuzhiyun "addi " __stringify(n) "," __stringify(n) "," __stringify(n) ";"
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun asm (POISON_REG(15)
64*4882a593Smuzhiyun POISON_REG(16)
65*4882a593Smuzhiyun POISON_REG(17)
66*4882a593Smuzhiyun POISON_REG(18)
67*4882a593Smuzhiyun POISON_REG(19)
68*4882a593Smuzhiyun POISON_REG(20)
69*4882a593Smuzhiyun POISON_REG(21)
70*4882a593Smuzhiyun POISON_REG(22)
71*4882a593Smuzhiyun POISON_REG(23)
72*4882a593Smuzhiyun POISON_REG(24)
73*4882a593Smuzhiyun POISON_REG(25)
74*4882a593Smuzhiyun POISON_REG(26)
75*4882a593Smuzhiyun POISON_REG(27)
76*4882a593Smuzhiyun POISON_REG(28)
77*4882a593Smuzhiyun POISON_REG(29)
78*4882a593Smuzhiyun : // inputs
79*4882a593Smuzhiyun : // outputs
80*4882a593Smuzhiyun : "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25",
81*4882a593Smuzhiyun "26", "27", "28", "29"
82*4882a593Smuzhiyun );
83*4882a593Smuzhiyun #undef POISON_REG
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
check_regs(void)86*4882a593Smuzhiyun static int check_regs(void)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun unsigned long i;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun for (i = 15; i <= 29; i++)
91*4882a593Smuzhiyun FAIL_IF(signal_regs.gpr[i] != POISONED_REG(i));
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun printf("Regs OK\n");
94*4882a593Smuzhiyun return 0;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
dump_regs(void)97*4882a593Smuzhiyun static void dump_regs(void)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun for (int i = 0; i < 32; i += 4) {
100*4882a593Smuzhiyun printf("r%02d 0x%016lx r%02d 0x%016lx " \
101*4882a593Smuzhiyun "r%02d 0x%016lx r%02d 0x%016lx\n",
102*4882a593Smuzhiyun i, signal_regs.gpr[i],
103*4882a593Smuzhiyun i+1, signal_regs.gpr[i+1],
104*4882a593Smuzhiyun i+2, signal_regs.gpr[i+2],
105*4882a593Smuzhiyun i+3, signal_regs.gpr[i+3]);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun #ifdef _CALL_AIXDESC
110*4882a593Smuzhiyun struct opd {
111*4882a593Smuzhiyun unsigned long ip;
112*4882a593Smuzhiyun unsigned long toc;
113*4882a593Smuzhiyun unsigned long env;
114*4882a593Smuzhiyun };
115*4882a593Smuzhiyun static struct opd bad_opd = {
116*4882a593Smuzhiyun .ip = BAD_NIP,
117*4882a593Smuzhiyun };
118*4882a593Smuzhiyun #define BAD_FUNC (&bad_opd)
119*4882a593Smuzhiyun #else
120*4882a593Smuzhiyun #define BAD_FUNC BAD_NIP
121*4882a593Smuzhiyun #endif
122*4882a593Smuzhiyun
test_wild_bctr(void)123*4882a593Smuzhiyun int test_wild_bctr(void)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun int (*func_ptr)(void);
126*4882a593Smuzhiyun struct sigaction segv = {
127*4882a593Smuzhiyun .sa_sigaction = segv_handler,
128*4882a593Smuzhiyun .sa_flags = SA_SIGINFO
129*4882a593Smuzhiyun };
130*4882a593Smuzhiyun struct sigaction usr2 = {
131*4882a593Smuzhiyun .sa_sigaction = usr2_handler,
132*4882a593Smuzhiyun .sa_flags = SA_SIGINFO
133*4882a593Smuzhiyun };
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun FAIL_IF(sigaction(SIGSEGV, &segv, NULL));
136*4882a593Smuzhiyun FAIL_IF(sigaction(SIGUSR2, &usr2, NULL));
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun bzero(&signal_regs, sizeof(signal_regs));
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if (setjmp(setjmp_env) == 0) {
141*4882a593Smuzhiyun func_ptr = ok;
142*4882a593Smuzhiyun func_ptr();
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun kill(getpid(), SIGUSR2);
145*4882a593Smuzhiyun printf("Regs before:\n");
146*4882a593Smuzhiyun dump_regs();
147*4882a593Smuzhiyun bzero(&signal_regs, sizeof(signal_regs));
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun poison_regs();
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun func_ptr = (int (*)(void))BAD_FUNC;
152*4882a593Smuzhiyun func_ptr();
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun FAIL_IF(1); /* we didn't segv? */
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun FAIL_IF(signal_regs.nip != BAD_NIP);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun printf("All good - took SEGV as expected branching to 0x%llx\n", BAD_NIP);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun dump_regs();
162*4882a593Smuzhiyun FAIL_IF(check_regs());
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun return 0;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
main(void)167*4882a593Smuzhiyun int main(void)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun return test_harness(test_wild_bctr, "wild_bctr");
170*4882a593Smuzhiyun }
171