mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Bug 1436845: Part 3 - Add support for ModuleSignatureInfo field in .extra file on Windows builds; r=ted
We want to send information about the organization whose cert was used to sign modules in our address space. Originally I had written this code to accumulate that info within Firefox, but I realized that a better option is to do this from the minidump analyzer: (1) This way does not affect browser performance; (2) This way allows us to properly gather cert info even from startup crashes. This functionality was reviewed for data collection via bug 1430857.
This commit is contained in:
parent
0540f81560
commit
bfbeb16e09
@ -26,6 +26,7 @@
|
||||
#if defined(XP_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
#include "mozilla/glue/WindowsDllServices.h"
|
||||
|
||||
#elif defined(XP_UNIX) || defined(XP_MACOSX)
|
||||
|
||||
@ -43,6 +44,12 @@
|
||||
|
||||
namespace CrashReporter {
|
||||
|
||||
#if defined(XP_WIN)
|
||||
|
||||
static mozilla::glue::BasicDllServices gDllServices;
|
||||
|
||||
#endif
|
||||
|
||||
using std::ios;
|
||||
using std::ios_base;
|
||||
using std::hex;
|
||||
@ -179,7 +186,7 @@ ConvertStackToJSON(const ProcessState& aProcessState,
|
||||
static int
|
||||
ConvertModulesToJSON(const ProcessState& aProcessState,
|
||||
OrderedModulesMap& aOrderedModules,
|
||||
Json::Value& aNode)
|
||||
Json::Value& aNode, Json::Value& aCertSubjects)
|
||||
{
|
||||
const CodeModules* modules = aProcessState.modules();
|
||||
|
||||
@ -217,6 +224,24 @@ ConvertModulesToJSON(const ProcessState& aProcessState,
|
||||
mainModuleIndex = moduleSequence;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
auto certSubject = gDllServices.GetBinaryOrgName(
|
||||
UTF8ToWide(module->code_file()).c_str());
|
||||
if (certSubject) {
|
||||
string strSubject(WideToUTF8(certSubject.get()));
|
||||
// Json::Value::operator[] creates and returns a null member if the key
|
||||
// does not exist.
|
||||
Json::Value& subjectNode = aCertSubjects[strSubject];
|
||||
if (!subjectNode) {
|
||||
// If the member is null, we want to convert that to an array.
|
||||
subjectNode = Json::Value(Json::arrayValue);
|
||||
}
|
||||
|
||||
// Now we're guaranteed that subjectNode is an array. Add the new entry.
|
||||
subjectNode.append(PathnameStripper::File(module->code_file()));
|
||||
}
|
||||
#endif
|
||||
|
||||
Json::Value moduleNode;
|
||||
moduleNode["filename"] = PathnameStripper::File(module->code_file());
|
||||
moduleNode["code_id"] = PathnameStripper::File(module->code_identifier());
|
||||
@ -236,8 +261,10 @@ ConvertModulesToJSON(const ProcessState& aProcessState,
|
||||
// crash, the module list and stack traces for every thread
|
||||
|
||||
static void
|
||||
ConvertProcessStateToJSON(const ProcessState& aProcessState, Json::Value& aRoot,
|
||||
const bool aFullStacks)
|
||||
ConvertProcessStateToJSON(const ProcessState& aProcessState,
|
||||
Json::Value& aStackTraces,
|
||||
const bool aFullStacks,
|
||||
Json::Value& aCertSubjects)
|
||||
{
|
||||
// We use this map to get the index of a module when listed by address
|
||||
OrderedModulesMap orderedModules;
|
||||
@ -266,17 +293,18 @@ ConvertProcessStateToJSON(const ProcessState& aProcessState, Json::Value& aRoot,
|
||||
}
|
||||
}
|
||||
|
||||
aRoot["crash_info"] = crashInfo;
|
||||
aStackTraces["crash_info"] = crashInfo;
|
||||
|
||||
// Modules
|
||||
Json::Value modules(Json::arrayValue);
|
||||
int mainModule = ConvertModulesToJSON(aProcessState, orderedModules, modules);
|
||||
int mainModule = ConvertModulesToJSON(aProcessState, orderedModules,
|
||||
modules, aCertSubjects);
|
||||
|
||||
if (mainModule != -1) {
|
||||
aRoot["main_module"] = mainModule;
|
||||
aStackTraces["main_module"] = mainModule;
|
||||
}
|
||||
|
||||
aRoot["modules"] = modules;
|
||||
aStackTraces["modules"] = modules;
|
||||
|
||||
// Threads
|
||||
Json::Value threads(Json::arrayValue);
|
||||
@ -303,14 +331,17 @@ ConvertProcessStateToJSON(const ProcessState& aProcessState, Json::Value& aRoot,
|
||||
}
|
||||
}
|
||||
|
||||
aRoot["threads"] = threads;
|
||||
aStackTraces["threads"] = threads;
|
||||
}
|
||||
|
||||
// Process the minidump file and append the JSON-formatted stack traces to
|
||||
// the node specified in |aRoot|
|
||||
|
||||
// the node specified in |aStackTraces|. We also populate |aCertSubjects| with
|
||||
// information about the certificates used to sign modules, when present and
|
||||
// supported by the underlying OS.
|
||||
static bool
|
||||
ProcessMinidump(Json::Value& aRoot, const string& aDumpFile, const bool aFullStacks) {
|
||||
ProcessMinidump(Json::Value& aStackTraces, Json::Value& aCertSubjects,
|
||||
const string& aDumpFile, const bool aFullStacks)
|
||||
{
|
||||
#if XP_WIN && HAVE_64BIT_BUILD
|
||||
MozStackFrameSymbolizer symbolizer;
|
||||
MinidumpProcessor minidumpProcessor(&symbolizer, false);
|
||||
@ -334,18 +365,19 @@ ProcessMinidump(Json::Value& aRoot, const string& aDumpFile, const bool aFullSta
|
||||
ProcessResult rv;
|
||||
ProcessState processState;
|
||||
rv = minidumpProcessor.Process(&dump, &processState);
|
||||
aRoot["status"] = ResultString(rv);
|
||||
aStackTraces["status"] = ResultString(rv);
|
||||
|
||||
ConvertProcessStateToJSON(processState, aRoot, aFullStacks);
|
||||
ConvertProcessStateToJSON(processState, aStackTraces, aFullStacks,
|
||||
aCertSubjects);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Update the extra data file by adding the StackTraces field holding the
|
||||
// JSON output of this program.
|
||||
|
||||
// Update the extra data file by adding the StackTraces and ModuleSignatureInfo
|
||||
// fields that contain the JSON outputs of this program.
|
||||
static bool
|
||||
UpdateExtraDataFile(const string &aDumpPath, const Json::Value& aRoot)
|
||||
UpdateExtraDataFile(const string &aDumpPath, const Json::Value& aStackTraces,
|
||||
const Json::Value& aCertSubjects)
|
||||
{
|
||||
string extraDataPath(aDumpPath);
|
||||
int dot = extraDataPath.rfind('.');
|
||||
@ -370,9 +402,14 @@ UpdateExtraDataFile(const string &aDumpPath, const Json::Value& aRoot)
|
||||
if (f.is_open()) {
|
||||
Json::FastWriter writer;
|
||||
|
||||
f << "StackTraces=" << writer.write(aRoot);
|
||||
f << "StackTraces=" << writer.write(aStackTraces);
|
||||
res = !f.fail();
|
||||
|
||||
if (!!aCertSubjects) {
|
||||
f << "ModuleSignatureInfo=" << writer.write(aCertSubjects);
|
||||
res &= !f.fail();
|
||||
}
|
||||
|
||||
f.close();
|
||||
}
|
||||
|
||||
@ -381,13 +418,14 @@ UpdateExtraDataFile(const string &aDumpPath, const Json::Value& aRoot)
|
||||
|
||||
bool
|
||||
GenerateStacks(const string& aDumpPath, const bool aFullStacks) {
|
||||
Json::Value root;
|
||||
Json::Value stackTraces;
|
||||
Json::Value certSubjects;
|
||||
|
||||
if (!ProcessMinidump(root, aDumpPath, aFullStacks)) {
|
||||
if (!ProcessMinidump(stackTraces, certSubjects, aDumpPath, aFullStacks)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return UpdateExtraDataFile(aDumpPath, root);
|
||||
return UpdateExtraDataFile(aDumpPath, stackTraces, certSubjects);
|
||||
}
|
||||
|
||||
} // namespace CrashReporter
|
||||
|
Loading…
Reference in New Issue
Block a user