1// Copyright (c) 2014, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10//     * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14//     * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#include "client/linux/dump_writer_common/seccomp_unwinder.h"
31
32#include <string.h>
33
34#include "google_breakpad/common/minidump_format.h"
35#include "common/linux/linux_libc_support.h"
36
37namespace google_breakpad {
38
39void SeccompUnwinder::PopSeccompStackFrame(RawContextCPU* cpu,
40                                           const MDRawThread& thread,
41                                           uint8_t* stack_copy) {
42#if defined(__x86_64)
43  uint64_t bp = cpu->rbp;
44  uint64_t top = thread.stack.start_of_memory_range;
45  for (int i = 4; i--; ) {
46    if (bp < top ||
47        bp > thread.stack.start_of_memory_range +
48        thread.stack.memory.data_size - sizeof(bp) ||
49        bp & 1) {
50      break;
51    }
52    uint64_t old_top = top;
53    top = bp;
54    uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
55    my_memcpy(&bp, bp_addr, sizeof(bp));
56    if (bp == 0xDEADBEEFDEADBEEFull) {
57      struct {
58        uint64_t r15;
59        uint64_t r14;
60        uint64_t r13;
61        uint64_t r12;
62        uint64_t r11;
63        uint64_t r10;
64        uint64_t r9;
65        uint64_t r8;
66        uint64_t rdi;
67        uint64_t rsi;
68        uint64_t rdx;
69        uint64_t rcx;
70        uint64_t rbx;
71        uint64_t deadbeef;
72        uint64_t rbp;
73        uint64_t fakeret;
74        uint64_t ret;
75        /* char redzone[128]; */
76      } seccomp_stackframe;
77      if (top - offsetof(__typeof__(seccomp_stackframe), deadbeef) < old_top ||
78          top - offsetof(__typeof__(seccomp_stackframe), deadbeef) +
79          sizeof(seccomp_stackframe) >
80          thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
81        break;
82      }
83      my_memcpy(&seccomp_stackframe,
84                bp_addr - offsetof(__typeof__(seccomp_stackframe), deadbeef),
85                sizeof(seccomp_stackframe));
86      cpu->rbx = seccomp_stackframe.rbx;
87      cpu->rcx = seccomp_stackframe.rcx;
88      cpu->rdx = seccomp_stackframe.rdx;
89      cpu->rsi = seccomp_stackframe.rsi;
90      cpu->rdi = seccomp_stackframe.rdi;
91      cpu->rbp = seccomp_stackframe.rbp;
92      cpu->rsp = top + 4*sizeof(uint64_t) + 128;
93      cpu->r8  = seccomp_stackframe.r8;
94      cpu->r9  = seccomp_stackframe.r9;
95      cpu->r10 = seccomp_stackframe.r10;
96      cpu->r11 = seccomp_stackframe.r11;
97      cpu->r12 = seccomp_stackframe.r12;
98      cpu->r13 = seccomp_stackframe.r13;
99      cpu->r14 = seccomp_stackframe.r14;
100      cpu->r15 = seccomp_stackframe.r15;
101      cpu->rip = seccomp_stackframe.fakeret;
102      return;
103    }
104  }
105#elif defined(__i386__)
106  uint32_t bp = cpu->ebp;
107  uint32_t top = thread.stack.start_of_memory_range;
108  for (int i = 4; i--; ) {
109    if (bp < top ||
110        bp > thread.stack.start_of_memory_range +
111        thread.stack.memory.data_size - sizeof(bp) ||
112        bp & 1) {
113      break;
114    }
115    uint32_t old_top = top;
116    top = bp;
117    uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
118    my_memcpy(&bp, bp_addr, sizeof(bp));
119    if (bp == 0xDEADBEEFu) {
120      struct {
121        uint32_t edi;
122        uint32_t esi;
123        uint32_t edx;
124        uint32_t ecx;
125        uint32_t ebx;
126        uint32_t deadbeef;
127        uint32_t ebp;
128        uint32_t fakeret;
129        uint32_t ret;
130      } seccomp_stackframe;
131      if (top - offsetof(__typeof__(seccomp_stackframe), deadbeef) < old_top ||
132          top - offsetof(__typeof__(seccomp_stackframe), deadbeef) +
133          sizeof(seccomp_stackframe) >
134          thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
135        break;
136      }
137      my_memcpy(&seccomp_stackframe,
138                bp_addr - offsetof(__typeof__(seccomp_stackframe), deadbeef),
139                sizeof(seccomp_stackframe));
140      cpu->ebx = seccomp_stackframe.ebx;
141      cpu->ecx = seccomp_stackframe.ecx;
142      cpu->edx = seccomp_stackframe.edx;
143      cpu->esi = seccomp_stackframe.esi;
144      cpu->edi = seccomp_stackframe.edi;
145      cpu->ebp = seccomp_stackframe.ebp;
146      cpu->esp = top + 4*sizeof(void*);
147      cpu->eip = seccomp_stackframe.fakeret;
148      return;
149    }
150  }
151#endif
152}
153
154}  // namespace google_breakpad
155