From 49ba60e9e0fb4439d8c8eb419daf71cc6d2c7d2b Mon Sep 17 00:00:00 2001 From: DL6ER Date: Fri, 5 Feb 2021 08:16:15 +0100 Subject: [PATCH] Do not try to delete existing shmem objects on start - that may cause running FTL instances to crash when it tries to access them. Instead, new instances should properly fail to start. Signed-off-by: DL6ER --- src/CMakeLists.txt | 2 + src/gc.c | 2 +- src/log.c | 25 ++++++--- src/log.h | 2 +- src/main.c | 2 + src/procps.c | 133 +++++++++++++++++++++++++++++++++++++++++++++ src/procps.h | 15 +++++ src/shmem.c | 26 ++------- 8 files changed, 177 insertions(+), 30 deletions(-) create mode 100644 src/procps.c create mode 100644 src/procps.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e2d6facc8..5dc4ce6d4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -133,6 +133,8 @@ set(sources main.h overTime.c overTime.h + procps.c + procps.h regex.c regex_r.h resolve.c diff --git a/src/gc.c b/src/gc.c index f29409bfe..f76461c95 100644 --- a/src/gc.c +++ b/src/gc.c @@ -56,7 +56,7 @@ void *GC_thread(void *val) { timer_start(GC_TIMER); char timestring[84] = ""; - get_timestr(timestring, mintime); + get_timestr(timestring, mintime, false); logg("GC starting, mintime: %s (%llu)", timestring, (long long)mintime); } diff --git a/src/log.c b/src/log.c index 51c171d39..648bb2975 100644 --- a/src/log.c +++ b/src/log.c @@ -79,18 +79,27 @@ void open_FTL_log(const bool init) // The size of 84 bytes has been carefully selected for all possible timestamps // to always fit into the available space without buffer overflows -void get_timestr(char * const timestring, const time_t timein) +void get_timestr(char * const timestring, const time_t timein, const bool millis) { struct tm tm; localtime_r(&timein, &tm); - struct timeval tv; - gettimeofday(&tv, NULL); - const int millisec = tv.tv_usec/1000; + if(millis) + { + struct timeval tv; + gettimeofday(&tv, NULL); + const int millisec = tv.tv_usec/1000; - sprintf(timestring,"%d-%02d-%02d %02d:%02d:%02d.%03i", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, millisec); + sprintf(timestring,"%d-%02d-%02d %02d:%02d:%02d.%03i", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, millisec); + } + else + { + sprintf(timestring,"%d-%02d-%02d %02d:%02d:%02d", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + } } void _FTL_log(const bool newline, const char *format, ...) @@ -104,7 +113,7 @@ void _FTL_log(const bool newline, const char *format, ...) pthread_mutex_lock(&lock); - get_timestr(timestring, time(NULL)); + get_timestr(timestring, time(NULL), true); // Get and log PID of current process to avoid ambiguities when more than one // pihole-FTL instance is logging into the same file diff --git a/src/log.h b/src/log.h index eb99cd52e..821d6b28c 100644 --- a/src/log.h +++ b/src/log.h @@ -21,7 +21,7 @@ void format_memory_size(char * const prefix, unsigned long long int bytes, void format_time(char buffer[42], unsigned long seconds, double milliseconds); const char *get_FTL_version(void) __attribute__ ((malloc)); void log_FTL_version(bool crashreport); -void get_timestr(char * const timestring, const time_t timein); +void get_timestr(char * const timestring, const time_t timein, const bool millis); const char *get_ordinal_suffix(unsigned int number) __attribute__ ((const)); // The actual logging routine can take extra options for specialized logging diff --git a/src/main.c b/src/main.c index 3b9fb8da0..bbdad82ac 100644 --- a/src/main.c +++ b/src/main.c @@ -24,6 +24,7 @@ #include "capabilities.h" #include "database/gravity-db.h" #include "timers.h" +#include "procps.h" char * username; bool needGC = false; @@ -59,6 +60,7 @@ int main (int argc, char* argv[]) if(!init_shmem(true)) { logg("Initialization of shared memory failed."); + check_running_FTL(); return EXIT_FAILURE; } diff --git a/src/procps.c b/src/procps.c new file mode 100644 index 000000000..c3c16f1d7 --- /dev/null +++ b/src/procps.c @@ -0,0 +1,133 @@ +/* Pi-hole: A black hole for Internet advertisements +* (c) 2021 Pi-hole, LLC (https://pi-hole.net) +* Network-wide ad blocking via your own hardware. +* +* FTL Engine +* /proc system subroutines +* +* This file is copyright under the latest version of the EUPL. +* Please see LICENSE file for your rights under this license. */ + +#include "FTL.h" +#include "procps.h" +#include "log.h" +#include +// getpid() +#include + +#define PROCESS_NAME "pihole-FTL" + +static bool get_process_name(const pid_t pid, char name[128]) +{ + if(pid == 0) + { + strcpy(name, "init"); + return true; + } + + // Try to open comm file + char filename[sizeof("/proc/%u/task/%u/comm") + sizeof(int)*3 * 2]; + snprintf(filename, sizeof(filename), "/proc/%d/comm", pid); + FILE *f = fopen(filename, "r"); + if(f == NULL) + return false; + + // Read name from opened file + if(fscanf(f, "%128s", name) != 1) + false; + fclose(f); + + return true; +} + + +static bool get_process_ppid(const pid_t pid, pid_t *ppid) +{ + // Try to open status file + char filename[sizeof("/proc/%u/task/%u/comm") + sizeof(int)*3 * 2]; + snprintf(filename, sizeof(filename), "/proc/%d/status", pid); + FILE *f = fopen(filename, "r"); + if(f == NULL) + return false; + + // Read comm from opened file + char buffer[128]; + while(fgets(buffer, sizeof(buffer), f) != NULL) + { + if(sscanf(buffer, "PPid: %d\n", ppid) == 1) + break; + } + fclose(f); + + return true; +} + +static bool get_process_creation_time(const pid_t pid, char timestr[84]) +{ + // Try to open comm file + char filename[sizeof("/proc/%u/task/%u/comm") + sizeof(int)*3 * 2]; + snprintf(filename, sizeof(filename), "/proc/%d/comm", pid); + struct stat st; + if(stat(filename, &st) < 0) + return false; + get_timestr(timestr, st.st_ctim.tv_sec, false); + + return true; +} + +void check_running_FTL(void) +{ + //pid_t pid; + DIR *dirPos; + struct dirent *entry; + + // Open /proc + errno = 0; + if ((dirPos = opendir("/proc")) == NULL) + { + logg("Dailed to access /proc: %s", strerror(errno)); + return; + } + + // Loop over entries in /proc + // This is much more efficient than iterating over all possible PIDs + while ((entry = readdir(dirPos)) != NULL) + { + // We are only interested in subdirectories of /proc + if(entry->d_type != DT_DIR) + continue; + // We are only interested in PID subdirectories + if(entry->d_name[0] < '0' || entry->d_name[0] > '9') + continue; + + // Extract PID + const pid_t pid = strtol(entry->d_name, NULL, 10); + + // Skip our own process + if(pid == getpid()) + continue; + + // Get process name + char name[128] = { 0 }; + if(!get_process_name(pid, name)) + continue; + + // Get parent process ID (PPID) + pid_t ppid; + if(!get_process_ppid(pid, &ppid)) + continue; + char ppid_name[128] = { 0 }; + if(!get_process_name(ppid, ppid_name)) + continue; + + char timestr[84] = { 0 }; + get_process_creation_time(pid, timestr); + + // Log this process if it is a duplicate of us + if(strcasecmp(name, PROCESS_NAME) == 0) + logg("---> %s is already running as PID %d (started %s, child of PID %i (%s))", + PROCESS_NAME, pid, timestr, ppid, ppid_name); + } + + closedir(dirPos); +} diff --git a/src/procps.h b/src/procps.h new file mode 100644 index 000000000..2993fbca5 --- /dev/null +++ b/src/procps.h @@ -0,0 +1,15 @@ +/* Pi-hole: A black hole for Internet advertisements +* (c) 2021 Pi-hole, LLC (https://pi-hole.net) +* Network-wide ad blocking via your own hardware. +* +* FTL Engine +* /proc system prototypes +* +* This file is copyright under the latest version of the EUPL. +* Please see LICENSE file for your rights under this license. */ + +#ifndef PROCPS_H +#define PROCPS_H +void check_running_FTL(void); + +#endif // POCPS_H \ No newline at end of file diff --git a/src/shmem.c b/src/shmem.c index 0581f46eb..a8963284e 100644 --- a/src/shmem.c +++ b/src/shmem.c @@ -548,28 +548,14 @@ SharedMemory create_shm(const char *name, const size_t size, bool create_new) }; // O_RDWR: Open the object for read-write access (we need to be able to modify the locks) - int shm_oflags = O_RDWR; - if(create_new) - { - // Try unlinking the shared memory object before creating a new one. - // If the object is still existing, e.g., due to a past unclean exit - // of FTL, shm_open() would fail with error "File exists" - int ret = shm_unlink(name); - // Check return code. shm_unlink() returns -1 on error and sets errno - // We specifically ignore ENOENT (No such file or directory) as this is not an - // error in our use case (we only want the file to be deleted when existing) - if(ret != 0 && errno != ENOENT) - logg("create_shm(): shm_unlink(\"%s\") failed: %s (%i)", name, strerror(errno), errno); - - // Replace shm_oflags - // O_CREAT: Create the shared memory object if it does not exist. - // O_EXCL: Return an error if a shared memory object with the given name already exists. - // O_TRUNC: If the shared memory object already exists, truncate it to zero bytes. - shm_oflags |= O_CREAT | O_EXCL | O_TRUNC; - } + // When creating a new shared memory object, we add to this + // - O_CREAT: Create the shared memory object if it does not exist. + // - O_EXCL: Return an error if a shared memory object with the given name already exists. + const int shm_oflags = create_new ? O_RDWR | O_CREAT | O_EXCL : O_RDWR; // Create the shared memory file in read/write mode with 600 permissions - int fd = shm_open(sharedMemory.name, shm_oflags, S_IRUSR | S_IWUSR); + errno = 0; + const int fd = shm_open(sharedMemory.name, shm_oflags, S_IRUSR | S_IWUSR); // Check for `shm_open` error if(fd == -1)