.. | .. |
---|
29 | 29 | #include <dlfcn.h> |
---|
30 | 30 | #include <stddef.h> |
---|
31 | 31 | |
---|
| 32 | +#include <linux/compiler.h> |
---|
| 33 | + |
---|
32 | 34 | #include "../kselftest.h" |
---|
33 | 35 | #include "rseq.h" |
---|
34 | 36 | |
---|
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; |
---|
| 37 | +/* |
---|
| 38 | + * Define weak versions to play nice with binaries that are statically linked |
---|
| 39 | + * against a libc that doesn't support registering its own rseq. |
---|
| 40 | + */ |
---|
| 41 | +__weak ptrdiff_t __rseq_offset; |
---|
| 42 | +__weak unsigned int __rseq_size; |
---|
| 43 | +__weak unsigned int __rseq_flags; |
---|
| 44 | + |
---|
| 45 | +static const ptrdiff_t *libc_rseq_offset_p = &__rseq_offset; |
---|
| 46 | +static const unsigned int *libc_rseq_size_p = &__rseq_size; |
---|
| 47 | +static const unsigned int *libc_rseq_flags_p = &__rseq_flags; |
---|
38 | 48 | |
---|
39 | 49 | /* Offset from the thread pointer to the rseq area. */ |
---|
40 | 50 | ptrdiff_t rseq_offset; |
---|
.. | .. |
---|
108 | 118 | static __attribute__((constructor)) |
---|
109 | 119 | void rseq_init(void) |
---|
110 | 120 | { |
---|
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) { |
---|
| 121 | + /* |
---|
| 122 | + * If the libc's registered rseq size isn't already valid, it may be |
---|
| 123 | + * because the binary is dynamically linked and not necessarily due to |
---|
| 124 | + * libc not having registered a restartable sequence. Try to find the |
---|
| 125 | + * symbols if that's the case. |
---|
| 126 | + */ |
---|
| 127 | + if (!*libc_rseq_size_p) { |
---|
| 128 | + libc_rseq_offset_p = dlsym(RTLD_NEXT, "__rseq_offset"); |
---|
| 129 | + libc_rseq_size_p = dlsym(RTLD_NEXT, "__rseq_size"); |
---|
| 130 | + libc_rseq_flags_p = dlsym(RTLD_NEXT, "__rseq_flags"); |
---|
| 131 | + } |
---|
| 132 | + if (libc_rseq_size_p && libc_rseq_offset_p && libc_rseq_flags_p && |
---|
| 133 | + *libc_rseq_size_p != 0) { |
---|
115 | 134 | /* rseq registration owned by glibc */ |
---|
116 | 135 | rseq_offset = *libc_rseq_offset_p; |
---|
117 | 136 | rseq_size = *libc_rseq_size_p; |
---|