How to use popen() in a shared library?

573 views Asked by At

When attempting to use popen() in a shared library and preloading it via LD_PRELOAD or /etc/ld.so.preload, the process gets stuck in an infinite loop with either an error message saying that the shared library cannot be preloaded, or the system just freezes and needs to be rebooted, depending on the code.

Please note that compiling not as a shared library (gcc test.c; ./a.out) will work without error.

If it is helpful, I am running a fresh install of Debian on VirtualBox:

Linux debian 3.16.0-4-586 #1 Debian 3.16.36-1+deb8u2 (2016-10-19) i686 GNU/Linux

Okay, so this code:

#define _GNU_SOURCE
#include <stdio.h>

__attribute__((constructor, visibility("hidden")))
void init()
{
    FILE *fp = popen("/usr/bin/id", "r");
    pclose(fp);
}

Results in the first case:

root@debian:/mnt/group/hcfrk# gcc test.c -o test.so -std=c99 -shared -fPIC
root@debian:/mnt/group/hcfrk# LD_PRELOAD=./test.so whoami
ERROR: ld.so: object './test.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
ERROR: ld.so: object './test.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
ERROR: ld.so: object './test.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
ERROR: ld.so: object './test.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
# For eternity.

This code:

...
#include <limits.h>
...
{
    FILE *fp = popen("/usr/bin/id", "r");

    if(!fp)
        puts("Error.\n");

    char buf[PATH_MAX];

    while(fgets(buf, sizeof buf, fp))
        printf("%s\n", buf);

    pclose(fp);    // Never gets here: VM just freezes.
}

Results in the second case (the system freezes). I suspect it is because of the while loop not ending and causing pclose() to not be called, as the first code example will freeze the system without pclose() as well.

Any help would be appreciated. Thank you!

1

There are 1 answers

2
yugr On BEST ANSWER

Aren't you forkbombing here? Constructor in LD_PRELOAD will cause /usr/bin/id to execute itself forever (as each new instance will get get your library preloaded), most probably halting your machine. You should probably unsetenv before popening.