1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
/*
* 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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#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);
}
|