[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#844237: Incorrect handling of device major/minor



Package: libefivar1
Version: 30-1
Severity: important
Tags: upstream patch

Part of the code in linux.c uses "st_rdev >> 8" and "st_rdev & 0xFF" to find
the major and minor device number for the disk to install. It was correct a
long time ago but it has been quite some time that both major and minor can
exceed 8 bits. The libc provides macros to extract the major and minor;
another part of the same file uses these macros. Furthermore, the field
containing the minor is declared as unsigned char, making it 8 bits.

The result is a failure to prepare boot variables, making grub-install fail
for example, for a device with a minor >= 256. The device I needed to use
was 179:256. Running with strace showed an attempt to access
/sys/dev/block/4275:0 instead of /sys/dev/block/179:256 that would have been
correct considering the previous system call was fstat() showing
"st_rdev=makedev(179, 256)". You can notice that 179+256*16 = 4275.

The attached patch fixes things.

Regards,

-- 
  Nicolas George


-- System Information:
Debian Release: stretch/sid
  APT prefers stable-updates
  APT policy: (500, 'stable-updates'), (500, 'testing'), (500, 'stable'), (50, 'unstable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 4.6.0-1-amd64 (SMP w/8 CPU cores)
Locale: LANG=, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)

Versions of packages libefivar1:amd64 depends on:
ii  libc6  2.24-5

libefivar1:amd64 recommends no packages.

libefivar1:amd64 suggests no packages.

-- no debconf information
diff -ru orig/efivar-30/src/linux.c efivar-30/src/linux.c
--- orig/efivar-30/src/linux.c	2016-10-03 18:29:32.000000000 +0200
+++ efivar-30/src/linux.c	2016-11-13 16:55:17.001150388 +0100
@@ -55,7 +55,7 @@
 	char *linkbuf;
 	ssize_t rc;
 
-	rc = sysfs_readlink(&linkbuf, "/sys/dev/block/%"PRIu64":%hhu",
+	rc = sysfs_readlink(&linkbuf, "/sys/dev/block/%"PRIu64":%"PRIu32,
 		      info->major, info->minor);
 	if (rc < 0)
 		return -1;
@@ -913,11 +913,11 @@
 		return 1;
 	}
 	if (S_ISBLK(buf.st_mode)) {
-		info->major = buf.st_rdev >> 8;
-		info->minor = buf.st_rdev & 0xFF;
+		info->major = major(buf.st_rdev);
+		info->minor = minor(buf.st_rdev);
 	} else if (S_ISREG(buf.st_mode)) {
-		info->major = buf.st_dev >> 8;
-		info->minor = buf.st_dev & 0xFF;
+		info->major = major(buf.st_dev);
+		info->minor = minor(buf.st_dev);
 	} else {
 		printf("Cannot stat non-block or non-regular file\n");
 		return 1;
diff -ru orig/efivar-30/src/linux.h efivar-30/src/linux.h
--- orig/efivar-30/src/linux.h	2016-10-03 18:29:32.000000000 +0200
+++ efivar-30/src/linux.h	2016-11-13 16:47:30.773353757 +0100
@@ -75,7 +75,7 @@
 	unsigned int disknum;
 	unsigned char part;
 	uint64_t major;
-	unsigned char minor;
+	uint32_t minor;
 	uint32_t edd10_devicenum;
 
 	struct pci_root_info pci_root;

Attachment: signature.asc
Description: Digital signature


Reply to: