linux: Fix interpretation of device numbers in /proc/pid/maps

While the kernel formats device major and minor numbers as %02x:%02x,
they are not restricted to 8 bits apiece. Crashpad was requiring that
the hexadecimal representations be exactly two characters, rather than
at least two characters.

The proper way to reconstruct a dev_t from major and minor numbers in
user space is to use makedev() from <sys/sysmacros.h>. MKDEV() from
<linux/kdev_t.h> interfaces with an older (pre-Linux 2.6) format which
actually did use 8-bit major and minor numbers. makedev() places the
major number at bits 8-19, and splits the minor number into two groups
at bits 0-7 and 20-31. This is the correct user space view of device
numbers. (Note that this is distinct from the kernel’s view: the kernel
uses MKDEV() from a distinct internal <linux/kdev_t.h> which places the
minor number at bits 0-19 and the major number at bits 20-31.)

Bionic for 32-bit platforms uses a 32-bit user space dev_t while a
64-bit version is used elsewhere, and a comment in Bionic’s
<sys/types.h> calls this a “historical accident”. However, due to the
kernel’s use of only 32 bits for device numbers, this accident does not
have any ill effect.

Bug: crashpad:30
Test: crashpad_util_test, crashpad_snapshot_test
Change-Id: Ic343454393d7399f598f9eba169a9e5f5630e601
Reviewed-on: https://chromium-review.googlesource.com/733863
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Mark Mentovai 2017-10-23 13:58:42 -04:00
parent 2f4516f938
commit aff8d906b6

View File

@ -14,9 +14,9 @@
#include "util/linux/memory_map.h"
#include <linux/kdev_t.h>
#include <stdio.h>
#include <string.h>
#include <sys/sysmacros.h>
#include "base/files/file_path.h"
#include "base/logging.h"
@ -147,16 +147,25 @@ ParseResult ParseMapsLine(DelimitedFileReader* maps_file_reader,
return ParseResult::kError;
}
int major, minor;
if (maps_file_reader->GetDelim(' ', &field) !=
uint32_t major;
if (maps_file_reader->GetDelim(':', &field) !=
DelimitedFileReader::Result::kSuccess ||
(field.pop_back(), field.size() != 5) ||
!HexStringToNumber(field.substr(0, 2), &major) ||
!HexStringToNumber(field.substr(3, 2), &minor)) {
(field.pop_back(), field.size()) < 2 ||
!HexStringToNumber(field, &major)) {
LOG(ERROR) << "format error";
return ParseResult::kError;
}
mapping.device = MKDEV(major, minor);
uint32_t minor;
if (maps_file_reader->GetDelim(' ', &field) !=
DelimitedFileReader::Result::kSuccess ||
(field.pop_back(), field.size()) < 2 ||
!HexStringToNumber(field, &minor)) {
LOG(ERROR) << "format error";
return ParseResult::kError;
}
mapping.device = makedev(major, minor);
if (maps_file_reader->GetDelim(' ', &field) !=
DelimitedFileReader::Result::kSuccess ||