aboutsummaryrefslogtreecommitdiff
blob: 0a648a9c2e6ce379b0b868187643ddb405b95e62 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd">
<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/proj/en/hardened/hardened-debugging.xml,v 1.1 2010/11/25 20:25:59 zorry Exp $ -->

<guide link="/proj/en/hardened/hardenedfaq.xml" lang="en">
<title>Gentoo Hardened debugging</title>
<author title="Author">
  <mail link="klondike"/>
</author>
<author title="Contributor">
  <!-- Via bugs #341889 and 265693 -->
  Hugo Mildenberger
</author>

<abstract>
In this document we study the ways to do proper binary debugging when using a
hardened kernel and toolcahin with PaX/Grsec, PIE and SSP.
</abstract>

<!-- The content of this document is licensed under the CC-BY-SA license -->
<!-- See http://creativecommons.org/licenses/by-sa/2.5 -->
<license/>

<version>2</version>
<date>2012-04-28</date>

<chapter>
<title>Solving the '??' issue.</title>
<section>
<body>
<p>
When debugging you'll probably have found that <c>GDB</c> may not show the
addresses showing instead a stream of lines with <e>'??'</e> where the symbol
should be. This can be caused by two different things.
</p>

<p>
The first cause is that your <c>GDB</c> version is too old and is unable to
realize that the addresses are relative. This should be fixed in the current
stable versions of <c>GDB</c> so you should try to upgrade it. Other workaround
is applying solution 3.
</p>

<p>
The second reason is that your hardened kernel may be hidding the mappings. This
is a known problem and <uri
link="http://forums.grsecurity.net/viewtopic.php?f=1&amp;t=2467" >has been
fixed upstream</uri> so it will be fixed on further releases of
<c>hardened-sources</c>. Anyway, until the fix reaches the tree and is
stabilized, you can apply any of the solutions.
</p>

</body>
</section>

<section>
<title>Solution 1: Disabling RANDMMAP on the binary</title>
<body>

<p>
One solution is disabling the RANDMMAP feature with <c>paxctl</c> for that
particular binary. Doing this will make Grsec disable the mapping protection for
that binary as it makes no sense protecting it then. This means a more secure
environment but also getting away from the way the binary would be executed on
the real environment.
</p>

<pre caption="Disabling RANDMMAP with paxctl.">
# <i>paxctl -r binary</i>
</pre>

</body>
</section>

<section>
<title>Solution 2: Disabling the option to hide mappings</title>
<body>

<p>
Other fix is disabling the option that hides the addresses on the PaX protected
executables to avoid attacks based on that information. This option may make
the things easier for an attacker until it is enabled again although also means
that the environment will be the most similar possible to the real execution
environment.
</p>

<pre caption="Disabling the mapping hiding.">
Address Space Protection ---&gt;
 [ ] Remove addresses from /proc/&lt;pid&gt;/[smaps|maps|stat]
</pre>

</body>
</section>

<section>
<title>Solution 3: Linking a non PIE binary</title>
<body>

<p>
A last solution is disabling the last pie linking stage while compiling using
<c>-nopie</c>. All previous compilation can still use <c>-fPIE</c> as normal
(which is also the default with the hardened compiler) so that your executable
is as close as possible to the real thing as long as the final link must create
a regular executable.
<br />
Try adding <c>-nopie</c> to LDFLAGS if you're building with emerge.
</p>

</body>
</section>
</chapter>

<chapter>
<title>Using breakpoints</title>
<section>
<body>

<p>
You may find that PaX may prevent <c>GDB</c> from setting software breakpoints,
depending on how the kernel is configured. This includes the breakpoint at main
which you need to get started. There are two workarounds with different
effects and constraints to to solve this.
</p>

</body>
</section>

<section>
<title>Solution 1: Removing the RANDEXEC and MPROTECT flags</title>
<body>

<p>
The first solution is making PaX disable the RANDEXEC and MPROTECT features
for the binary to be debugged. To do this you have to set with <c>paxctl</c> the
<c>m</c> and <c>x</c> flags on the executable. The <c>x</c> flag is set by
default, so it should suffice to do:
</p>

<pre caption="Disabling MPROTECT">
# <i>/sbin/paxctl -m binary</i>
</pre>

<p>
After that <c>GDB</c> should be able to add software breakpoints on the binary,
if it still can't try disabling the SEGMEXEC and PAGEEXEC features (flags
<c>s</c> and <c>p</c> respectively).
</p>

<pre caption="Disabling SEGMEXEC and PAGEEXEC">
# <i>/sbin/paxctl -ps binary</i>
</pre>

<p>
Below we'll expose what's happening on a lower level when you add a software
breakpoint, and why PaX disallows this. You need to know a bit about how
processors work in order to understand it. This is not needed to solve your
problem so feel free to ignore it.
</p>

<p>
When the debugger adds a soft breakpoint it changes the instruction on the
executable memory image so it is a breakpoint instruction (on x86 and amd64
they are the <c>bp</c> and <c>bu</c> instructions). This instruction halts the
processor and gives the control back to the debugger and has the advantage
that it can be set in an unlimited number of points on the program. As PaX
disallows writes in executable memory for security reasons it is impossible for
the debugger to modify the code and add the breakpoint.
</p>

</body>
</section>

<section>
<title>Solution 2: Using hardware breakpoints</title>
<body>

<p>
Another solution is using hardware breakpoints, they don't require any changes
on PaX behavior, but they are usually limited (for example to a maximum of 4 on
x86 and amd64 including address watchpoints) and also have the problem that they
require the program to be already running in order to be added (although there
is some WIP to fix this in <c>GDB</c>).
</p>

<p>
To use them just use the <c>hbreak</c> instead of the <c>break</c> command.
</p>

<p>
Below we'll expose what's happening on a lower level when you add a hardware
breakpoint. You need to know a bit about how processors work in order to
understand it. This is not needed to solve your problem so feel free to ignore
it.
</p>

<p>
When the debugger adds a hardware breakpoint it changes some of the
processor registers (on x86 and amd64 they are the Dr registers) so the
processor halts when a certain address is accessed (either for reading, writing
or execution). As a result this implies that no data has to be written in
memory solving the soft breakpoints problem, but also limits the number of
available breakpoints.
</p>

</body>
</section>
</chapter>

<chapter>
<title>Restoring the file after debugging</title>
<section>
<body>

<p>
After debugging you may want to restore the system to its normal state, if you
used <c>paxctl</c> you can reset the flags to default using the <c>-z</c> flag.
Since the -z flags will zero all the flags also want to keep trampoline
emulation disabled. This is done with the <c>-e</c> flag.
</p>

<pre caption="Reseting the flags back to its defaults. Keep  trampoline emulation disabled">
# <i>paxctl -ze binary</i>
</pre>

</body>
</section>
</chapter>
</guide>