hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/tools/testing/selftests/rseq/rseq.c
....@@ -25,83 +25,115 @@
2525 #include <syscall.h>
2626 #include <assert.h>
2727 #include <signal.h>
28
+#include <limits.h>
29
+#include <dlfcn.h>
30
+#include <stddef.h>
2831
32
+#include "../kselftest.h"
2933 #include "rseq.h"
3034
31
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
35
+static const ptrdiff_t *libc_rseq_offset_p;
36
+static const unsigned int *libc_rseq_size_p;
37
+static const unsigned int *libc_rseq_flags_p;
3238
33
-__attribute__((tls_model("initial-exec"))) __thread
34
-volatile struct rseq __rseq_abi = {
35
- .cpu_id = RSEQ_CPU_ID_UNINITIALIZED,
39
+/* Offset from the thread pointer to the rseq area. */
40
+ptrdiff_t rseq_offset;
41
+
42
+/* Size of the registered rseq area. 0 if the registration was
43
+ unsuccessful. */
44
+unsigned int rseq_size = -1U;
45
+
46
+/* Flags used during rseq registration. */
47
+unsigned int rseq_flags;
48
+
49
+static int rseq_ownership;
50
+
51
+static
52
+__thread struct rseq_abi __rseq_abi __attribute__((tls_model("initial-exec"))) = {
53
+ .cpu_id = RSEQ_ABI_CPU_ID_UNINITIALIZED,
3654 };
3755
38
-static __attribute__((tls_model("initial-exec"))) __thread
39
-volatile int refcount;
40
-
41
-static void signal_off_save(sigset_t *oldset)
42
-{
43
- sigset_t set;
44
- int ret;
45
-
46
- sigfillset(&set);
47
- ret = pthread_sigmask(SIG_BLOCK, &set, oldset);
48
- if (ret)
49
- abort();
50
-}
51
-
52
-static void signal_restore(sigset_t oldset)
53
-{
54
- int ret;
55
-
56
- ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
57
- if (ret)
58
- abort();
59
-}
60
-
61
-static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len,
56
+static int sys_rseq(struct rseq_abi *rseq_abi, uint32_t rseq_len,
6257 int flags, uint32_t sig)
6358 {
6459 return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig);
6560 }
6661
62
+int rseq_available(void)
63
+{
64
+ int rc;
65
+
66
+ rc = sys_rseq(NULL, 0, 0, 0);
67
+ if (rc != -1)
68
+ abort();
69
+ switch (errno) {
70
+ case ENOSYS:
71
+ return 0;
72
+ case EINVAL:
73
+ return 1;
74
+ default:
75
+ abort();
76
+ }
77
+}
78
+
6779 int rseq_register_current_thread(void)
6880 {
69
- int rc, ret = 0;
70
- sigset_t oldset;
81
+ int rc;
7182
72
- signal_off_save(&oldset);
73
- if (refcount++)
74
- goto end;
75
- rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG);
76
- if (!rc) {
77
- assert(rseq_current_cpu_raw() >= 0);
78
- goto end;
83
+ if (!rseq_ownership) {
84
+ /* Treat libc's ownership as a successful registration. */
85
+ return 0;
7986 }
80
- if (errno != EBUSY)
81
- __rseq_abi.cpu_id = -2;
82
- ret = -1;
83
- refcount--;
84
-end:
85
- signal_restore(oldset);
86
- return ret;
87
+ rc = sys_rseq(&__rseq_abi, sizeof(struct rseq_abi), 0, RSEQ_SIG);
88
+ if (rc)
89
+ return -1;
90
+ assert(rseq_current_cpu_raw() >= 0);
91
+ return 0;
8792 }
8893
8994 int rseq_unregister_current_thread(void)
9095 {
91
- int rc, ret = 0;
92
- sigset_t oldset;
96
+ int rc;
9397
94
- signal_off_save(&oldset);
95
- if (--refcount)
96
- goto end;
97
- rc = sys_rseq(&__rseq_abi, sizeof(struct rseq),
98
- RSEQ_FLAG_UNREGISTER, RSEQ_SIG);
99
- if (!rc)
100
- goto end;
101
- ret = -1;
102
-end:
103
- signal_restore(oldset);
104
- return ret;
98
+ if (!rseq_ownership) {
99
+ /* Treat libc's ownership as a successful unregistration. */
100
+ return 0;
101
+ }
102
+ rc = sys_rseq(&__rseq_abi, sizeof(struct rseq_abi), RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG);
103
+ if (rc)
104
+ return -1;
105
+ return 0;
106
+}
107
+
108
+static __attribute__((constructor))
109
+void rseq_init(void)
110
+{
111
+ libc_rseq_offset_p = dlsym(RTLD_NEXT, "__rseq_offset");
112
+ libc_rseq_size_p = dlsym(RTLD_NEXT, "__rseq_size");
113
+ libc_rseq_flags_p = dlsym(RTLD_NEXT, "__rseq_flags");
114
+ if (libc_rseq_size_p && libc_rseq_offset_p && libc_rseq_flags_p) {
115
+ /* rseq registration owned by glibc */
116
+ rseq_offset = *libc_rseq_offset_p;
117
+ rseq_size = *libc_rseq_size_p;
118
+ rseq_flags = *libc_rseq_flags_p;
119
+ return;
120
+ }
121
+ if (!rseq_available())
122
+ return;
123
+ rseq_ownership = 1;
124
+ rseq_offset = (void *)&__rseq_abi - rseq_thread_pointer();
125
+ rseq_size = sizeof(struct rseq_abi);
126
+ rseq_flags = 0;
127
+}
128
+
129
+static __attribute__((destructor))
130
+void rseq_exit(void)
131
+{
132
+ if (!rseq_ownership)
133
+ return;
134
+ rseq_offset = 0;
135
+ rseq_size = -1U;
136
+ rseq_ownership = 0;
105137 }
106138
107139 int32_t rseq_fallback_current_cpu(void)