Package: eject Version: 2.1.5+deb1+cvs20081104-11 Severity: wishlist Dear Maintainer, I noticed that the only reason dmcrypt-get-device (from eject package) needs setuid privilege is to read the major:minor numbers (unless I have missed something). A lot of distributions are trying to avoid use of the setuid bit because it can potentially introduce a privilege escalation attack vector. I think the same thing could be accomplished by reading the major:minor device numbers through a sys file, and then eliminate the need for dmcrypt-get-device to be setuid-to-root. The major:minor numbers are available in the file /sys/block/dm-*/dev and the corresponding device name can be confirmed from file /sys/block/dm-*/dm/name. Martin Pitt - the author of dmcrypt-get-device.c - suggested that I should send the patch here and you could help integrate and comment on the patch. Attached is the patch for dmcrypt-get-device.c.
-- System Information: Debian Release: wheezy/sid APT prefers quantal-updates APT policy: (500, 'quantal-updates'), (500, 'quantal-security'), (500, 'quantal'), (100, 'quantal-backports') Architecture: i386 (i686) Kernel: Linux 3.5.0-17-generic (SMP w/1 CPU core) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages eject depends on: ii libc6 2.15-0ubuntu20 ii libdevmapper1.02.1 2:1.02.74-4ubuntu1 eject recommends no packages. Versions of packages eject suggests: pn cdtool <none> pn setcd <none> -- no debconf information
--- original-dmcrypt-get-device.c 2012-12-09 05:29:50.792388997 -0500 +++ dmcrypt-get-device.c 2012-12-09 05:38:00.512388998 -0500 @@ -15,20 +15,22 @@ * parsing is done with normal user privileges afterwards. */ -#include <libdevmapper.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <unistd.h> +#include <dirent.h> +#include <stdlib.h> +#include <linux/dm-ioctl.h> int main (int argc, char** argv) { - struct dm_task *dmt = NULL; - struct dm_info dmi; - char *target_type = NULL, *params = NULL; - uint64_t start, length; - void *next = NULL; + DIR *dir; + FILE *file; + struct dirent *ent; + char filename[4096]; + char name[DM_NAME_LEN]; struct stat st; unsigned major, minor; @@ -49,37 +51,35 @@ if (stat (argv[1], &st) || !S_ISBLK(st.st_mode)) return 1; - /* Request device info */ - if (!(dmt = dm_task_create(DM_DEVICE_TABLE))) - return 1; - if (!dm_task_set_name(dmt, argv[1])) - return 1; - if (!dm_task_run(dmt)) - return 1; - - /* Drop all privileges */ - setgid(getgid()); - setuid(getuid()); - - if (!dm_task_get_info(dmt, &dmi)) - return 1; - - /* Get underlying physical device */ - next = dm_get_next_target(dmt, next, &start, &length, - &target_type, ¶ms); - - /* verify validity and that it is a dmcrypt device */ - if (!target_type || strcmp(target_type, "crypt") || next) - return 1; - - /* params has the format: cipher key offset major:minor <unknown> */ - length = sscanf(params, "%*s %*s %*s %u:%u %*s", &major, &minor); - if (length != 2) - return 1; + if ((dir = opendir("/sys/block")) == NULL) + { + perror("Unable to open directory"); + return 1; + } - /* Success */ - printf ("%u:%u\n", major, minor); - - return 0; + while ((ent = readdir(dir)) != NULL) + { + const char* dmname = "dm-"; + /* Check for the device name */ + if(!strncmp(ent->d_name, dmname, strlen(dmname))) + { + sprintf(filename,"/sys/block/%s/dm/name",ent->d_name); + file = fopen(filename,"r"); + fscanf(file,"%s",name); + fclose(file); + /* Read the major:minor number for given device */ + if(!strcmp(name,argv[1] + devmapdirlen)) + { + sprintf(filename,"/sys/block/%s/dev",ent->d_name); + file = fopen(filename,"r"); + fscanf(file,"%u:%u",&major,&minor); + /* Success */ + printf ("%u:%u\n", major, minor); + fclose(file); + return 0; + } + } + } + /* Not found */ + return 1; } -