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