118 lines
3.7 KiB
C
118 lines
3.7 KiB
C
|
|
// hakmem_syscall.c - Direct libc calls via dlsym (Box 3)
|
||
|
|
//
|
||
|
|
// Purpose: Bypass LD_PRELOAD to avoid infinite recursion
|
||
|
|
//
|
||
|
|
// How it works:
|
||
|
|
// 1. dlsym(RTLD_NEXT, "malloc") finds the NEXT symbol after current one
|
||
|
|
// 2. In LD_PRELOAD context: hakmem.so → libc.so (skips our wrapper!)
|
||
|
|
// 3. Result: Direct libc call, no recursion possible
|
||
|
|
//
|
||
|
|
// Performance impact:
|
||
|
|
// - dlsym: Called ONCE at init (cached in function pointers)
|
||
|
|
// - hkm_libc_malloc(): Direct function call (no overhead)
|
||
|
|
// - No TLS access, no guards, no recursion checks
|
||
|
|
//
|
||
|
|
// License: MIT
|
||
|
|
// Date: 2025-10-24
|
||
|
|
|
||
|
|
#include "hakmem_syscall.h"
|
||
|
|
#include <dlfcn.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Function Pointers (initialized once at startup)
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
// Real libc functions (bypassing LD_PRELOAD)
|
||
|
|
static void* (*real_malloc)(size_t) = NULL;
|
||
|
|
static void* (*real_calloc)(size_t, size_t) = NULL;
|
||
|
|
static void (*real_free)(void*) = NULL;
|
||
|
|
static void* (*real_realloc)(void*, size_t) = NULL;
|
||
|
|
|
||
|
|
// Initialization flag
|
||
|
|
static int g_syscall_initialized = 0;
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Initialization
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
void hkm_syscall_init(void) {
|
||
|
|
// Idempotent: safe to call multiple times
|
||
|
|
if (g_syscall_initialized) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// dlsym with RTLD_NEXT: Get NEXT symbol in library chain
|
||
|
|
// In LD_PRELOAD context: libhakmem.so → libc.so (skips our malloc!)
|
||
|
|
real_malloc = dlsym(RTLD_NEXT, "malloc");
|
||
|
|
real_calloc = dlsym(RTLD_NEXT, "calloc");
|
||
|
|
real_free = dlsym(RTLD_NEXT, "free");
|
||
|
|
real_realloc = dlsym(RTLD_NEXT, "realloc");
|
||
|
|
|
||
|
|
// Fatal error if dlsym fails (should never happen)
|
||
|
|
if (!real_malloc || !real_calloc || !real_free || !real_realloc) {
|
||
|
|
fprintf(stderr, "[hakmem_syscall] FATAL: dlsym failed\n");
|
||
|
|
fprintf(stderr, " real_malloc=%p\n", (void*)real_malloc);
|
||
|
|
fprintf(stderr, " real_calloc=%p\n", (void*)real_calloc);
|
||
|
|
fprintf(stderr, " real_free=%p\n", (void*)real_free);
|
||
|
|
fprintf(stderr, " real_realloc=%p\n", (void*)real_realloc);
|
||
|
|
abort();
|
||
|
|
}
|
||
|
|
|
||
|
|
g_syscall_initialized = 1;
|
||
|
|
|
||
|
|
// Optional: Debug logging (only in debug builds)
|
||
|
|
#ifdef HAKMEM_DEBUG_VERBOSE
|
||
|
|
fprintf(stderr, "[hakmem_syscall] Initialized successfully\n");
|
||
|
|
fprintf(stderr, " real_malloc=%p\n", (void*)real_malloc);
|
||
|
|
fprintf(stderr, " real_calloc=%p\n", (void*)real_calloc);
|
||
|
|
fprintf(stderr, " real_free=%p\n", (void*)real_free);
|
||
|
|
fprintf(stderr, " real_realloc=%p\n", (void*)real_realloc);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Direct libc Functions (Box 3)
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
void* hkm_libc_malloc(size_t size) {
|
||
|
|
// Auto-initialize on first use (defensive programming)
|
||
|
|
if (!real_malloc) {
|
||
|
|
hkm_syscall_init();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Direct call to libc malloc (no LD_PRELOAD, no recursion!)
|
||
|
|
return real_malloc(size);
|
||
|
|
}
|
||
|
|
|
||
|
|
void* hkm_libc_calloc(size_t nmemb, size_t size) {
|
||
|
|
// Auto-initialize on first use
|
||
|
|
if (!real_calloc) {
|
||
|
|
hkm_syscall_init();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Direct call to libc calloc
|
||
|
|
return real_calloc(nmemb, size);
|
||
|
|
}
|
||
|
|
|
||
|
|
void hkm_libc_free(void* ptr) {
|
||
|
|
// Auto-initialize on first use
|
||
|
|
if (!real_free) {
|
||
|
|
hkm_syscall_init();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Direct call to libc free
|
||
|
|
real_free(ptr);
|
||
|
|
}
|
||
|
|
|
||
|
|
void* hkm_libc_realloc(void* ptr, size_t size) {
|
||
|
|
// Auto-initialize on first use
|
||
|
|
if (!real_realloc) {
|
||
|
|
hkm_syscall_init();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Direct call to libc realloc
|
||
|
|
return real_realloc(ptr, size);
|
||
|
|
}
|