Using dlsym() to stub malloc/free leads to segmentation fault - c

I started to dabble in unit testing C code (using check) and stubbing functions. I am trying to unit
test a small library of data structures that I wrote and wanted to test how it would react to OOM. So I
wrote a simple stubs.c file containing:
#include <stdlib.h>
#include <errno.h>
#include <dlfcn.h>
static int malloc_fail_code = 0;
static int calloc_fail_code = 0;
void set_malloc_fail_code(int no) { malloc_fail_code = no; }
void set_calloc_fail_code(int no) { calloc_fail_code = no; }
void *malloc(size_t size)
{
static void *(*real_malloc)(size_t) = NULL;
if (!real_malloc)
real_malloc = (void *(*)(size_t)) dlsym(RTLD_NEXT, "malloc");
if (malloc_fail_code != 0) {
errno = malloc_fail_code;
malloc_fail_code = 0;
return NULL;
}
return real_malloc(size);
}
void *calloc(size_t nmemb, size_t size)
{
static void *(*real_calloc)(size_t, size_t) = NULL;
if (!real_calloc)
real_calloc = (void *(*)(size_t, size_t)) dlsym(RTLD_NEXT, "calloc");
if (calloc_fail_code != 0) {
errno = calloc_fail_code;
calloc_fail_code = 0;
return NULL;
}
return real_calloc(nmemb, size);
}
with its relative stubs.h containing the definitions for the two setters. I then compiled stubs.c as
a shared object called libstubs.so. I also compiled my library as a shared object called
libmy_lib.so.
My test code is in test.c is something like this:
#include <stdlib.h>
#include <errno.h>
#include <check.h>
#include "my_lib.h"
#include "stubs.h"
START_TEST(my_test)
{
... // using the two setters I force malloc and calloc to return null and set errno to ENOMEM
}
END_TEST
... // check boilerplate to create suite and add tests
I then linked the test executable against libmy_lib.so and libstubs.so. Running said executable greets me with a segfault. Inspecting the crash with gdb makes me believe that I encountered a stack overflow due to infinte recursion (gdb backtrace):
#0 0x00007ffff7fc143c in calloc (
nmemb=<error reading variable: Cannot access memory at address 0x7fffff7feff8>,
size=<error reading variable: Cannot access memory at address 0x7fffff7feff0>)
at stubs.c
#1 0x00007ffff7db9c88 in _dlerror_run (operate=operate#entry=0x7ffff7db94f0 <dlsym_doit>,
args=args#entry=0x7fffff7ff030) at dlerror.c:148
#2 0x00007ffff7db9570 in __dlsym (handle=<optimized out>, name=<optimized out>) at dlsym.c:70
#3 0x00007ffff7fc1487 in calloc (nmemb=1, size=32) at stubs.c
...
I tried including directly stubs.c into test.c but no luck. I also tried writing a small unit testing framework of my own that extends stubs.c and it worked. However I don't want to waste time reinventing the wheel and I am sure there is something I am doing wrong in linking since I don't know much in compilation/linking.
For compilation I am using the meson build system so I don't know how to get the exact command line arguments but I can write a MWE of my build targets:
lib = library(
'my_lib',
sources,
include_directories: includes,
install: true
)
stubs = shared_library(
'stubs',
'stubs.c',
c_args: ['-g'],
include_directories: test_includes,
link_args: ['-ldl']
)
test_exe = executable(
'test_exe',
c_args: ['-g'],
sources: 'test.c',
dependencies: check,
link_with: [stubs, lib],
include_directories: includes + test_includes
)
test('test', test_exe, suite: 'suite')

Try using LD_PRELOAD trick. The meson-ish way to accomplish it would be:
test_env = environment()
test_env.prepend('LD_PRELOAD', stubs.full_path())
test('test', test_exe, suite: 'suite', env: test_env)
note: do not link executable with stubs.

Related

Calling function from library in any other project than library crash

I have made a library that handle strings in c.
I've added it in another project CMakeLists. Issue is that, whenever i want to call a function from that library, it crash.
However, if i call the same function from the library itself, no crash, the function call is handled properly.
I kept thinking that i did something wrong with my CMakeLists but as far as i'm aware and the different methods i used to arrive to the same conclusion, it doesn't look like it anymore.
I tried running the test in question in gdb and this is what it returned
Starting program: C:\Users\s\Documents\Repo\C\Projet\lib\rule\build\test-create-destroy.exe
gdb: unknown target exception 0xc0000135 at 0x7ffdfa70cf40
gdb: unknown target exception 0xc0000135 at 0x7ffdfa70cf40
Program received signal ?, Unknown signal.
0x00007ffdfa70cf40 in ntdll!RtlRaiseStatus () from C:\Windows\SYSTEM32\ntdll.dll
I've read that it could be an issue related to memory allocation errors, but if this was the case, why would i be able to call the function without any error directly from my library?
replit of fairly simple example: https://replit.com/#Mrcubix-Mrcubix/EmbellishedOldfashionedBaitware#lib/rule/src/test-create-destroy.c
Here is the function called in the library in question, to keep it simple:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct _String
{
unsigned int size;
char *string;
} String;
String *create_string(char *chr)
{
String *str = malloc(sizeof(String));
str->size = strlen(chr);
str->string = malloc(str->size + 1);
memcpy(str->string, chr, str->size);
str->string[str->size] = '\0';
return str;
}
void destroy_string(String *str)
{
free(str);
}
Here the second library i'm calling a function from which work as it's part of the same project:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string-struct.h>
typedef struct _rule
{
String *premise;
String *conclusion;
} rule;
rule *create_rule(String *premise, String *conclusion)
{
rule *r = calloc(1, 16);
r->premise = premise;
r->conclusion = conclusion;
return r;
}
void destroy_rule(rule *r)
{
free(r);
}
here is the CMakeLists used by Rulestruct:
cmake_minimum_required(VERSION 3.0)
project("Rulestruct")
find_package(Stringstruct)
include_directories(${STRINGSTRUCT_INCLUDE_DIRS})
link_directories(${STRINGSTRUCT_LIB_DIRS})
add_library(rulestruct SHARED "${CMAKE_CURRENT_SOURCE_DIR}/src/rule-struct.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/rule-struct.h")
target_link_libraries(rulestruct ${STRINGSTRUCT_LIBRARIES})
add_executable(test-create-destroy "${CMAKE_CURRENT_SOURCE_DIR}/src/test-create-destroy.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/rule-struct.h")
add_dependencies(test-create-destroy rulestruct)
target_link_libraries(test-create-destroy rulestruct)
and finally, here is where i call the function from (test-create-destroy.c)
#include <assert.h>
#include <string-struct.h>
#include "rule-struct.h"
#include "rules-struct.inc"
int main(void)
{
String *premise = create_string("1 2"); // location of crash
String *conclusion = create_string("3"); // location of crash
/*rule *rule_A = create_rule(premise, conclusion);
assert(string_char_equal(rule_A->premise, "1 2"));
assert(!string_char_equal(rule_A->premise, "3"));
assert(string_char_equal(rule_A->conclusion, "3"));
assert(!string_char_equal(rule_A->conclusion, "1 2"));
destroy_rule(rule_A);*/
destroy_string(premise);
destroy_string(conclusion);
}
Here are screenshots of bin, lib and cmake-gui: https://imgur.com/a/3OdrC2D
I could probably fix it on every project provided i know what i did wrong and why,
So if anyone could provide further explanation then i'll glad to read it.
I will also take tips about issues or potential issues related to my CMakeLists as i have a hard time understanding any of it, needing to mix multiple examples and the documentation to have a very small bit of understanding of why something is done this or that way.
TLDR: Function called elsewhere than inside the library = crash, accept tips about other parts of the presented data (CMakeLists).
Gladly accept further explanation of the core of the issue.

Is it possible for an LD_PRELOAD to only affect the main executable?

The Actual Problem
I have an executable that by default uses EGL and SDL 1.2 to handle graphics and user input respectively. Using LD_PRELOAD, I have replaced both with GLFW.
This works normally unless the user has installed the Wayland version of GLFW, which depends on EGL itself. Because all the EGL calls are either stubbed to do nothing or call GLFW equivalents, it doesn't work (ie. eglSwapBuffers calls glfwSwapBuffers which calls eglSwapBuffers and so on). I can't remove the EGL stubs because then it would call both EGL and GLFW and the main executable is closed-source so I can't modify that.
Is there any way to make LD_PRELOAD affect the main executable but not GLFW? Or any other solution to obtain the same effect?
The Simplified Problem
I made a simplified example to demonstrate the problem.
Main Executable:
#include <stdio.h>
extern void do_something();
int main() {
do_something();
fputs("testing B\n", stderr);
}
Shared Library:
#include <stdio.h>
void do_something() {
fputs("testing A\n", stderr);
}
Preloaded Library:
#include <stdio.h>
int fputs(const char *str, FILE *file) {
// Do Nothing
return 0;
}
When the preloaded library isn't used, the output is:
testing A
testing B
When it is used, the output is nothing.
I'm looking for a way to make the preloaded library only affect the main executable, that the output would be:
testing A
Thank you!
You can check if the return address is in the executable or the library, and then call either the "real" function or do your stub code, like this:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <link.h>
#include <stdio.h>
#include <stdlib.h>
static struct {
ElfW(Addr) start, end;
} *segments;
static int n;
static int (*real_fputs)(const char *, FILE *);
static int callback(struct dl_phdr_info *info, size_t size, void *data) {
n = info->dlpi_phnum;
segments = malloc(n * sizeof *segments);
for(int i = 0; i < n; ++i) {
segments[i].start = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
segments[i].end = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr + info->dlpi_phdr[i].p_memsz;
}
return 1;
}
__attribute__((__constructor__))
static void setup(void) {
real_fputs = dlsym(RTLD_NEXT, "fputs");
dl_iterate_phdr(callback, NULL);
}
__attribute__((__destructor__))
static void teardown(void) {
free(segments);
}
__attribute__((__noinline__))
int fputs(const char *str, FILE *file) {
ElfW(Addr) addr = (ElfW(Addr))__builtin_extract_return_addr(__builtin_return_address(0));
for(int i = 0; i < n; ++i) {
if(addr >= segments[i].start && addr < segments[i].end) {
// Do Nothing
return 0;
}
}
return real_fputs(str, file);
}
This has some caveats, though. For example, if your executable calls a library function that tail-calls a function you're hooking, then this will incorrectly consider that library call an executable call. (You could mitigate this problem by adding wrappers for those library functions too, that unconditionally forward to the "real" function, and compiling the wrapper code with -fno-optimize-sibling-calls.) Also, there's no way to distinguish whether anonymous executable memory (e.g., JITted code) originally came from the executable or a library.
To test this, save my code as hook_fputs.c, your main executable as main.c, and your shared library as libfoo.c. Then run these commands:
clang -fPIC -shared hook_fputs.c -ldl -o hook_fputs.so
clang -fPIC -shared libfoo.c -o libfoo.so
clang main.c ./libfoo.so
LD_PRELOAD=./hook_fputs.so ./a.out
Implement the interposing library separately for the two cases.
Create a wrapper script or program that uses ldd to find out the exact EGL library version and their paths the target binary is dynamically linked against; then, using ldd on the the GLFW library, to find out whether it is linked against EGL or not. Finally, have it execute the target binary with the path to the appropriate interposing library in LD_PRELOAD environment variable.

Library interpositioning

I have been trying to intercept calls to malloc and free, following our textbook (CSAPP book).
I have followed their exact code, and nearly the same code that I found online and I keep getting a segmentation fault. I heard our professor saying something about printf that mallocs and frees memory so I think that this happens because I am intercepting a malloc and since I am using a printf function inside the intercepting function, it will call itself recursively.
However I can't seem to find a solution to solving this problem? Our professor demonstrated that intercepting worked ( he didn't show us the code) and prints our information every time a malloc occurs, so I do know that it's possible.
Can anyone suggest a working method??
Here is the code that I used and get nothing:
mymalloc.c
#ifdef RUNTIME
// Run-time interposition of malloc and free based on // dynamic linker's (ld-linux.so) LD_PRELOAD mechanism #define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h> #include <dlfcn.h>
void *malloc(size_t size) {
static void *(*mallocp)(size_t size) = NULL; char *error;
void *ptr;
// get address of libc malloc
if (!mallocp) {
mallocp = dlsym(RTLD_NEXT, "malloc"); if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(EXIT_FAILURE);
}
}
ptr = mallocp(size);
printf("malloc(%d) = %p\n", (int)size, ptr); return ptr;
}
#endif
test.c
#include <stdio.h>
#include <stdlib.h>
int main(){
printf("main\n");
int* a = malloc(sizeof(int)*5);
a[0] = 1;
printf("end\n");
}
The result i'm getting:
$ gcc -o test test.c
$ gcc -DRUNTIME -shared -fPIC mymalloc.c -o mymalloc.so
$ LD_PRELOAD=./mymalloc.so ./test
Segmentation Fault
This is the code that I tried and got segmentation fault (from https://gist.github.com/iamben/4124829):
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
void* malloc(size_t size)
{
static void* (*rmalloc)(size_t) = NULL;
void* p = NULL;
// resolve next malloc
if(!rmalloc) rmalloc = dlsym(RTLD_NEXT, "malloc");
// do actual malloc
p = rmalloc(size);
// show statistic
fprintf(stderr, "[MEM | malloc] Allocated: %lu bytes\n", size);
return p;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STR_LEN 128
int main(int argc, const char *argv[])
{
char *c;
char *str1 = "Hello ";
char *str2 = "World";
//allocate an empty string
c = malloc(STR_LEN * sizeof(char));
c[0] = 0x0;
//and concatenate str{1,2}
strcat(c, str1);
strcat(c, str2);
printf("New str: %s\n", c);
return 0;
}
The makefile from the git repo didn't work so I manually compiled the files and got:
$ gcc -shared -fPIC libint.c -o libint.so
$ gcc -o str str.c
$ LD_PRELOAD=./libint.so ./str
Segmentation fault
I have been doing this for hours and I still get the same incorrect result, despite the fact that I copied textbook code. I would really appreciate any help!!
One way to deal with this is to turn off the printf when your return is called recursively:
static char ACallIsInProgress = 0;
if (!ACallIsInProgress)
{
ACallIsInProgress = 1;
printf("malloc(%d) = %p\n", (int)size, ptr);
ACallIsInProgress = 0;
}
return ptr;
With this, if printf calls malloc, your routine will merely call the actual malloc (via mallocp) and return without causing another printf. You will miss printing information about a call to malloc that the printf does, but that is generally tolerable when interposing is being used to study the general program, not the C library.
If you need to support multithreading, some additional work might be needed.
The printf implementation might allocate a buffer only once, the first time it is used. In that case, you can initialize a flag that turns off the printf similar to the above, call printf once in the main routine (maybe be sure it includes a nice formatting task that causes printf to allocate a buffer, not a plain string), and then set the flag to turn on the printf call and leave it set for the rest of the program.
Another option is for your malloc routine not to use printf at all but to cache data in a buffer to be written later by some other routine or to write raw data to a file using write, with that data interpreted and formatted by a separate program later. Or the raw data could be written by a pipe to a program that formats and prints it and that is not using your interposed malloc.

How do I make dynamic allocations for a program run fail

I have a C program which uses malloc (it could also have been C++ with new). I would like to test my program and simulate an "out of memory" scenario.
I would strongly prefer running my program from within a bash or sh shell environment without modifying the core code.
How do I make dynamic memory allocations fail for a program run?
Seems like it could be possible using ulimit but I can't seem to find the right parameters:
$ ulimit -d 50
$ ./program_which_heap_allocates
./program_which_heap_allocates: error while loading shared libraries: libc.so.6: cannot map zero-fill pages
$ ulimit -d 51
bash: ulimit: data seg size: cannot modify limit: Operation not permitted
I'm having trouble running the program in such a way that dynamic linking can occur (such as stdlib) but not the allocations from my program.
If you are under Linux and using glibc then there are Hooks for Malloc. The hooks allow you to catch calls to malloc and make them randomly fail.
Your test suite could use an environment variable to tell the code to insert the malloc hook and which call of malloc to fail. E.g. if you set FOOBAR_FAIL_MALLOC=10 then your malloc hook would count down and let the 10th use of malloc return 0.
FOOBAR_FAIL_MALLOC=0 could simply report the numbers of mallocs in a testcase. You would then run the test once with FOOBAR_FAIL_MALLOC=0 and capture the number of mallocs involved. Then repeat for FOOBAR_FAIL_MALLOC=1 to N to test every single malloc.
Unless after a failure of malloc you have more mallocs. Then you have to think of something more complex to specify which mallocs should fail.
You could also just make the hook fail randomly. Given enough runs every malloc call would fail at some point.
Note: a C++ new should also hot the malloc hook
You can have your test program include the .c under test and use a #define to override calls to malloc.
For example:
prog.c:
#include <stdio.h>
#include <stdlib.h>
void *foo(int x)
{
return malloc(x);
}
test.c:
#include <stdio.h>
#include <stdlib.h>
static char buf[100];
static int malloc_fail;
void *test_malloc(size_t n)
{
if (malloc_fail) {
return NULL;
} else {
return buf;
}
}
#define malloc(x) test_malloc(x)
#include "prog.c"
#undef malloc
int main()
{
void *p;
malloc_fail=0;
p = foo(5);
printf("buf=%p, p=%p\n", (void *)buf, p); // prints same value both times
malloc_fail=1;
p = foo(4);
if (p) {
printf("buf=%p, p=%p\n", (void *)buf, p);
} else {
printf("p is NULL\n"); // this prints
}
return 0;
}

How would a loaded library function call a symbol in the main application?

When loaded a shared library is opened via the function dlopen(), is there a way for it to call functions in main program?
Code of dlo.c (the lib):
#include <stdio.h>
// function is defined in main program
void callb(void);
void test(void) {
printf("here, in lib\n");
callb();
}
Compile with
gcc -shared -olibdlo.so dlo.c
Here the code of the main program (copied from dlopen manpage, and adjusted):
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
void callb(void) {
printf("here, i'm back\n");
}
int
main(int argc, char **argv)
{
void *handle;
void (*test)(void);
char *error;
handle = dlopen("libdlo.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror(); /* Clear any existing error */
*(void **) (&test) = dlsym(handle, "test");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
(*test)();
dlclose(handle);
exit(EXIT_SUCCESS);
}
Build with
gcc -ldl -rdynamic main.c
Output:
[js#HOST2 dlopen]$ LD_LIBRARY_PATH=. ./a.out
here, in lib
here, i'm back
[js#HOST2 dlopen]$
The -rdynamic option puts all symbols in the dynamic symbol table (which is mapped into memory), not only the names of the used symbols. Read further about it here. Of course you can also provide function pointers (or a struct of function pointers) that define the interface between the library and your main program. It's actually the method what i would choose probably. I heard from other people that it's not so easy to do -rdynamic in windows, and it also would make for a cleaner communication between library and main program (you've got precise control on what can be called and not), but it also requires more house-keeping.
Yes, If you provide your library a pointer to that function, I'm sure the library will be able to run/execute the function in the main program.
Here is an example, haven't compiled it so beware ;)
/* in main app */
/* define your function */
int do_it( char arg1, char arg2);
int do_it( char arg1, char arg2){
/* do it! */
return 1;
}
/* some where else in main app (init maybe?) provide the pointer */
LIB_set_do_it(&do_it);
/** END MAIN CODE ***/
/* in LIBRARY */
int (*LIB_do_it_ptr)(char, char) = NULL;
void LIB_set_do_it( int (*do_it_ptr)(char, char) ){
LIB_do_it_ptr = do_it_ptr;
}
int LIB_do_it(){
char arg1, arg2;
/* do something to the args
...
... */
return LIB_do_it_ptr( arg1, arg2);
}
The dlopen() function, as discussed by #litb, is primarily provided on systems using ELF format object files. It is rather powerful and will let you control whether symbols referenced by the loaded library can be satisfied from the main program, and generally does let them be satisfied. Not all shared library loading systems are as flexible - be aware if it comes to porting your code.
The callback mechanism outlined by #hhafez works now that the kinks in that code are straightened out.

Resources