| .. | .. |
|---|
| 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; |
|---|