DF-5611 / siglog.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | /* * siglog.c - DF-5611 observation shim (LD_PRELOAD on the vkernel). * * Pure OBSERVER + real trigger: it never injects signals or faults. * - wraps sigaction(SIGXCPU,...) so every SIGXCPU delivery logs * {pthread_self, %gs base} BEFORE calling the real vkernel handler * (stopsig). %gs base == 0 => delivered on a cothread / pre-init AP * thread => stopsig's mycpu load must fault. * - wraps pthread_create() to log each created host thread so the doomed * thread can be correlated with its creation. * - logs sigblock() masks so the runtime evidence shows exactly which * signal sets cpu_disable_intr()/cpu_mask_all_signals() install * (SIGXCPU absent from both - machintr.c:194-195, 207-209). * * Signal-handler-context code only uses raw syscalls, pthread_self(), * and single write(2) calls (async-signal-safe). */ #define _GNU_SOURCE #include <signal.h> #include <stddef.h> #include <stdint.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <pthread.h> #include <dlfcn.h> #include <sys/syscall.h> struct tls_info_ { void *base; long size; }; /* SYS_get_tls_area = 473, which=1 is %gs (TLS_WHICH_GS) */ static uintptr_t gsbase(void) { struct tls_info_ ti; ti.base = NULL; ti.size = 0; if (syscall(473, 1, &ti, sizeof(ti)) != 0) return (uintptr_t)0xdeadbeefU; return (uintptr_t)ti.base; } /* minimal async-safe line logger: "SIGLOG: " tag + 3 hex fields + '\n' */ static void slog_raw(const char *tag, uintptr_t a, uintptr_t b, uintptr_t c) { char buf[160]; int n = 0; int i; const char *p; for (p = "SIGLOG: "; *p; ++p) buf[n++] = *p; for (p = tag; *p; ++p) buf[n++] = *p; buf[n++] = ' '; buf[n++] = '0'; buf[n++] = 'x'; for (i = (int)(sizeof(uintptr_t) * 2) - 1; i >= 0; --i) { char h = (char)((a >> (i * 4)) & 0xf); buf[n++] = (char)(h < 10 ? '0' + h : 'a' + h - 10); } buf[n++] = ' '; buf[n++] = '0'; buf[n++] = 'x'; for (i = (int)(sizeof(uintptr_t) * 2) - 1; i >= 0; --i) { char h = (char)((b >> (i * 4)) & 0xf); buf[n++] = (char)(h < 10 ? '0' + h : 'a' + h - 10); } buf[n++] = ' '; buf[n++] = '0'; buf[n++] = 'x'; for (i = (int)(sizeof(uintptr_t) * 2) - 1; i >= 0; --i) { char h = (char)((c >> (i * 4)) & 0xf); buf[n++] = (char)(h < 10 ? '0' + h : 'a' + h - 10); } buf[n++] = '\n'; write(2, buf, (size_t)n); } /* ---------------- SIGXCPU handler wrapper ---------------- */ static void (*real_xcpu_handler)(int, siginfo_t *, void *); static void xcpu_wrapper(int signo, siginfo_t *info, void *ctx) { int save = errno; slog_raw("XCPU-IN thr=", (uintptr_t)pthread_self(), gsbase(), (uintptr_t)ctx); errno = save; if (real_xcpu_handler) real_xcpu_handler(signo, info, ctx); errno = save; } /* ---------------- pthread_create wrapper ---------------- */ struct pc_arg { void *(*start)(void *); void *arg; }; static void * pc_child(struct pc_arg *pa) { void *(*start)(void *) = pa->start; void *arg = pa->arg; slog_raw("THREAD-START thr=", (uintptr_t)pthread_self(), gsbase(), (uintptr_t)start); free(pa); return start(arg); } static int (*real_pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *); int pthread_create(pthread_t *t, const pthread_attr_t *a, void *(*start)(void *), void *arg) { struct pc_arg *pa; int rc; if (!real_pthread_create) return EAGAIN; pa = malloc(sizeof(*pa)); if (pa == NULL) return real_pthread_create(t, a, start, arg); pa->start = start; pa->arg = arg; rc = real_pthread_create(t, a, pc_child, pa); if (rc == 0) slog_raw("THREAD-CREATE newthr=", (uintptr_t)*t, 0, (uintptr_t)start); else free(pa); return rc; } /* ---------------- sigaction wrapper (SIGXCPU only) ---------------- */ static int (*real_sigaction)(int, const struct sigaction *, struct sigaction *); int sigaction(int signo, const struct sigaction *act, struct sigaction *oact) { struct sigaction na; void *h; if (!real_sigaction) return -1; if (signo == SIGXCPU && act != NULL) { h = act->sa_sigaction; if (h != NULL && h != SIG_IGN && h != SIG_DFL && h != (void *)xcpu_wrapper) { real_xcpu_handler = h; na = *act; na.sa_sigaction = xcpu_wrapper; slog_raw("HOOK-XCPU handler=", (uintptr_t)h, (uintptr_t)pthread_self(), gsbase()); return real_sigaction(signo, &na, oact); } } return real_sigaction(signo, act, oact); } /* ---------------- sigblock logger ---------------- */ static int (*real_sigblock_)(int); int sigblock(int mask) { if (real_sigblock_) slog_raw("SIGBLOCK mask=", (uintptr_t)(unsigned int)mask, (uintptr_t)pthread_self(), 0); return real_sigblock_ ? real_sigblock_(mask) : 0; } /* ---------------- bootstrap ---------------- */ __attribute__((constructor)) static void siglog_init(void) { real_pthread_create = (void *(*)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *)) dlsym(RTLD_NEXT, "pthread_create"); real_sigaction = (int (*)(int, const struct sigaction *, struct sigaction *)) dlsym(RTLD_NEXT, "sigaction"); real_sigblock_ = (int (*)(int))dlsym(RTLD_NEXT, "sigblock"); slog_raw("INIT thr=", (uintptr_t)pthread_self(), gsbase(), 0); } |