Diamorphine
Diamorphine copied to clipboard
Segmentation fault at readdir64 on CentOS 7
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.