Diamorphine icon indicating copy to clipboard operation
Diamorphine copied to clipboard

Segmentation fault at readdir64 on CentOS 7

Open vikman90 opened this issue 2 years ago • 0 comments

Hi, we've found an issue that happens during a scan of /proc on CentOS 7 (kernel 3.10.0-1160.36.2.el7.x86_64): the program sometimes crashes (https://github.com/wazuh/wazuh/issues/9737) and sometimes falls into an infinite loop (https://github.com/wazuh/wazuh/issues/9032), when Diamorphine (commit 8988105) is installed.

We've written this program to detect this problem:

testproc.c
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>

volatile bool keepalive = false;

// List content of a directory
static void list_dir(const char * dirname, int depth) {
    char fname[PATH_MAX];
    struct dirent * entry;
    DIR * dir = opendir(dirname);

    if (dir == NULL) {
        return;
    }

    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_name[0] == '.' && (entry->d_name[1] == '\0' || (entry->d_name[1] == '.' && entry->d_name[2] == '\0'))) {
            continue;
        }

        snprintf(fname, PATH_MAX, "%s/%s", dirname, entry->d_name);
        puts(fname);

        if (depth > 0) {
            list_dir(fname, depth - 1);
        }
    }

    closedir(dir);
    keepalive = true;
}

// Monitor keepalive with 1-second timeout
static void * monitor_main() {
    int delay = 0;

    while (true) {
        sleep(1);

        if (keepalive) {
            if (delay > 0) {
                fprintf(stderr, "INFO: Program is now responding.\n");
            }
            delay = 0;
            keepalive = false;
        } else {
            fprintf(stderr, "WARNING: Program is taking %d sec. to respond.\n", ++delay);
        }
    }

    return NULL;
}

// Launch monitor thread
static void run_monitor() {
    pthread_t thread;

    int r = pthread_create(&thread, NULL, (void *(*)(void *))monitor_main, NULL);

    if (r != 0) {
        fprintf(stderr, "ERROR: Cannot run thread: %s\n", strerror(r));
        exit(EXIT_FAILURE);
    }

    r = pthread_detach(thread);

    if (r != 0) {
        fprintf(stderr, "ERROR: Cannot detach thread: %s\n", strerror(r));
    }
}

int main(int argc, char ** argv) {
    run_monitor();

    while (true) {
        if (argc > 1) {
            int i;
            for (i = 1; i < argc; i++) {
                list_dir(argv[i], 1);
            }
        } else {
            list_dir("/proc", 1);
        }
    }

    return EXIT_SUCCESS;
}

How to reproduce

We've managed to reproduce this problem by scanning /proc and launching lots of ephemeral processes (/bin/echo). I think that the issue occurs when a directory (or its content) is removed while readdir() is getting it. However, I don't know if this happens only with /proc.

insmod diamorphine.ko
for i in {1..8}; do while true; do /bin/echo Hello > /dev/null; done & done

Catching the issue

gcc -g -pthread -o testproc testproc.c
./testproc > /dev/null

(... Few seconds after running the loops above ...)

WARNING: Program is taking 1 sec. to respond.
WARNING: Program is taking 2 sec. to respond.
WARNING: Program is taking 3 sec. to respond.
WARNING: Program is taking 4 sec. to respond.
(...)

Backtrace

#0  0x00007f8f83b9b334 in __getdents64 () from /lib64/libc.so.6
#1  0x00007f8f83b9af11 in readdir64 () from /lib64/libc.so.6
#2  0x00000000004009bb in list_dir (dirname=0x7ffe3a11ff10 "/proc/31244",
    depth=0) at testproc.c:22
#3  0x00000000004009af in list_dir (dirname=0x400c91 "/proc", depth=1)
    at testproc.c:31
#4  0x0000000000400b5b in main (argc=1, argv=0x7ffe3a121038)
    at testproc.c:88

Hope this helps find the cause of the bug.

Thank you.

vikman90 avatar Aug 23 '21 17:08 vikman90