Commit b577efe4 authored by Julian Lettner's avatar Julian Lettner
Browse files

[ASan] Do not misrepresent high value address dereferences as null dereferences

Dereferences with addresses above the 48-bit hardware addressable range
produce "invalid instruction" (instead of "invalid access") hardware
exceptions (there is no hardware address decoding logic for those bits),
and the address provided by this exception is the address of the
instruction (not the faulting address).  The kernel maps the "invalid
instruction" to SEGV, but fails to provide the real fault address.

Because of this ASan lies and says that those cases are null
dereferences.  This downgrades the severity of a found bug in terms of
security.  In the ASan signal handler, we can not provide the real
faulting address, but at least we can try not to lie.

rdar://50366151

Reviewed By: vitalybuka

Differential Revision: https://reviews.llvm.org/D68676

llvm-svn: 374265
parent d6e9e99c
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -48,7 +48,8 @@ struct ErrorDeadlySignal : ErrorBase {
      scariness.Scare(10, "stack-overflow");
    } else if (!signal.is_memory_access) {
      scariness.Scare(10, "signal");
    } else if (signal.addr < GetPageSizeCached()) {
    } else if (signal.is_true_faulting_addr &&
               signal.addr < GetPageSizeCached()) {
      scariness.Scare(10, "null-deref");
    } else if (signal.addr == signal.pc) {
      scariness.Scare(60, "wild-jump");
+8 −1
Original line number Diff line number Diff line
@@ -881,6 +881,11 @@ struct SignalContext {
  bool is_memory_access;
  enum WriteFlag { UNKNOWN, READ, WRITE } write_flag;

  // In some cases the kernel cannot provide the true faulting address; `addr`
  // will be zero then.  This field allows to distinguish between these cases
  // and dereferences of null.
  bool is_true_faulting_addr;

  // VS2013 doesn't implement unrestricted unions, so we need a trivial default
  // constructor
  SignalContext() = default;
@@ -893,7 +898,8 @@ struct SignalContext {
        context(context),
        addr(GetAddress()),
        is_memory_access(IsMemoryAccess()),
        write_flag(GetWriteFlag()) {
        write_flag(GetWriteFlag()),
        is_true_faulting_addr(IsTrueFaultingAddress()) {
    InitPcSpBp();
  }

@@ -914,6 +920,7 @@ struct SignalContext {
  uptr GetAddress() const;
  WriteFlag GetWriteFlag() const;
  bool IsMemoryAccess() const;
  bool IsTrueFaultingAddress() const;
};

void InitializePlatformEarly();
+6 −0
Original line number Diff line number Diff line
@@ -1849,6 +1849,12 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
#endif
}

bool SignalContext::IsTrueFaultingAddress() const {
  auto si = static_cast<const siginfo_t *>(siginfo);
  // SIGSEGV signals without a true fault address have si_code set to 128.
  return si->si_signo == SIGSEGV && si->si_code != 128;
}

void SignalContext::DumpAllRegisters(void *context) {
  // FIXME: Implement this.
}
+6 −0
Original line number Diff line number Diff line
@@ -754,6 +754,12 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
#endif
}

bool SignalContext::IsTrueFaultingAddress() const {
  auto si = static_cast<const siginfo_t *>(siginfo);
  // "Real" SIGSEGV codes (e.g., SEGV_MAPERR, SEGV_MAPERR) are non-zero.
  return si->si_signo == SIGSEGV && si->si_code != 0;
}

static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
  ucontext_t *ucontext = (ucontext_t*)context;
# if defined(__aarch64__)
+13 −4
Original line number Diff line number Diff line
@@ -191,6 +191,11 @@ static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
  SanitizerCommonDecorator d;
  Printf("%s", d.Warning());
  const char *description = sig.Describe();
  if (sig.is_memory_access && !sig.is_true_faulting_addr)
    Report("ERROR: %s: %s on unknown address (pc %p bp %p sp %p T%d)\n",
           SanitizerToolName, description, (void *)sig.pc, (void *)sig.bp,
           (void *)sig.sp, tid);
  else
    Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n",
           SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc,
           (void *)sig.bp, (void *)sig.sp, tid);
@@ -203,7 +208,11 @@ static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
            ? "WRITE"
            : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN");
    Report("The signal is caused by a %s memory access.\n", access_type);
    if (sig.addr < GetPageSizeCached())
    if (!sig.is_true_faulting_addr)
      Report("Hint: this fault was caused by a dereference of a high value "
             "address (see registers below).  Dissassemble the provided pc "
             "to learn which register value was used.\n");
    else if (sig.addr < GetPageSizeCached())
      Report("Hint: address points to the zero page.\n");
  }
  MaybeReportNonExecRegion(sig.pc);
Loading