Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f5e568e6 authored by Christopher Ferris's avatar Christopher Ferris
Browse files

Do not access device maps.

It's possible that a device map has memory controlled by a single entry
device driver. Thus, you can deadlock if a process is touching that
device memory and we try to unwind it and also touch that device memory.
Simply skip any attempts to step through, or get function names from
device memory maps.

Bug: 36130325

Test: Ran new unit tests, ran bionic unit tests, ran art ThreadStress.
Change-Id: Ibc62d7ec8106c619ee08968f05e04aea55d7cbfa
parent 435fc451
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -283,7 +283,7 @@ static void dump_stack_segment(
    if (BacktraceMap::IsValid(map) && !map.name.empty()) {
      line += "  " + map.name;
      uintptr_t offset = 0;
      std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset));
      std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset, &map));
      if (!func_name.empty()) {
        line += " (" + func_name;
        if (offset) {
+4 −2
Original line number Diff line number Diff line
@@ -104,8 +104,10 @@ public:
  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0;

  // Get the function name and offset into the function given the pc.
  // If the string is empty, then no valid function name was found.
  virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset);
  // If the string is empty, then no valid function name was found,
  // or the pc is not in any valid map.
  virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset,
                                      const backtrace_map_t* map = NULL);

  // Fill in the map data associated with the given pc.
  virtual void FillInMap(uintptr_t pc, backtrace_map_t* map);
+4 −0
Original line number Diff line number Diff line
@@ -33,6 +33,10 @@
#include <string>
#include <vector>

// Special flag to indicate a map is in /dev/. However, a map in
// /dev/ashmem/... does not set this flag.
static constexpr int PROT_DEVICE_MAP = 0x8000;

struct backtrace_map_t {
  uintptr_t start = 0;
  uintptr_t end = 0;
+10 −1
Original line number Diff line number Diff line
@@ -52,7 +52,16 @@ Backtrace::~Backtrace() {
  }
}

std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset, const backtrace_map_t* map) {
  backtrace_map_t map_value;
  if (map == nullptr) {
    FillInMap(pc, &map_value);
    map = &map_value;
  }
  // If no map is found, or this map is backed by a device, then return nothing.
  if (map->start == 0 || (map->flags & PROT_DEVICE_MAP)) {
    return "";
  }
  std::string func_name = GetFunctionNameRaw(pc, offset);
  return func_name;
}
+11 −1
Original line number Diff line number Diff line
@@ -127,7 +127,7 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucon
      if (num_ignore_frames == 0) {
        // GetFunctionName is an expensive call, only do it if we are
        // keeping the frame.
        frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
        frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);
        if (num_frames > 0) {
          // Set the stack size for the previous frame.
          backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
@@ -143,6 +143,16 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucon
        frames_.resize(0);
      }
    }
    // If the pc is in a device map, then don't try to step.
    if (frame->map.flags & PROT_DEVICE_MAP) {
      break;
    }
    // Verify the sp is not in a device map too.
    backtrace_map_t map;
    FillInMap(frame->sp, &map);
    if (map.flags & PROT_DEVICE_MAP) {
      break;
    }
    ret = unw_step (cursor.get());
  } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);

Loading