Overriding getdirentries in C

718 views Asked by At

I would like to override getdirentries (and others, like lstat) libc syscalls. I can override -for example- lstat and chmod, but I can't override getdirentries (and amongst others fstatfs).

Example code is:

    #include <errno.h>
    #include <dlfcn.h>
    #include <stdio.h>
    #include <strings.h>
    #include <string.h>
    #include <sys/_timespec.h>
    #include <sys/stat.h>
    #include <sys/mount.h>

    #ifndef RTLD_NEXT
    #define RTLD_NEXT   ((void *) -1l)
    #endif

    int (*getdirentries_orig)(int fd, char *buf, int nbytes, long *basep);
    int (*lstat_orig)(const char *path, struct stat *sb);
    int (*fstatfs_orig)(int fd, struct statfs *buf);
    int (*chmod_orig)(const char *path, mode_t mode);

    #define HOOK(func) func##_##orig = dlsym(RTLD_NEXT,#func)

    int getdirentries(int fd, char *buf, int nbytes, long *basep) {
        HOOK(getdirentries);
        printf("getdirentries\n");
        return getdirentries_orig(fd, buf, nbytes, basep);
    }

    int lstat(const char *path, struct stat *sb) {
        HOOK(lstat);
        printf("lstat\n");
        return (lstat_orig(path, sb));
    }

    int fstatfs(int fd, struct statfs *buf) {
        HOOK(fstatfs);
        printf("fstatfs\n");
        return fstatfs_orig(fd, buf);
    }

    int chmod(const char *path, mode_t mode) {
        HOOK(chmod);
        printf("chmod\n");
        return chmod_orig(path, mode);
    }

I compile this on FreeBSD with:

cc -Wall -g -O2 -fPIC -shared -o preload.so preload.c

(on Linux, adding -ldl may be needed) and use it with LD_PRELOAD=./preload.so bash.

If I then issue an ls -l, I get "lstat" printed multiple times, that's good. But ls calls multiple getdirentries too, according to ktrace, and its override function does not get called. fstatfs also doesn't work.

How can I override getdirentries, fstatfs and possibly other syscalls, and why they aren't working in this case?

Thanks,

1

There are 1 answers

0
user582175 On BEST ANSWER

As it turns out, readdir() in libc/readdir.c (readdir is what ls calls and that should call getdirentries) calls _getdirentries, not getdirentries. If I override _getdirentries, it works. The same for fstatfs, so this is why my program did not work.