1 /* 2 * Temporary debug code to find processes locking internal cryptsetup devices. 3 * This code is intended to run only in debug mode. 4 * 5 * inspired by psmisc/fuser proc scanning code 6 */ 7 #include <stdint.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <errno.h> 11 #include <sys/types.h> 12 #include <sys/stat.h> 13 #include <dirent.h> 14 #include <fcntl.h> 15 #include <unistd.h> 16 #include <string.h> 17 #include "libcryptsetup.h" 18 #include "internal.h" 19 20 #define MAX_PATHNAME 1024 21 #define MAX_SHORTNAME 64 22 23 static int numeric_name(const char *name) 24 { 25 return (name[0] < '0' || name[0] > '9') ? 0 : 1; 26 } 27 28 static int check_pid(const pid_t pid, const char *dev_name, const char *short_dev_name) 29 { 30 char dirpath[MAX_SHORTNAME], fdpath[MAX_SHORTNAME], linkpath[MAX_PATHNAME]; 31 DIR *dirp; 32 struct dirent *direntry; 33 size_t len; 34 int r = 0; 35 36 snprintf(dirpath, sizeof(dirpath), "/proc/%d/fd", pid); 37 38 if (!(dirp = opendir(dirpath))) 39 return r; 40 41 while ((direntry = readdir(dirp))) { 42 if (!numeric_name(direntry->d_name)) 43 continue; 44 45 snprintf(fdpath, sizeof(fdpath), "/proc/%d/fd/%s", pid, direntry->d_name); 46 47 if ((len = readlink(fdpath, linkpath, MAX_PATHNAME-1)) < 0) 48 break; 49 linkpath[len] = '\0'; 50 51 if (!strcmp(dev_name, linkpath)) { 52 r = 1; 53 break; 54 } 55 56 if (!strcmp(short_dev_name, linkpath)) { 57 r = 2; 58 break; 59 } 60 } 61 closedir(dirp); 62 return r; 63 } 64 65 static int read_proc_info(const pid_t pid, pid_t *ppid, char *name, int max_size) 66 { 67 char path[MAX_SHORTNAME], info[max_size], c; 68 int fd, xpid, r = 0; 69 70 snprintf(path, sizeof(path), "/proc/%u/stat", pid); 71 if ((fd = open(path, O_RDONLY)) < 0) 72 return 0; 73 74 if (read(fd, info, max_size) > 0 && 75 sscanf(info, "%d %s %c %d", &xpid, name, &c, ppid) == 4) 76 r = 1; 77 78 if (!r) { 79 *ppid = 0; 80 name[0] = '\0'; 81 } 82 close(fd); 83 return r; 84 } 85 86 static void report_proc(const pid_t pid, const char *dev_name) 87 { 88 char name[MAX_PATHNAME], name2[MAX_PATHNAME]; 89 pid_t ppid, ppid2; 90 91 if (read_proc_info(pid, &ppid, name, MAX_PATHNAME) && 92 read_proc_info(ppid, &ppid2, name2, MAX_PATHNAME)) 93 log_dbg("WARNING: Process PID %u %s [PPID %u %s] spying on internal device %s.", 94 pid, name, ppid, name2, dev_name); 95 } 96 97 void debug_processes_using_device(const char *dm_name) 98 { 99 char short_dev_name[MAX_SHORTNAME], dev_name[MAX_PATHNAME]; 100 DIR *proc_dir; 101 struct dirent *proc_dentry; 102 struct stat st; 103 pid_t pid; 104 105 if (crypt_get_debug_level() != CRYPT_LOG_DEBUG) 106 return; 107 108 snprintf(dev_name, sizeof(dev_name), "/dev/mapper/%s", dm_name); 109 if (stat(dev_name, &st) || !S_ISBLK(st.st_mode)) 110 return; 111 snprintf(short_dev_name, sizeof(short_dev_name), "/dev/dm-%u", minor(st.st_rdev)); 112 113 if (!(proc_dir = opendir("/proc"))) 114 return; 115 116 while ((proc_dentry = readdir(proc_dir))) { 117 if (!numeric_name(proc_dentry->d_name)) 118 continue; 119 120 pid = atoi(proc_dentry->d_name); 121 switch(check_pid(pid, dev_name, short_dev_name)) { 122 case 1: report_proc(pid, dev_name); 123 break; 124 case 2: report_proc(pid, short_dev_name); 125 default: 126 break; 127 } 128 } 129 closedir(proc_dir); 130 } 131