/* * Temporary debug code to find processes locking internal cryptsetup devices. * This code is intended to run only in debug mode. * * inspired by psmisc/fuser proc scanning code */ #include #include #include #include #include #include #include #include #include #include #include "libcryptsetup.h" #include "internal.h" #define MAX_PATHNAME 1024 #define MAX_SHORTNAME 64 static int numeric_name(const char *name) { return (name[0] < '0' || name[0] > '9') ? 0 : 1; } static int check_pid(const pid_t pid, const char *dev_name, const char *short_dev_name) { char dirpath[MAX_SHORTNAME], fdpath[MAX_SHORTNAME], linkpath[MAX_PATHNAME]; DIR *dirp; struct dirent *direntry; size_t len; int r = 0; snprintf(dirpath, sizeof(dirpath), "/proc/%d/fd", pid); if (!(dirp = opendir(dirpath))) return r; while ((direntry = readdir(dirp))) { if (!numeric_name(direntry->d_name)) continue; snprintf(fdpath, sizeof(fdpath), "/proc/%d/fd/%s", pid, direntry->d_name); if ((len = readlink(fdpath, linkpath, MAX_PATHNAME-1)) < 0) break; linkpath[len] = '\0'; if (!strcmp(dev_name, linkpath)) { r = 1; break; } if (!strcmp(short_dev_name, linkpath)) { r = 2; break; } } closedir(dirp); return r; } static int read_proc_info(const pid_t pid, pid_t *ppid, char *name, int max_size) { char path[MAX_SHORTNAME], info[max_size], c; int fd, xpid, r = 0; snprintf(path, sizeof(path), "/proc/%u/stat", pid); if ((fd = open(path, O_RDONLY)) < 0) return 0; if (read(fd, info, max_size) > 0 && sscanf(info, "%d %s %c %d", &xpid, name, &c, ppid) == 4) r = 1; if (!r) { *ppid = 0; name[0] = '\0'; } close(fd); return r; } static void report_proc(const pid_t pid, const char *dev_name) { char name[MAX_PATHNAME], name2[MAX_PATHNAME]; pid_t ppid, ppid2; if (read_proc_info(pid, &ppid, name, MAX_PATHNAME) && read_proc_info(ppid, &ppid2, name2, MAX_PATHNAME)) log_dbg("WARNING: Process PID %u %s [PPID %u %s] spying on internal device %s.", pid, name, ppid, name2, dev_name); } void debug_processes_using_device(const char *dm_name) { char short_dev_name[MAX_SHORTNAME], dev_name[MAX_PATHNAME]; DIR *proc_dir; struct dirent *proc_dentry; struct stat st; pid_t pid; if (crypt_get_debug_level() != CRYPT_LOG_DEBUG) return; snprintf(dev_name, sizeof(dev_name), "/dev/mapper/%s", dm_name); if (stat(dev_name, &st) || !S_ISBLK(st.st_mode)) return; snprintf(short_dev_name, sizeof(short_dev_name), "/dev/dm-%u", minor(st.st_rdev)); if (!(proc_dir = opendir("/proc"))) return; while ((proc_dentry = readdir(proc_dir))) { if (!numeric_name(proc_dentry->d_name)) continue; pid = atoi(proc_dentry->d_name); switch(check_pid(pid, dev_name, short_dev_name)) { case 1: report_proc(pid, dev_name); break; case 2: report_proc(pid, short_dev_name); default: break; } } closedir(proc_dir); }