mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-08 09:20:11 +01:00
Add temporary debug code to allow better debugging of races
with various udev-event tools which wrongly scan and open internal temporary cryptsetup devices. If cryptsetup run in debug mode (--debug) and remove of device fails, code scan /proc directory and tries to find process name which locked that device. git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@141 36d66b0a-2a48-0410-832c-cd162a569da5
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
* Add CRYPT_ prefix to enum defined in libcryptsetup.h.
|
||||
* Fix status call to fail when running as non-root user.
|
||||
* Check in configure if selinux libraries are required in static version.
|
||||
* Add temporary debug code to find processes locking internal device.
|
||||
|
||||
2009-09-30 Milan Broz <mbroz@redhat.com>
|
||||
* Fix exported symbols and versions in libcryptsetup.
|
||||
|
||||
@@ -42,6 +42,7 @@ libcryptsetup_la_SOURCES = \
|
||||
blockdev.h \
|
||||
libcryptsetup.h \
|
||||
utils.c \
|
||||
utils_debug.c \
|
||||
backends.c \
|
||||
libdevmapper.c \
|
||||
gcrypt.c
|
||||
|
||||
@@ -116,6 +116,9 @@ void logger(struct crypt_device *cd, int class, const char *file, int line, cons
|
||||
logger(c, CRYPT_LOG_ERROR, __FILE__, __LINE__, x); \
|
||||
set_error(x); } while(0)
|
||||
|
||||
int crypt_get_debug_level(void);
|
||||
void debug_processes_using_device(const char *name);
|
||||
|
||||
int crypt_memlock_inc(struct crypt_device *ctx);
|
||||
int crypt_memlock_dec(struct crypt_device *ctx);
|
||||
|
||||
|
||||
@@ -249,6 +249,8 @@ int dm_remove_device(const char *name, int force, uint64_t size)
|
||||
if (--retries && r) {
|
||||
log_dbg("WARNING: other process locked internal device %s, %s.",
|
||||
name, retries ? "retrying remove" : "giving up");
|
||||
if (force && (crypt_get_debug_level() == CRYPT_LOG_DEBUG))
|
||||
debug_processes_using_device(name);
|
||||
sleep(1);
|
||||
if (force && !error_target) {
|
||||
/* If force flag is set, replace device with error, read-only target.
|
||||
|
||||
@@ -47,6 +47,11 @@ void crypt_set_debug_level(int level)
|
||||
_debug_level = level;
|
||||
}
|
||||
|
||||
int crypt_get_debug_level()
|
||||
{
|
||||
return _debug_level;
|
||||
}
|
||||
|
||||
void crypt_log(struct crypt_device *cd, int class, const char *msg)
|
||||
{
|
||||
if (cd && cd->log)
|
||||
|
||||
130
lib/utils_debug.c
Normal file
130
lib/utils_debug.c
Normal file
@@ -0,0 +1,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);
|
||||
}
|
||||
Reference in New Issue
Block a user