mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
mac: Tolerate the new flavor of weird cl_kernels modules on 10.14
OpenCL modules that appeared as “cl_kernels” since 10.7 now show up in 10.14 as ad-hoc signed modules at /private/var/db/CVMS/cvmsCodeSignObjXXXXXXXXXXXXXXXX (16 random characters). The modules are unlinked from the filesystem once loaded. Bug: crashpad:243 Change-Id: I00fdd1311d4e6cd4c9224ef54ac990ac1afb849c Reviewed-on: https://chromium-review.googlesource.com/1142027 Reviewed-by: Robert Sesek <rsesek@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
fb0f7ca8d7
commit
03abd1bb34
@ -15,6 +15,7 @@
|
||||
#include "snapshot/mac/mach_o_image_segment_reader.h"
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
@ -35,6 +36,37 @@ std::string SizeLimitedCString(const char* c_string, size_t max_length) {
|
||||
|
||||
} // namespace
|
||||
|
||||
bool IsMalformedCLKernelsModule(uint32_t mach_o_file_type,
|
||||
const std::string& module_name,
|
||||
bool* has_timestamp) {
|
||||
if (mach_o_file_type != MH_BUNDLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (module_name == "cl_kernels") {
|
||||
if (MacOSXMinorVersion() >= 10) {
|
||||
if (has_timestamp) {
|
||||
*has_timestamp = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char kCvmsObjectPathPrefix[] =
|
||||
"/private/var/db/CVMS/cvmsCodeSignObj";
|
||||
if (module_name.compare(
|
||||
0, strlen(kCvmsObjectPathPrefix), kCvmsObjectPathPrefix) == 0 &&
|
||||
MacOSXMinorVersion() >= 14) {
|
||||
if (has_timestamp) {
|
||||
*has_timestamp = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
MachOImageSegmentReader::MachOImageSegmentReader()
|
||||
: segment_command_(),
|
||||
sections_(),
|
||||
@ -121,21 +153,13 @@ bool MachOImageSegmentReader::Initialize(ProcessReaderMac* process_reader,
|
||||
load_command_info.c_str());
|
||||
|
||||
// cl_kernels modules (for OpenCL) aren’t ld output, and they’re formatted
|
||||
// incorrectly on OS X 10.10 and later. They have a single __TEXT segment,
|
||||
// but one of the sections within it claims to belong to the __LD segment.
|
||||
// This mismatch shouldn’t happen. This errant section also has the
|
||||
// S_ATTR_DEBUG flag set, which shouldn’t happen unless all of the other
|
||||
// sections in the segment also have this bit set (they don’t). These odd
|
||||
// sections are reminiscent of unwind information stored in MH_OBJECT
|
||||
// images, although cl_kernels images claim to be MH_BUNDLE. Because at
|
||||
// least one cl_kernels module will commonly be found in a process, and
|
||||
// sometimes more will be, tolerate this quirk.
|
||||
// incorrectly on OS X 10.10 and later. Because at least one cl_kernels
|
||||
// module will commonly be found in a process, and sometimes more will be,
|
||||
// tolerate this quirk.
|
||||
//
|
||||
// https://openradar.appspot.com/20239912
|
||||
if (section_segment_name != segment_name &&
|
||||
!(file_type == MH_BUNDLE &&
|
||||
module_name == "cl_kernels" &&
|
||||
MacOSXMinorVersion() >= 10 &&
|
||||
!(IsMalformedCLKernelsModule(file_type, module_name, nullptr) &&
|
||||
segment_name == SEG_TEXT &&
|
||||
section_segment_name == "__LD" &&
|
||||
section_name == "__compact_unwind" &&
|
||||
|
@ -29,6 +29,41 @@
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief Determines whether a module appears to be a malformed OpenCL
|
||||
//! `cl_kernels` module based on its name and Mach-O file type.
|
||||
//!
|
||||
//! `cl_kernels` modules require special handling because they’re malformed on
|
||||
//! OS X 10.10 and later. A `cl_kernels` module always has Mach-O type
|
||||
//! `MH_BUNDLE` and is named `"cl_kernels"` until macOS 10.14, and
|
||||
//! `"/private/var/db/CVMS/cvmsCodeSignObj"` plus 16 random characters on macOS
|
||||
//! 10.14.
|
||||
//!
|
||||
//! Malformed `cl_kernels` modules have a single `__TEXT` segment, but one of
|
||||
//! the sections within it claims to belong to the `__LD` segment. This mismatch
|
||||
//! shouldn’t happen. This errant section also has the `S_ATTR_DEBUG` flag set,
|
||||
//! which shouldn’t happen unless all of the other sections in the segment also
|
||||
//! have this bit set (they don’t). These odd sections are reminiscent of unwind
|
||||
//! information stored in `MH_OBJECT` images, although `cl_kernels` images claim
|
||||
//! to be `MH_BUNDLE`.
|
||||
//!
|
||||
//! This function is exposed for testing purposes only.
|
||||
//!
|
||||
//! \param[in] mach_o_file_type The Mach-O type of the module being examined.
|
||||
//! \param[in] module_name The pathname that `dyld` reported having loaded the
|
||||
//! module from.
|
||||
//! \param[out] has_timestamp Optional, may be `nullptr`. If provided, and the
|
||||
//! module is a maformed `cl_kernels` module, this will be set to `true` if
|
||||
//! the module was loaded from the filesystem (as is the case when loaded
|
||||
//! from the CVMS directory) and is expected to have a timestamp, and
|
||||
//! `false` otherwise. Note that even when loaded from the filesystem, these
|
||||
//! modules are unlinked from the filesystem after loading.
|
||||
//!
|
||||
//! \return `true` if the module appears to be a malformed `cl_kernels` module
|
||||
//! based on the provided information, `false` otherwise.
|
||||
bool IsMalformedCLKernelsModule(uint32_t mach_o_file_type,
|
||||
const std::string& module_name,
|
||||
bool* has_timestamp);
|
||||
|
||||
//! \brief A reader for `LC_SEGMENT` or `LC_SEGMENT_64` load commands in Mach-O
|
||||
//! images mapped into another process.
|
||||
//!
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "build/build_config.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "snapshot/mac/mach_o_image_reader.h"
|
||||
#include "snapshot/mac/mach_o_image_segment_reader.h"
|
||||
#include "test/errors.h"
|
||||
#include "test/mac/dyld.h"
|
||||
#include "test/mac/mach_errors.h"
|
||||
@ -663,14 +664,20 @@ TEST(ProcessReaderMac, SelfModules) {
|
||||
modules[index].reader->Address(),
|
||||
FromPointerCast<mach_vm_address_t>(_dyld_get_image_header(index)));
|
||||
|
||||
bool expect_timestamp;
|
||||
if (index == 0) {
|
||||
// dyld didn’t load the main executable, so it couldn’t record its
|
||||
// timestamp, and it is reported as 0.
|
||||
EXPECT_EQ(modules[index].timestamp, 0);
|
||||
} else if (modules[index].reader->FileType() == MH_BUNDLE &&
|
||||
modules[index].name == "cl_kernels") {
|
||||
// cl_kernels doesn’t exist as a file.
|
||||
EXPECT_EQ(modules[index].timestamp, 0);
|
||||
} else if (IsMalformedCLKernelsModule(modules[index].reader->FileType(),
|
||||
modules[index].name,
|
||||
&expect_timestamp)) {
|
||||
// cl_kernels doesn’t exist as a file, but may still have a timestamp.
|
||||
if (!expect_timestamp) {
|
||||
EXPECT_EQ(modules[index].timestamp, 0);
|
||||
} else {
|
||||
EXPECT_NE(modules[index].timestamp, 0);
|
||||
}
|
||||
found_cl_kernels = true;
|
||||
} else {
|
||||
// Hope that the module didn’t change on disk.
|
||||
@ -747,14 +754,20 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
|
||||
ASSERT_TRUE(modules[index].reader);
|
||||
EXPECT_EQ(modules[index].reader->Address(), expect_address);
|
||||
|
||||
bool expect_timestamp;
|
||||
if (index == 0 || index == modules.size() - 1) {
|
||||
// dyld didn’t load the main executable or itself, so it couldn’t record
|
||||
// these timestamps, and they are reported as 0.
|
||||
EXPECT_EQ(modules[index].timestamp, 0);
|
||||
} else if (modules[index].reader->FileType() == MH_BUNDLE &&
|
||||
modules[index].name == "cl_kernels") {
|
||||
// cl_kernels doesn’t exist as a file.
|
||||
EXPECT_EQ(modules[index].timestamp, 0);
|
||||
} else if (IsMalformedCLKernelsModule(modules[index].reader->FileType(),
|
||||
modules[index].name,
|
||||
&expect_timestamp)) {
|
||||
// cl_kernels doesn’t exist as a file, but may still have a timestamp.
|
||||
if (!expect_timestamp) {
|
||||
EXPECT_EQ(modules[index].timestamp, 0);
|
||||
} else {
|
||||
EXPECT_NE(modules[index].timestamp, 0);
|
||||
}
|
||||
found_cl_kernels = true;
|
||||
} else {
|
||||
// Hope that the module didn’t change on disk.
|
||||
|
Loading…
x
Reference in New Issue
Block a user