1*053f45beSAndroid Build Coastguard Worker // SPDX-License-Identifier: LGPL-2.1
2*053f45beSAndroid Build Coastguard Worker /*
3*053f45beSAndroid Build Coastguard Worker * rseq.c
4*053f45beSAndroid Build Coastguard Worker *
5*053f45beSAndroid Build Coastguard Worker * Copyright (C) 2016 Mathieu Desnoyers <[email protected]>
6*053f45beSAndroid Build Coastguard Worker *
7*053f45beSAndroid Build Coastguard Worker * This library is free software; you can redistribute it and/or
8*053f45beSAndroid Build Coastguard Worker * modify it under the terms of the GNU Lesser General Public
9*053f45beSAndroid Build Coastguard Worker * License as published by the Free Software Foundation; only
10*053f45beSAndroid Build Coastguard Worker * version 2.1 of the License.
11*053f45beSAndroid Build Coastguard Worker *
12*053f45beSAndroid Build Coastguard Worker * This library is distributed in the hope that it will be useful,
13*053f45beSAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*053f45beSAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15*053f45beSAndroid Build Coastguard Worker * Lesser General Public License for more details.
16*053f45beSAndroid Build Coastguard Worker */
17*053f45beSAndroid Build Coastguard Worker
18*053f45beSAndroid Build Coastguard Worker #define _GNU_SOURCE
19*053f45beSAndroid Build Coastguard Worker #include <errno.h>
20*053f45beSAndroid Build Coastguard Worker #include <sched.h>
21*053f45beSAndroid Build Coastguard Worker #include <stdio.h>
22*053f45beSAndroid Build Coastguard Worker #include <stdlib.h>
23*053f45beSAndroid Build Coastguard Worker #include <string.h>
24*053f45beSAndroid Build Coastguard Worker #include <unistd.h>
25*053f45beSAndroid Build Coastguard Worker #include <syscall.h>
26*053f45beSAndroid Build Coastguard Worker #include <assert.h>
27*053f45beSAndroid Build Coastguard Worker #include <signal.h>
28*053f45beSAndroid Build Coastguard Worker #include <limits.h>
29*053f45beSAndroid Build Coastguard Worker #include <dlfcn.h>
30*053f45beSAndroid Build Coastguard Worker #include <stddef.h>
31*053f45beSAndroid Build Coastguard Worker
32*053f45beSAndroid Build Coastguard Worker #include "../kselftest.h"
33*053f45beSAndroid Build Coastguard Worker #include "rseq.h"
34*053f45beSAndroid Build Coastguard Worker
35*053f45beSAndroid Build Coastguard Worker static const ptrdiff_t *libc_rseq_offset_p;
36*053f45beSAndroid Build Coastguard Worker static const unsigned int *libc_rseq_size_p;
37*053f45beSAndroid Build Coastguard Worker static const unsigned int *libc_rseq_flags_p;
38*053f45beSAndroid Build Coastguard Worker
39*053f45beSAndroid Build Coastguard Worker /* Offset from the thread pointer to the rseq area. */
40*053f45beSAndroid Build Coastguard Worker ptrdiff_t rseq_offset;
41*053f45beSAndroid Build Coastguard Worker
42*053f45beSAndroid Build Coastguard Worker /* Size of the registered rseq area. 0 if the registration was
43*053f45beSAndroid Build Coastguard Worker unsuccessful. */
44*053f45beSAndroid Build Coastguard Worker unsigned int rseq_size = -1U;
45*053f45beSAndroid Build Coastguard Worker
46*053f45beSAndroid Build Coastguard Worker /* Flags used during rseq registration. */
47*053f45beSAndroid Build Coastguard Worker unsigned int rseq_flags;
48*053f45beSAndroid Build Coastguard Worker
49*053f45beSAndroid Build Coastguard Worker static int rseq_ownership;
50*053f45beSAndroid Build Coastguard Worker
51*053f45beSAndroid Build Coastguard Worker static
52*053f45beSAndroid Build Coastguard Worker __thread struct rseq_abi __rseq_abi __attribute__((tls_model("initial-exec"))) = {
53*053f45beSAndroid Build Coastguard Worker .cpu_id = RSEQ_ABI_CPU_ID_UNINITIALIZED,
54*053f45beSAndroid Build Coastguard Worker };
55*053f45beSAndroid Build Coastguard Worker
sys_rseq(struct rseq_abi * rseq_abi,uint32_t rseq_len,int flags,uint32_t sig)56*053f45beSAndroid Build Coastguard Worker static int sys_rseq(struct rseq_abi *rseq_abi, uint32_t rseq_len,
57*053f45beSAndroid Build Coastguard Worker int flags, uint32_t sig)
58*053f45beSAndroid Build Coastguard Worker {
59*053f45beSAndroid Build Coastguard Worker return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig);
60*053f45beSAndroid Build Coastguard Worker }
61*053f45beSAndroid Build Coastguard Worker
rseq_available(void)62*053f45beSAndroid Build Coastguard Worker int rseq_available(void)
63*053f45beSAndroid Build Coastguard Worker {
64*053f45beSAndroid Build Coastguard Worker int rc;
65*053f45beSAndroid Build Coastguard Worker
66*053f45beSAndroid Build Coastguard Worker rc = sys_rseq(NULL, 0, 0, 0);
67*053f45beSAndroid Build Coastguard Worker if (rc != -1)
68*053f45beSAndroid Build Coastguard Worker abort();
69*053f45beSAndroid Build Coastguard Worker switch (errno) {
70*053f45beSAndroid Build Coastguard Worker case ENOSYS:
71*053f45beSAndroid Build Coastguard Worker return 0;
72*053f45beSAndroid Build Coastguard Worker case EINVAL:
73*053f45beSAndroid Build Coastguard Worker return 1;
74*053f45beSAndroid Build Coastguard Worker default:
75*053f45beSAndroid Build Coastguard Worker abort();
76*053f45beSAndroid Build Coastguard Worker }
77*053f45beSAndroid Build Coastguard Worker }
78*053f45beSAndroid Build Coastguard Worker
rseq_register_current_thread(void)79*053f45beSAndroid Build Coastguard Worker int rseq_register_current_thread(void)
80*053f45beSAndroid Build Coastguard Worker {
81*053f45beSAndroid Build Coastguard Worker int rc;
82*053f45beSAndroid Build Coastguard Worker
83*053f45beSAndroid Build Coastguard Worker if (!rseq_ownership) {
84*053f45beSAndroid Build Coastguard Worker /* Treat libc's ownership as a successful registration. */
85*053f45beSAndroid Build Coastguard Worker return 0;
86*053f45beSAndroid Build Coastguard Worker }
87*053f45beSAndroid Build Coastguard Worker rc = sys_rseq(&__rseq_abi, sizeof(struct rseq_abi), 0, RSEQ_SIG);
88*053f45beSAndroid Build Coastguard Worker if (rc)
89*053f45beSAndroid Build Coastguard Worker return -1;
90*053f45beSAndroid Build Coastguard Worker assert(rseq_current_cpu_raw() >= 0);
91*053f45beSAndroid Build Coastguard Worker return 0;
92*053f45beSAndroid Build Coastguard Worker }
93*053f45beSAndroid Build Coastguard Worker
rseq_unregister_current_thread(void)94*053f45beSAndroid Build Coastguard Worker int rseq_unregister_current_thread(void)
95*053f45beSAndroid Build Coastguard Worker {
96*053f45beSAndroid Build Coastguard Worker int rc;
97*053f45beSAndroid Build Coastguard Worker
98*053f45beSAndroid Build Coastguard Worker if (!rseq_ownership) {
99*053f45beSAndroid Build Coastguard Worker /* Treat libc's ownership as a successful unregistration. */
100*053f45beSAndroid Build Coastguard Worker return 0;
101*053f45beSAndroid Build Coastguard Worker }
102*053f45beSAndroid Build Coastguard Worker rc = sys_rseq(&__rseq_abi, sizeof(struct rseq_abi), RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG);
103*053f45beSAndroid Build Coastguard Worker if (rc)
104*053f45beSAndroid Build Coastguard Worker return -1;
105*053f45beSAndroid Build Coastguard Worker return 0;
106*053f45beSAndroid Build Coastguard Worker }
107*053f45beSAndroid Build Coastguard Worker
108*053f45beSAndroid Build Coastguard Worker static __attribute__((constructor))
rseq_init(void)109*053f45beSAndroid Build Coastguard Worker void rseq_init(void)
110*053f45beSAndroid Build Coastguard Worker {
111*053f45beSAndroid Build Coastguard Worker libc_rseq_offset_p = dlsym(RTLD_NEXT, "__rseq_offset");
112*053f45beSAndroid Build Coastguard Worker libc_rseq_size_p = dlsym(RTLD_NEXT, "__rseq_size");
113*053f45beSAndroid Build Coastguard Worker libc_rseq_flags_p = dlsym(RTLD_NEXT, "__rseq_flags");
114*053f45beSAndroid Build Coastguard Worker if (libc_rseq_size_p && libc_rseq_offset_p && libc_rseq_flags_p &&
115*053f45beSAndroid Build Coastguard Worker *libc_rseq_size_p != 0) {
116*053f45beSAndroid Build Coastguard Worker /* rseq registration owned by glibc */
117*053f45beSAndroid Build Coastguard Worker rseq_offset = *libc_rseq_offset_p;
118*053f45beSAndroid Build Coastguard Worker rseq_size = *libc_rseq_size_p;
119*053f45beSAndroid Build Coastguard Worker rseq_flags = *libc_rseq_flags_p;
120*053f45beSAndroid Build Coastguard Worker return;
121*053f45beSAndroid Build Coastguard Worker }
122*053f45beSAndroid Build Coastguard Worker if (!rseq_available())
123*053f45beSAndroid Build Coastguard Worker return;
124*053f45beSAndroid Build Coastguard Worker rseq_ownership = 1;
125*053f45beSAndroid Build Coastguard Worker rseq_offset = (void *)&__rseq_abi - rseq_thread_pointer();
126*053f45beSAndroid Build Coastguard Worker rseq_size = sizeof(struct rseq_abi);
127*053f45beSAndroid Build Coastguard Worker rseq_flags = 0;
128*053f45beSAndroid Build Coastguard Worker }
129*053f45beSAndroid Build Coastguard Worker
130*053f45beSAndroid Build Coastguard Worker static __attribute__((destructor))
rseq_exit(void)131*053f45beSAndroid Build Coastguard Worker void rseq_exit(void)
132*053f45beSAndroid Build Coastguard Worker {
133*053f45beSAndroid Build Coastguard Worker if (!rseq_ownership)
134*053f45beSAndroid Build Coastguard Worker return;
135*053f45beSAndroid Build Coastguard Worker rseq_offset = 0;
136*053f45beSAndroid Build Coastguard Worker rseq_size = -1U;
137*053f45beSAndroid Build Coastguard Worker rseq_ownership = 0;
138*053f45beSAndroid Build Coastguard Worker }
139*053f45beSAndroid Build Coastguard Worker
rseq_fallback_current_cpu(void)140*053f45beSAndroid Build Coastguard Worker int32_t rseq_fallback_current_cpu(void)
141*053f45beSAndroid Build Coastguard Worker {
142*053f45beSAndroid Build Coastguard Worker int32_t cpu;
143*053f45beSAndroid Build Coastguard Worker
144*053f45beSAndroid Build Coastguard Worker cpu = sched_getcpu();
145*053f45beSAndroid Build Coastguard Worker if (cpu < 0) {
146*053f45beSAndroid Build Coastguard Worker perror("sched_getcpu()");
147*053f45beSAndroid Build Coastguard Worker abort();
148*053f45beSAndroid Build Coastguard Worker }
149*053f45beSAndroid Build Coastguard Worker return cpu;
150*053f45beSAndroid Build Coastguard Worker }
151