Skip to content

Segmentation fault at readdir64 on CentOS 7 #31

@vikman90

Description

@vikman90

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 (wazuh/wazuh#9737) and sometimes falls into an infinite loop (wazuh/wazuh#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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions