Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Add parser for Android tombstone files #568

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ install:
test-requirements:
python3 -m pip install --upgrade -r test-requirements.txt

generate-proto-parsers:
# Generate python parsers for protobuf files
PROTO_DIR="src/mvt/android/parsers/proto/"; \
PROTO_FILES=$$(find $(PROTO_DIR) -iname "*.proto"); \
protoc -I$(PROTO_DIR) --python_betterproto_out=$(PROTO_DIR) $$PROTO_FILES

clean:
rm -rf $(PWD)/build $(PWD)/dist $(PWD)/src/mvt.egg-info

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ dependencies = [
"cryptography >=42.0.5",
"pyyaml >=6.0",
"pyahocorasick >= 2.0.0",
"betterproto >=1.2.0",
]
requires-python = ">= 3.8"

Expand Down
13 changes: 13 additions & 0 deletions src/mvt/android/artifacts/tombstone_crashes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2023 The MVT Authors.
# Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/


from .artifact import AndroidArtifact


class TombstoneCrashArtifact(AndroidArtifact):
def parse(self, content: bytes) -> None:
"""
Parse Android tombstone crash files."""
59 changes: 59 additions & 0 deletions src/mvt/android/modules/bugreport/tombstones.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2023 The MVT Authors.
# Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/

import logging
from typing import Optional

from mvt.android.artifacts.tombstone_crashes import TombstoneCrashArtifact
from .base import BugReportModule


class Tombstones(TombstoneCrashArtifact, BugReportModule):
"""This module extracts records from battery daily updates."""

slug = "tombstones"

def __init__(
self,
file_path: Optional[str] = None,
target_path: Optional[str] = None,
results_path: Optional[str] = None,
module_options: Optional[dict] = None,
log: logging.Logger = logging.getLogger(__name__),
results: Optional[list] = None,
) -> None:
super().__init__(
file_path=file_path,
target_path=target_path,
results_path=results_path,
module_options=module_options,
log=log,
results=results,
)

def run(self) -> None:
tombstone_files = self._get_files_by_pattern("*/tombstone_*")
if not tombstone_files:
self.log.error(
"Unable to find any tombstone files. "
"Did you provide a valid bugreport archive?"
)
return

for tombstone_file in tombstone_files:
if tombstone_file.endswith("*.pb"):
self.log.info("Skipping protobuf tombstone file: %s", tombstone_file)
continue

print(tombstone_file)
tombstone_data = self._get_file_content(tombstone_file)
tombstone = self.parse_tombstone(tombstone_data)
print(tombstone)
break

# self.log.info(
# "Extracted a total of %d database connection pool records",
# len(self.results),
# )
Empty file.
195 changes: 195 additions & 0 deletions src/mvt/android/parsers/proto/tombstone.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
// tombstone.proto file from Android source
// Src: https://android.googlesource.com/platform/system/core/+/refs/heads/main/debuggerd/proto/tombstone.proto
//
// Protobuf definition for Android tombstones.
//
// An app can get hold of these for any `REASON_CRASH_NATIVE` instance of
// `android.app.ApplicationExitInfo`.
//
// https://developer.android.com/reference/android/app/ApplicationExitInfo#getTraceInputStream()
//
syntax = "proto3";
option java_package = "com.android.server.os";
option java_outer_classname = "TombstoneProtos";
// NOTE TO OEMS:
// If you add custom fields to this proto, do not use numbers in the reserved range.
message CrashDetail {
bytes name = 1;
bytes data = 2;
reserved 3 to 999;
}
message StackHistoryBufferEntry {
BacktraceFrame addr = 1;
uint64 fp = 2;
uint64 tag = 3;
reserved 4 to 999;
}
message StackHistoryBuffer {
uint64 tid = 1;
repeated StackHistoryBufferEntry entries = 2;
reserved 3 to 999;
}
message Tombstone {
Architecture arch = 1;
Architecture guest_arch = 24;
string build_fingerprint = 2;
string revision = 3;
string timestamp = 4;
uint32 pid = 5;
uint32 tid = 6;
uint32 uid = 7;
string selinux_label = 8;
repeated string command_line = 9;
// Process uptime in seconds.
uint32 process_uptime = 20;
Signal signal_info = 10;
string abort_message = 14;
repeated CrashDetail crash_details = 21;
repeated Cause causes = 15;
map<uint32, Thread> threads = 16;
map<uint32, Thread> guest_threads = 25;
repeated MemoryMapping memory_mappings = 17;
repeated LogBuffer log_buffers = 18;
repeated FD open_fds = 19;
uint32 page_size = 22;
bool has_been_16kb_mode = 23;
StackHistoryBuffer stack_history_buffer = 26;
reserved 27 to 999;
}
enum Architecture {
ARM32 = 0;
ARM64 = 1;
X86 = 2;
X86_64 = 3;
RISCV64 = 4;
NONE = 5;
reserved 6 to 999;
}
message Signal {
int32 number = 1;
string name = 2;
int32 code = 3;
string code_name = 4;
bool has_sender = 5;
int32 sender_uid = 6;
int32 sender_pid = 7;
bool has_fault_address = 8;
uint64 fault_address = 9;
// Note, may or may not contain the dump of the actual memory contents. Currently, on arm64, we
// only include metadata, and not the contents.
MemoryDump fault_adjacent_metadata = 10;
reserved 11 to 999;
}
message HeapObject {
uint64 address = 1;
uint64 size = 2;
uint64 allocation_tid = 3;
repeated BacktraceFrame allocation_backtrace = 4;
uint64 deallocation_tid = 5;
repeated BacktraceFrame deallocation_backtrace = 6;
}
message MemoryError {
enum Tool {
GWP_ASAN = 0;
SCUDO = 1;
reserved 2 to 999;
}
Tool tool = 1;
enum Type {
UNKNOWN = 0;
USE_AFTER_FREE = 1;
DOUBLE_FREE = 2;
INVALID_FREE = 3;
BUFFER_OVERFLOW = 4;
BUFFER_UNDERFLOW = 5;
reserved 6 to 999;
}
Type type = 2;
oneof location {
HeapObject heap = 3;
}
reserved 4 to 999;
}
message Cause {
string human_readable = 1;
oneof details {
MemoryError memory_error = 2;
}
reserved 3 to 999;
}
message Register {
string name = 1;
uint64 u64 = 2;
reserved 3 to 999;
}
message Thread {
int32 id = 1;
string name = 2;
repeated Register registers = 3;
repeated string backtrace_note = 7;
repeated string unreadable_elf_files = 9;
repeated BacktraceFrame current_backtrace = 4;
repeated MemoryDump memory_dump = 5;
int64 tagged_addr_ctrl = 6;
int64 pac_enabled_keys = 8;
reserved 10 to 999;
}
message BacktraceFrame {
uint64 rel_pc = 1;
uint64 pc = 2;
uint64 sp = 3;
string function_name = 4;
uint64 function_offset = 5;
string file_name = 6;
uint64 file_map_offset = 7;
string build_id = 8;
reserved 9 to 999;
}
message ArmMTEMetadata {
// One memory tag per granule (e.g. every 16 bytes) of regular memory.
bytes memory_tags = 1;
reserved 2 to 999;
}
message MemoryDump {
string register_name = 1;
string mapping_name = 2;
uint64 begin_address = 3;
bytes memory = 4;
oneof metadata {
ArmMTEMetadata arm_mte_metadata = 6;
}
reserved 5, 7 to 999;
}
message MemoryMapping {
uint64 begin_address = 1;
uint64 end_address = 2;
uint64 offset = 3;
bool read = 4;
bool write = 5;
bool execute = 6;
string mapping_name = 7;
string build_id = 8;
uint64 load_bias = 9;
reserved 10 to 999;
}
message FD {
int32 fd = 1;
string path = 2;
string owner = 3;
uint64 tag = 4;
reserved 5 to 999;
}
message LogBuffer {
string name = 1;
repeated LogMessage logs = 2;
reserved 3 to 999;
}
message LogMessage {
string timestamp = 1;
uint32 pid = 2;
uint32 tid = 3;
uint32 priority = 4;
string tag = 5;
string message = 6;
reserved 7 to 999;
}
Loading
Loading