^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: LGPL-2.1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * rseq.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This library is free software; you can redistribute it and/or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * modify it under the terms of the GNU Lesser General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * License as published by the Free Software Foundation; only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * version 2.1 of the License.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * This library is distributed in the hope that it will be useful,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * but WITHOUT ANY WARRANTY; without even the implied warranty of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Lesser General Public License for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define _GNU_SOURCE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <syscall.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <assert.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <limits.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include "rseq.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) __thread volatile struct rseq __rseq_abi = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) .cpu_id = RSEQ_CPU_ID_UNINITIALIZED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * Shared with other libraries. This library may take rseq ownership if it is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * still 0 when executing the library constructor. Set to 1 by library
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * constructor when handling rseq. Set to 0 in destructor if handling rseq.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) int __rseq_handled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* Whether this library have ownership of rseq registration. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static int rseq_ownership;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static __thread volatile uint32_t __rseq_refcount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static void signal_off_save(sigset_t *oldset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) sigset_t set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) sigfillset(&set);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) ret = pthread_sigmask(SIG_BLOCK, &set, oldset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) abort();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static void signal_restore(sigset_t oldset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) abort();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) int flags, uint32_t sig)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) int rseq_register_current_thread(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) int rc, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) sigset_t oldset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (!rseq_ownership)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) signal_off_save(&oldset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (__rseq_refcount == UINT_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) ret = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (__rseq_refcount++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (!rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) assert(rseq_current_cpu_raw() >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (errno != EBUSY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) __rseq_abi.cpu_id = RSEQ_CPU_ID_REGISTRATION_FAILED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) ret = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) __rseq_refcount--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) end:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) signal_restore(oldset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) int rseq_unregister_current_thread(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) int rc, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) sigset_t oldset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (!rseq_ownership)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) signal_off_save(&oldset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (!__rseq_refcount) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) ret = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (--__rseq_refcount)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) rc = sys_rseq(&__rseq_abi, sizeof(struct rseq),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) RSEQ_FLAG_UNREGISTER, RSEQ_SIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (!rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) __rseq_refcount = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) ret = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) end:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) signal_restore(oldset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) int32_t rseq_fallback_current_cpu(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) int32_t cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) cpu = sched_getcpu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (cpu < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) perror("sched_getcpu()");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) abort();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) return cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) void __attribute__((constructor)) rseq_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /* Check whether rseq is handled by another library. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (__rseq_handled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) __rseq_handled = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) rseq_ownership = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) void __attribute__((destructor)) rseq_fini(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (!rseq_ownership)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) __rseq_handled = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) rseq_ownership = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }