-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
525 lines (525 loc) · 65.5 KB
/
index.html
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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="author" content="PUBLIC" />
<title>Below MI - IBM i for Hackers</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="https://neat.joeldare.com/neat.css" />
</head>
<body>
<header id="title-block-header">
<h1 class="title">Below MI - IBM i for Hackers</h1>
<p class="author">PUBLIC</p>
<p class="date">Version: 2024-07-22 (c50475a30a93d32b78c65ffa3b8cbd68d52f6187)</p>
</header>
<p>IBM i is a vertically integrated system, where the vendor has full control over both hardware and software from the operating system to the CPU. The tight control over the platform allowed IBM to create a completely abstract development environment, so applications can become truly independent from the underlying hardware, implementing full backwards compatibility. This is achieved through the Machine Interface (MI): an intermediate translation layer between program logic and native code. MI instructions work on “objects” instead of raw (virtual) memory. This object-oriented design and its supporting safety mechanisms implemented in the translator (the component responsble for generating native from intermetiate representations of programs) pose uniqe challenges in the exploitation of memory safety issues on IBM i.</p>
<p>In this writeup we provide a summary of technical information crucial to evaulate the exploitability and impact of memory safety problems in IBM i programs. As administrators and developers of IBM i aren’t supposed to work “below MI level” this kind of information is not officially documented by the vendor. The information presented here is thus based on already published reverse engineering results<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a><a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>, and our own findings uncovered using IBM’s System Sertice Tools (SST) and the POWER-AS specific Processor <a href="https://github.com/silentsignal/PowerAS">extensions</a> we developed for the Ghidra reverse engineering framework.</p>
<p>Tests were performed on a physical POWER 9 system running IBM i V7R4. Programs were compiled by the default settings of the system in the ILE program model. C language source code are <a href="https://github.com/silentsignal/SAVF">provided separately</a>.</p>
<h2 id="the-power-isa">The POWER ISA</h2>
<p>Current IBM i platforms are built around IBM’s POWER CPU. POWER implements the PowerPC ISA (IBM is one of the founding members of the PowerPC Alliance), extended with vendor-specific instructions, related primarily to memory tagging - commonly referred to as POWER-AS (the name originating from the AS/400 era). The processors implement the 64-bit, big-endian specification.</p>
<p>While the CPU registers are 64-bits wide, IBM i makes use of 128-bit (thick) pointers. Because of this, word lengths are denoted as follows:</p>
<ul>
<li>QWORD: 128 bits (thick pointer size)</li>
<li>DWORD: 64 bits (register size)</li>
<li>WORD: 32 bits (instruction size (not considering VLE))</li>
<li>HWORD: 16 bits (half word)</li>
</ul>
<h2 id="security-levels">Security Levels</h2>
<p>IBM i’s operating system can run in multiple security modes. The QSECURITY System Value (system-wide setting) on IBM i defines the following Security Levels:</p>
<ul>
<li>10 - No Security</li>
<li>20 - Password Security</li>
<li>30 - Resource Security</li>
<li>40 - Operating System Security</li>
<li>50 - C2 Level Security</li>
</ul>
<p>This writeup focuses on Security Level 40 that is the minimum recommended level. Security Level 50 was introduced to meet NCSC’s Class C2 security criteria - it is not widely used, likely because incompatibilities it introduces with existing 3rd party software.</p>
<h2 id="single-level-storage">Single-Level Storage</h2>
<p>IBM i implements a storage model typical to the platform: Single-Level Storage (SLS) is a model where main storage (memory) and secondary storage (typically SSDs) are treated as a single 64-bit virtual address space.</p>
<p>Virtual addesses in the SLS consist of two parts: a 40-bit segment identifier, and a 24-bit offset inside the segment:</p>
<pre><code>Virtual Address: 0xb4d5391dff001122
Segment: 0xb4d5391dff
Offset: 0x001122</code></pre>
<p>The PowerPC architecture supports segment tables, that can be used by the operating system to contol the set of segments accessible by a particular process. However, on IBM i below Security Level 50 this translation mechanism is not in use - all virtual address of the SLS can be accessed by any process.<a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a> Compared to common architectures where separate virtual memory is created for individual processes, SLS increases the impact of memory safety violations and add new attack vectors to consider:</p>
<table>
<colgroup>
<col style="width: 10%" />
<col style="width: 65%" />
<col style="width: 23%" />
</colgroup>
<thead>
<tr class="header">
<th>Threat</th>
<th>Impact on per-process virtual memory</th>
<th>Impact on SLS</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Memory safety violations when parsing untrusted data</td>
<td>Access to the address space of the affected process. Use of OS facilities with the privileges of the affected process through arbitrary code execution.</td>
<td>Access to all user-space storage.</td>
</tr>
<tr class="even">
<td>Execution of untrusted code, no safety violations.</td>
<td>Use OS facilities with the privileges of the executing user through arbitrary code execution.</td>
<td>Use OS facilities with the privileges of the executing user through arbitrary code execution.</td>
</tr>
<tr class="odd">
<td>Execution of untrusted code, deliberately introducing safety violations.</td>
<td>Use OS facilities with the privileges of the executing user through arbitrary code execution.</td>
<td>Access to all user-space storage.</td>
</tr>
</tbody>
</table>
<p><a href="#TODO">Link to dynamic demonstration</a></p>
<p>Security of memory accesses is guaranteed by the translator via memory tagging and typed pointers as discussed in later sections.</p>
<p>Address translation involves enforcing page protection when accessing virtual addresses. A two-bit field (PP) in each Page Table Entry controls whether load or store operations can be performed on a particular page (no separate “execute” protection bit is present). System-state programs can bypass most of these checks<a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a>.</p>
<h2 id="program-serialization">Program Serialization</h2>
<h3 id="string-constants">String constants</h3>
<p>String constants are loaded based on R2. An array of string pointers is located at R2, the array contains 0x10 byte structures pointing to variable length, NULL terminated strings. A typical use of the string table is as follows (TYPES.C):</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode asm"><code class="sourceCode fasm"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true"></a>e9 <span class="dv">42</span> <span class="dv">00</span> <span class="dv">20</span> ld <span class="kw">r10</span>,<span class="bn">0x20</span>(r2) <span class="co">; R10 := string table address</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true"></a><span class="dv">61</span> 5e <span class="dv">00</span> <span class="dv">00</span> ori r30,<span class="kw">r10</span><span class="bn">,0x0 </span><span class="co">; R30 := R10 </span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true"></a>...</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true"></a><span class="dv">39</span> 5e <span class="dv">00</span> <span class="dv">10</span> addi <span class="kw">r10</span>,r30<span class="bn">,0x10 </span><span class="co">; R10 := first string pointer from the string table</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true"></a>...</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true"></a><span class="dv">60</span> <span class="dv">88</span> <span class="dv">00</span> <span class="dv">00</span> ori <span class="kw">r8</span>,r4<span class="bn">,0x0 </span><span class="co">; Thick pointer type</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true"></a><span class="dv">61</span> <span class="dv">49</span> <span class="dv">00</span> <span class="dv">00</span> ori <span class="kw">r9</span>,<span class="kw">r10</span><span class="bn">,0x0 </span><span class="co">; Thick pointer address <- R10</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true"></a>f9 <span class="dv">05</span> <span class="dv">00</span> <span class="dv">22</span> stq <span class="kw">r8</span>,<span class="bn">0x20</span>(r5) <span class="co">; Store thick pointer on callee stack</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true"></a>...</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true"></a>4b ff ff <span class="dv">11</span> <span class="kw">bl</span> printf </span></code></pre></div>
<h2 id="below-mi">Below MI</h2>
<h3 id="calling-conventions">Calling Convention(s)</h3>
<pre><code>Future work: Currently this section covers intra-program function calls but should be expanded to cover other call types (e.g. PGM->SRVPGM) and eventually to cover the wider ABI.</code></pre>
<p>To understand how IBM i programs operate at the native instruction (RISC) level, including how control-flow can be redirected in case when programs reach unexpected states, it’s crucial to understand how control is transfrerred between program functions.</p>
<p>According to PowerPC register usage conventions for AIX<a href="#fn5" class="footnote-ref" id="fnref5" role="doc-noteref"><sup>5</sup></a> (another POWER-based system by IBM) the stack pointer is stored in R1. On IBM i we will of course see something different.</p>
<p>A typical function prologue would look like this (main@CALLCONV):</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode asm"><code class="sourceCode fasm"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true"></a>fb <span class="dv">41</span> ff <span class="dv">30</span> <span class="bu">std</span> r26,-<span class="bn">0xd0</span>(r1) <span class="co">; Save registers ...</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true"></a>fb <span class="dv">61</span> ff <span class="dv">38</span> <span class="bu">std</span> r27,-<span class="bn">0xc8</span>(r1) <span class="co">; ... r26-r32 ...</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true"></a>fb <span class="dv">81</span> ff <span class="dv">43</span> stmd r28,-<span class="bn">0x30</span>(r1) <span class="co">; ... "above" R1</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true"></a>7c <span class="dv">08</span> <span class="dv">02</span> a6 mfspr r0,LR <span class="co">; ... Save link register in R0</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true"></a>f8 <span class="dv">01</span> <span class="dv">00</span> <span class="dv">28</span> <span class="bu">std</span> r0,<span class="bn">0x28</span>(r1) <span class="co">; Store linkage address in memory "below" R1</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true"></a>f8 <span class="dv">21</span> fe c1 stdu r1,-<span class="bn">0x140</span>(r1) <span class="co">; Save R1 in memory</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true"></a>f8 <span class="dv">41</span> <span class="dv">00</span> <span class="dv">20</span> <span class="bu">std</span> r2,<span class="bn">0x20</span>(r1) <span class="co">; Save r2 in memory</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true"></a>3c <span class="dv">00</span> <span class="dv">44</span> <span class="dv">13</span> lis r0<span class="bn">,0x4413 </span><span class="co">; </span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true"></a>f8 <span class="dv">01</span> <span class="dv">00</span> <span class="dv">08</span> <span class="bu">std</span> r0,<span class="bn">0x8</span>(r1) <span class="co">;</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true"></a><span class="dv">33</span> ff <span class="dv">00</span> <span class="dv">60</span> addic r31,r31<span class="bn">,0x60 </span><span class="co">; Grow R31 to higher</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true"></a>7c <span class="dv">20</span> <span class="dv">01</span> c8 txer<span class="bn"> 0x1,0x0,0x3 </span><span class="co">; The undocumented TXER instruction traps if the stack would overflow its segment.</span></span></code></pre></div>
<p>R1 is only used afterwards to restore the saved R2 values after function calls:</p>
<pre><code>4b ff fd d1 bl fflush
e8 41 00 20 ld r2,0x20(r1)</code></pre>
<p>We can observe more frequent use of R31 in the function body, suggesting this register being primarily used to access local variables. The incrementation of this register value also suggests that the stack grows in the positive direction. This is a simple loop (LOOPS.C):</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true"></a> <span class="cf">for</span> (<span class="dt">int</span> i=<span class="dv">0</span>; i<<span class="dv">100</span>; i+=<span class="dv">10</span>){</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true"></a> printf(<span class="st">"Outer loop: %d</span><span class="sc">\n</span><span class="st">"</span>,i);</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true"></a> inner(i);</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true"></a> }</span></code></pre></div>
<p>… and its corresponding RISC code:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode asm"><code class="sourceCode fasm"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true"></a><span class="bu">loop</span>:</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true"></a>... printf function <span class="bu">call</span> ...</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true"></a>e8 9f ff a2 lwa r4,-<span class="bn">0x60</span>(r31) <span class="co">; Load i as first register parameter (R4)</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true"></a><span class="dv">39</span> 1f ff b0 subi <span class="kw">r8</span>,r31<span class="bn">,0x50 </span><span class="co">; Callee stack...</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true"></a><span class="dv">61</span> <span class="dv">03</span> <span class="dv">00</span> <span class="dv">00</span> ori r3,<span class="kw">r8</span><span class="bn">,0x0 </span><span class="co">; ... in R3</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true"></a>4b ff fe <span class="dv">61</span> <span class="kw">bl</span> inner <span class="co">; Function call</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true"></a>e8 bf ff a2 lwa r5,-<span class="bn">0x60</span>(r31) <span class="co">; i in R5</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true"></a><span class="dv">39</span> <span class="dv">85</span> <span class="dv">00</span> 0a addi <span class="kw">r12</span>,r5,<span class="bn">0xa</span> <span class="co">; Increment i by 10 </span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true"></a>7d 8c <span class="dv">07</span> b4 extsw <span class="kw">r12</span>,<span class="kw">r12</span> <span class="co">; Sign extend the result</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true"></a><span class="dv">91</span> 9f ff a0 stw <span class="kw">r12</span>,-<span class="bn">0x60</span>(r31) <span class="co">; Save the new i value</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true"></a>e9 5f ff a2 lwa <span class="kw">r10</span>,-<span class="bn">0x60</span>(r31) <span class="co">; Load the new i value for comparison</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true"></a>2d 0a <span class="dv">00</span> <span class="dv">64</span> cmpwi <span class="kw">cr2</span>,<span class="kw">r10</span><span class="bn">,0x64 </span><span class="co">; Compare i to 100</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true"></a><span class="dv">41</span> d5 <span class="dv">80</span> <span class="dv">23</span> bgtla cr5,SUB_ffffffffffff8020</span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true"></a><span class="dv">41</span> <span class="dv">88</span> ff a0 blt <span class="kw">cr2</span>,<span class="bu">loop</span> <span class="co">; Loop branch</span></span></code></pre></div>
<p>We also can confirm that R31 is used as a stack pointer and the direction of stack growth by taking a look at how a functions return value is saved to a local variable:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true"></a><span class="dt">int</span> num;</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true"></a><span class="dt">int</span> res;</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true"></a><span class="co">// ...</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true"></a>res=myfunc(num);</span></code></pre></div>
<p>The compiled RISC code corresponding to the last line is this:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode asm"><code class="sourceCode fasm"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true"></a>4b ff fc e9 <span class="kw">bl</span> myfunc <span class="co">; Function call</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true"></a><span class="dv">60</span> <span class="dv">64</span> <span class="dv">00</span> <span class="dv">00</span> ori r4,r3<span class="bn">,0x0 </span><span class="co">; R3 is the return value, copy it to R4</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true"></a><span class="dv">90</span> 9f ff a4 stw r4,-<span class="bn">0x5c</span>(r31) <span class="co">; Store the WORD part of the result relative to R31</span></span></code></pre></div>
<p>As we can see, the integer store operation (<code>stw</code>) addresses memory based on R31 and uses a negative offset.</p>
<p>R31 is previously saved in function prologue using the undocumented <code>stmd</code> (likely “Store Multiple Doubleword”) instruction, and is restored in the function epilogue with the undocumented <code>lmd</code> (likely “Load Multiple Doubleword”) instruction. The following example instruction loads DWORD’s from memory to R26-R31:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode asm"><code class="sourceCode fasm"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true"></a>eb <span class="dv">41</span> ff <span class="dv">33</span> lmd r26,-<span class="bn">0x34</span>(r1) </span></code></pre></div>
<p>Compilers for RISC generally prefer parameter passing in registers, relying on the high register count of these platforms. Since typed pointers of IBM i don’t fit into registers, passing pointer arguments requires the use of a stack. The ILE C compiler uses a dedicated stack pointer, R3 to keep track of pointer arguments. R3 and R31 point to the same segment, so it’s fair to say that local variables and function parameters use the same stack, only there are two different stack pointers.</p>
<p>This is how a function call translated from ILE looks like at the callers side:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode asm"><code class="sourceCode fasm"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true"></a>subi <span class="kw">r10</span>,r31<span class="bn">,0x40 </span><span class="co">; Set parameter stack location</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true"></a>lq <span class="kw">r8</span>,r31,<span class="bn">0xff9</span> <span class="co">; Load thick pointer value from stack</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true"></a>stq <span class="kw">r8</span>,local_<span class="dv">60</span>(<span class="kw">r10</span>) <span class="co">; Store thick pointer on user stack</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true"></a>li r4<span class="bn">,0x4 </span><span class="co">; Const parameter passed in register (R4,...)</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true"></a>ori r3,<span class="kw">r10</span><span class="bn">,0x0 </span><span class="co">; Copy pointer to thick pointer stack to R3</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true"></a><span class="kw">bl</span> hexprint <span class="co">; hexprint(strPtr, 4); </span></span></code></pre></div>
<p>At the callee side the function prologue copies the R3 value to R29, and later pointer access is done via this latter register, while R3 is used as return value (for fitting types).</p>
<p>In the function epilogue saved registers are restored, then the Link Register is set to the saved caller address, so an appropriate branch instructions (e.g. <code>blrl</code>) can transfer control back to the caller:</p>
<pre><code>addi r1,r1,0x100
ld r0,0x28(r1) ; No tag check!
mtspr LR,r0
; ... Restoring register context ...
blrl </code></pre>
<p>Note, that the <code>ld</code> instruction used to load the caller address from memory doesn’t perform a tag check, so the segment pointed by r1 can be an attractive target to exploit memory corruptions. However, dynamic tests show that this segment is different from the ones assigned to standard variables/buffers (R31, R3, R29), so there is no starting point from which the critical data stored here can be reached (see Segment Boundary Checking).</p>
<h3 id="memory-safety">Memory Safety</h3>
<p>MI doesn’t provide memory safety. It is trivial to create an ILE C program that accesses memory outside of a character buffers bounds (OOB.C):</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true"></a><span class="pp">#include</span><span class="im"><stdio.h></span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true"></a></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true"></a><span class="dt">int</span> main(){</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true"></a> <span class="dt">char</span> buf[<span class="dv">4</span>];</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true"></a> <span class="dt">int</span> num;</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true"></a></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true"></a> scanf(<span class="st">"%x %s"</span>, &num, buf);</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true"></a></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true"></a> <span class="co">// Out-of-bounds read in both directions</span></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true"></a> <span class="cf">for</span> (<span class="dt">int</span> i=-<span class="dv">2</span>; i < <span class="dv">8</span>; i++){</span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true"></a> printf(<span class="st">" %02x "</span>, buf[i]);</span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true"></a> }</span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true"></a></span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true"></a> printf(<span class="st">"</span><span class="sc">\n</span><span class="st">%x</span><span class="sc">\n</span><span class="st">"</span>, num);</span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true"></a> </span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true"></a> <span class="cf">return</span> <span class="dv">0</span>;</span>
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true"></a>}</span></code></pre></div>
<p>A sample execution of the above program produces the following result:</p>
<pre><code>> 1337 ABCDE
40 40 c1 c2 c3 c4 c5 00 13 37
c5001337 </code></pre>
<p>The result clearly shows that both out-of-bounds read and write operations completed without errors (characters are EBCDIC encoded). It’s worth noting that the compiler doesn’t seem to perform variable reordering to mitigate out-of-bounds access.</p>
<p>Since there is a single instance of any objects in the SLS, parts of program objects (code, compiled-in data, etc.) will occur at the same virtual addresses (in the same segments) for each run. Program addresses change when a program is recompiled. When a user executes a program, segments specific to that particular process (Associated Space, e.g. for stacks and heaps) are associated at random addresses.</p>
<p>While spatial and temporal memory safety are not enforced, the Security Features to be discussed aim for enforcing control-flow integrity (CFI) with compile-time checks:</p>
<ul>
<li>Pointer tagging prevents dereferencing corrupted code pointers.</li>
<li>Type checking prevents branching to data pointers even if they aren’t corrupted.</li>
<li>Segment Boundary Checks limit the range of memory reachable by offsetting valid pointers through existing application logic. This feature:
<ul>
<li>enables the translator to protect critical data (e.g. return addresses) by separating them from standard variables</li>
<li>reduce the number of reusable variables (e.g. character buffers containing CL commands; code pointers to abusable functions)</li>
</ul></li>
</ul>
<h3 id="security-features">Security Features</h3>
<h4 id="pointer-tagging">Pointer Tagging</h4>
<p>Pointer tagging is used to guarantee the integrity of pointers on the system. Every aligned QWORD has an additional tag bit, that signals:</p>
<blockquote>
<p>“This pointer is trusted, as it was created by the system”</p>
</blockquote>
<p>Pointer tagging prevents setting pointers to arbitrary values through a write primitive obtained (possibly) by exploiting a memory corruption bug.</p>
<p>QWORDs can be tagged by first issuing a <code>settag</code> instruction. This instruction is unprivileged, and the only reason it can’t be issued at will is that users can’t normally write RISC code to the system. A subsequent <code>stq</code> instruction will store a QWORD value at a specified memory address from a pair of 64-bit registers. It’s important to note that tag bits are not stored as part of the pointer values, but separately from the primary storage, possibly encoded in the ECC value mainained by the memory controller.</p>
<p>The following snippet shows calling the <code>printf</code> function (“imported” from the standard library) and setting its first format string parameter:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode asm"><code class="sourceCode fasm"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true"></a>e9 <span class="dv">42</span> <span class="dv">00</span> <span class="dv">20</span> ld <span class="kw">r10</span>,<span class="bn">0x20</span>(r2) <span class="co">; Global string table address is loaded to R10</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true"></a><span class="dv">61</span> 5e <span class="dv">00</span> <span class="dv">00</span> ori r30,<span class="kw">r10</span><span class="bn">,0x0 </span><span class="co">; R30 := R10</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true"></a><span class="dv">39</span> 3e <span class="dv">00</span> <span class="dv">40</span> addi <span class="kw">r9</span>,r30<span class="bn">,0x40 </span><span class="co">; R9 points to the format string inside the string table</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true"></a><span class="dv">39</span> 1f ff b0 subi <span class="kw">r8</span>,r31<span class="bn">,0x50 </span><span class="co">; R8 points to a local variable</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true"></a><span class="dv">38</span> e0 <span class="dv">00</span> <span class="dv">80</span> li r7<span class="bn">,0x80 </span><span class="co">; Two instructions load the ...</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true"></a><span class="dv">78</span> e7 c1 c6 rldicr r7,r7<span class="bn">,0x38,0x7 </span><span class="co">; ... pointer type 0x8000000000000000 to R7</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true"></a>7c <span class="dv">01</span> <span class="dv">03</span> e6 settag <span class="co">; Next store instruction is tagged</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true"></a><span class="dv">60</span> e4 <span class="dv">00</span> <span class="dv">00</span> ori r4,r7<span class="bn">,0x0 </span><span class="co">; Copy typed pointer from R7, R9 to ...</span></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true"></a><span class="dv">61</span> <span class="dv">25</span> <span class="dv">00</span> <span class="dv">00</span> ori r5,<span class="kw">r9</span><span class="bn">,0x0 </span><span class="co">; ... consecutive registers R4||R5</span></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true"></a>f8 <span class="dv">88</span> <span class="dv">00</span> <span class="dv">22</span> stq r4,<span class="bn">0x20</span>(<span class="kw">r8</span>) <span class="co">; Store the tagged & typed pointer after R8</span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true"></a><span class="dv">61</span> <span class="dv">03</span> <span class="dv">00</span> <span class="dv">00</span> ori r3,<span class="kw">r8</span><span class="bn">,0x0 </span><span class="co">; Set the stack for pointer parameters before branch</span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true"></a>4b ff fe a9 <span class="kw">bl</span> printf <span class="co">; Call printf("<format string>")</span></span></code></pre></div>
<p>The LQ instruction used to load thick pointers in a single instruction will also set a bit in register XER based on the tag bit associated with the target QWORD. This bit is then checked with a TXER (“Trap on XER”) instruction emitted together with LQ by the translator. In case the pointer was written to without a previous <code>settag</code> (e.g. as a result of a buffer overflow) the tag gets erased, LQ will not set XER, and TXER will cause an exception, terminating the process on unsafe pointer dereference.</p>
<p>This is part of the source code of a simple program that works with function pointers (FPTRLOOP):</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true"></a><span class="dt">int</span> main(){</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true"></a> <span class="dt">void</span> (*myCmd)();</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true"></a></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true"></a> <span class="cf">for</span>(<span class="dt">int</span> i = <span class="dv">0</span>; i < <span class="dv">4</span>; i++){</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true"></a> <span class="cf">if</span> (i % <span class="dv">2</span> == <span class="dv">0</span>){</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true"></a> myCmd = func0;</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true"></a> }<span class="cf">else</span>{</span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true"></a> myCmd = func1;</span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true"></a> }</span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true"></a> myCmd();</span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true"></a> }</span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true"></a></span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true"></a> <span class="cf">return</span> <span class="bn">0x1337</span>;</span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true"></a>}</span></code></pre></div>
<p>This is the corresponding disassembly:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode asm"><code class="sourceCode fasm"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true"></a><span class="dv">40</span> <span class="dv">92</span> <span class="dv">00</span> <span class="dv">24</span> bne <span class="kw">cr4</span>,LAB_11dbd7ca25002174 <span class="co">;if(){} branch</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true"></a>e9 <span class="dv">42</span> <span class="dv">00</span> <span class="dv">28</span> ld <span class="kw">r10</span>,<span class="bn">0x28</span>(r2) <span class="co">;Store the first fptr from 0x28(R2) </span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true"></a> <span class="co">;See other branch for details!</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true"></a><span class="co">; ...SNIP ...</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true"></a>e9 <span class="dv">02</span> <span class="dv">00</span> <span class="dv">30</span> ld <span class="kw">r8</span>,<span class="bn">0x30</span>(r2) <span class="co">;R2 points to a global symbol table </span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true"></a> <span class="co">;This is the second function address at offset 0x30</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true"></a> <span class="co">;Note: untagged load, R2 points to a </span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true"></a> <span class="co">;"protected" segment</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true"></a><span class="dv">38</span> c0 <span class="dv">00</span> a1 li r6,<span class="bn">0xa1</span> <span class="co">;R6 -> Type identifier</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true"></a><span class="dv">78</span> c6 c1 c6 rldicr r6,r6<span class="bn">,0x38,0x7</span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true"></a>7c <span class="dv">01</span> <span class="dv">03</span> e6 settag</span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true"></a><span class="dv">60</span> c4 <span class="dv">00</span> <span class="dv">00</span> ori r4,r6<span class="bn">,0x0 </span><span class="co">;R4 := R6 (fptr type tag)</span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true"></a><span class="dv">61</span> <span class="dv">05</span> <span class="dv">00</span> <span class="dv">00</span> ori r5,<span class="kw">r8</span><span class="bn">,0x0 </span><span class="co">;R5 := R8 (fptr address)</span></span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true"></a>f8 9f ff d2 stq r4,-<span class="bn">0x30</span>(r31) <span class="co">;Store tagged function pointer </span></span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true"></a> <span class="co">;to stack variable</span></span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true"></a><span class="dv">38</span> 7f ff e0 subi r3,r31<span class="bn">,0x20 </span><span class="co">;Setup callee parameter stack pointer</span></span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true"></a>e9 <span class="dv">42</span> <span class="dv">00</span> <span class="dv">08</span> ld <span class="kw">r10</span>,<span class="bn">0x8</span>(r2)</span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true"></a>e1 1f ff d1 lq <span class="kw">r8</span>,-<span class="bn">0x30</span>(r31) <span class="co">;R8||R9 := Saved fptr</span></span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true"></a>7c <span class="dv">00</span> <span class="dv">05</span> <span class="dv">48</span> txer<span class="bn"> 0x0,0x0,0xa</span> <span class="co">;Check if previous load was tagged</span></span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true"></a><span class="dv">61</span> <span class="dv">26</span> <span class="dv">00</span> <span class="dv">00</span> ori r6,<span class="kw">r9</span><span class="bn">,0x0 </span><span class="co">;R6 := fptr address</span></span>
<span id="cb17-21"><a href="#cb17-21" aria-hidden="true"></a><span class="dv">61</span> <span class="dv">07</span> <span class="dv">00</span> <span class="dv">00</span> ori r7,<span class="kw">r8</span><span class="bn">,0x0 </span><span class="co">;R7 := fptr type</span></span>
<span id="cb17-22"><a href="#cb17-22" aria-hidden="true"></a>e9 <span class="dv">66</span> <span class="dv">00</span> <span class="dv">00</span> ld <span class="kw">r11</span>,<span class="bn">0x0</span>(r6) <span class="co">;R11 := Dereferenced function address</span></span>
<span id="cb17-23"><a href="#cb17-23" aria-hidden="true"></a>e8 ab <span class="dv">00</span> <span class="dv">20</span> ld r5,<span class="bn">0x20</span>(<span class="kw">r11</span>)</span>
<span id="cb17-24"><a href="#cb17-24" aria-hidden="true"></a>7d 2a <span class="dv">28</span> <span class="dv">00</span> cmpd <span class="kw">cr2</span>,<span class="kw">r10</span>,r5</span>
<span id="cb17-25"><a href="#cb17-25" aria-hidden="true"></a><span class="dv">40</span> 8a <span class="dv">00</span> 1c bne <span class="kw">cr2</span>,LAB_11dbd7ca250021d0</span>
<span id="cb17-26"><a href="#cb17-26" aria-hidden="true"></a>e8 8b <span class="dv">00</span> <span class="dv">08</span> ld r4,<span class="bn">0x8</span>(<span class="kw">r11</span>) <span class="co">;R11 is the head of the thick pointer</span></span>
<span id="cb17-27"><a href="#cb17-27" aria-hidden="true"></a> <span class="co">;R4 is the jump target</span></span>
<span id="cb17-28"><a href="#cb17-28" aria-hidden="true"></a>7c <span class="dv">89</span> <span class="dv">03</span> a6 mtspr CTR,r4</span>
<span id="cb17-29"><a href="#cb17-29" aria-hidden="true"></a>e8 4b <span class="dv">00</span> <span class="dv">00</span> ld r2,<span class="bn">0x0</span>(<span class="kw">r11</span>)</span>
<span id="cb17-30"><a href="#cb17-30" aria-hidden="true"></a>4e <span class="dv">80</span> <span class="dv">04</span> <span class="dv">21</span> bctrl <span class="co">;xxx Indirect Call xxx</span></span></code></pre></div>
<p>It is important to note that while dereference of “base” pointers (as in a pointers created by the system) is guarded by tags, pointer arithmethic is not - see Memory Safety!</p>
<p><a href="#TODO">Link to dynamic demonstration</a></p>
<h4 id="segment-boundary-checking">Segment Boundary Checking</h4>
<p>Segment Boundary Checking ensures that pointer arithmetic can only result in pointers within the original segment (even though flawed pointer arithmetic may have caused out-of-bounds access).</p>
<p>The following C function accepts a pointer to a character array, so it can be used to demonstrate pointer dereference (CALLPTR.C):</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true"></a><span class="dt">void</span> myprint(<span class="dt">char</span>* str, <span class="dt">int</span> n){</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true"></a> printf(<span class="st">"Here is part of your message:</span><span class="sc">\r\n</span><span class="st">"</span>);</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true"></a> <span class="cf">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i<n; i++){</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true"></a> putchar(str[i]);</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true"></a> }</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true"></a> printf(<span class="st">"</span><span class="sc">\r\n</span><span class="st">"</span>);</span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true"></a> fflush(stdout);</span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true"></a>}</span></code></pre></div>
<p>The <code>str[i]</code> expression looks like this at the level of RISC code:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode asm"><code class="sourceCode fasm"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true"></a>e5 1d <span class="dv">00</span> <span class="dv">21</span> ltptr <span class="kw">r8</span>,<span class="bn">0x2</span>(r29)<span class="bn">,0x2 </span><span class="co">; Load address from typed pointer to R8</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true"></a>7c e8 <span class="dv">62</span> <span class="dv">14</span> <span class="bu">add</span> r7,<span class="kw">r8</span>,<span class="kw">r12</span> <span class="co">; Add offset (R12) to address, result in R7 </span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true"></a>7f a7 <span class="dv">40</span> <span class="dv">88</span> td<span class="bn"> 0x1d,</span>r7,<span class="kw">r8</span> <span class="co">; Trap conditionally</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true"></a><span class="dv">88</span> c7 <span class="dv">00</span> <span class="dv">00</span> lbz r6,<span class="bn">0x0</span>(r7) <span class="co">; Load byte from R7</span></span></code></pre></div>
<p>Thanks to the <a href="https://www.devever.net/~hl/ppcas">work of Hugo Landau</a> we know that the <code>ltptr</code> instruction is partially documented in <a href="https://patents.google.com/patent/US20090198967A1/en">this patent</a>. According to this document <code>ltptr</code> loads NULL to the target register if the tag bit is not set.</p>
<p>Based on our dynamic tests the conditional trap (<code>td</code>) is required to check whether the resulting pointer is beyond a segment boundary (offset 0xffffff) to prevent moving pointers to valid segments other than their original. When passing a value in <code>n</code> that would result reading beyond page boundary, the program terminated with and exception. In the above example <code>td</code> compares the values of R7 (original pointer) and R8 (incremented pointer). According the public POWER ISA documentation the conditions of trap are these:</p>
<pre><code>a <- (RA)
b <- (RB)
if (a < b) & TO0 then TRAP
if (a > b) & TO1 then TRAP
if (a = b) & TO2 then TRAP
if (a <u b) & TO3 then TRAP
if (a >u b) & TO4 then TRAP</code></pre>
<p>In the above example the value of the 5-bit TO field is 0b11101. This means that <code>td</code> should always trap, but since under normal circumstances (low offset values) pointer dereference works as expected, there is either an OS-level trap handler, or some undocumented behavior involved in the execution of this instruction. Since handling a trap at every valid pointer load would likely have detrimental performance cost, <code>td</code> likely has undocumented behavior supporting segment boundary checks.</p>
<p>For reference we created statistics of the TD masks from the QZSRAAU program. As we can see, similar “impossible” configuration of the TO field is the rule instead of the exception in case of X-form <code>td</code> instructions:</p>
<pre><code>td_masks.py> Running...
TD Mask: 0b11100 - 44 instances found
TD Mask: 0b11101 - 4 instances found
td_masks.py> Finished!</code></pre>
<p>Note that the above check itself should not break normal programs, since according to our tests memory allocations fail when requested size is above 0xffefff. Tests were conducted using malloc (single allocation), and by allocating stack space (e.g. two 0x800000 byte buffers). The observation is also confirmed <a href="https://archive.midrange.com/rpg400-l/201310/msg00307.html">here</a>, noting that terraspace may be useful to expand this limit - this needs further research.</p>
<p>The leaked PPCAS documentation of the <code>td</code> instruction includes the following logic for the 0b11100 mask value:</p>
<pre><code>if ( a0:15 =/ b0:15 |
( a0:15 =/ 0 &
( ( a16:39 =/ b16:39) | (a < b) ) ) ) &
TO = 0b11100 & (tags active) then TRAP</code></pre>
<p>Checks on bits [0,39] of the input register values confirms our previously stated result. While the 0b11101 mask is not even documented in the internal documentation (dated to 1999.), it is reasonable to assume that the trap logic works similarly in this case too.</p>
<p>To confirm the working and significance of segment boundary checking the program S2DBG was created. The program includes the following almost trivial function:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true"></a><span class="dt">char</span>* increment(<span class="dt">char</span>* p, <span class="dt">long</span> <span class="dt">long</span> l){</span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true"></a> <span class="cf">return</span> p+l;</span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true"></a>}</span></code></pre></div>
<p>The program expects the user to replace (patch) the <code>td</code> instruction generated as part of the above function with a NOP instruction (this requires access to SST with high privileges, but this is beside the point of the demonstration, as it is not supposed to be an exploit). After the single <code>td</code> instruction was patched, S2DBG allows reading and writing arbitrary memory, including segments belonging to QSECOFR (page protections still apply though). This behavior also confirms the threat model outlined in the Single-Level Store section on modern IBM i versions.</p>
<p><a href="https://vimeo.com/976308689">Link to Demo</a></p>
<h4 id="typed-pointers">Typed Pointers</h4>
<p>Another security measure implemented by IBM i is associating type metadata to pointers.<a href="#fn6" class="footnote-ref" id="fnref6" role="doc-noteref"><sup>6</sup></a> Typed, or “thick” pointers are aligned QWORDs, consisting of two DWORDs each: the first DWORD identifies the type, while the second is the 64-bit virtual address in the SLS. Typed pointers are supported by memory tagging: changing the type portion would break the memory tag just as changing the address portion would.</p>
<p>Type checking becomes important when otherwise valid (tagged) pointers are to be used in the wrong context, e.g. treating a “data” pointer as a “code” pointer. ILE C supports “open pointers” (<code>void *</code>), so there is no language-level constraint that would prevent such misuse (as opposed to e.g. inline assembly). We know that no separate execution permissions exist at a page level, thus any readable address should be executable too, so page protection will not cover this scenario. The following sample program was created to gain a better understanding of this scenario (DEREF2.C):</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true"></a><span class="dt">void</span> derefFuncPtr(<span class="dt">void</span>* ptr){</span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true"></a> <span class="dt">char</span> *dummy=<span class="st">"xxxx"</span>;</span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true"></a> <span class="dt">void</span> (*fp)(<span class="dt">char</span>*) = ptr;</span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true"></a> fp(dummy); <span class="co">// Avoid dead code elimination</span></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true"></a>}</span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true"></a></span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true"></a><span class="dt">int</span> main(){</span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true"></a> <span class="dt">char</span> buf[<span class="dv">16</span>];</span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true"></a> scanf(<span class="st">"%s"</span>, buf);</span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true"></a> derefFuncPtr(derefChar);</span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true"></a> <span class="cf">return</span> <span class="bn">0x1337</span>;</span>
<span id="cb24-12"><a href="#cb24-12" aria-hidden="true"></a>}</span></code></pre></div>
<p>Here is the RISC code generated for the function pointer declaration in <code>derefFuncPtr</code>:</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode asm"><code class="sourceCode fasm"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true"></a>e1 1f ff b1 lq <span class="kw">r8</span>,-<span class="dv">50</span>(r31)<span class="bn">,0x01 </span><span class="co">; Pointer from stack in R8||R9</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true"></a> <span class="co">; Last four reserved bits are: 0b0001</span></span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true"></a>7c <span class="dv">00</span> <span class="dv">05</span> <span class="dv">48</span> txer<span class="bn"> 0x0,0x0,0xa</span> <span class="co">; Trap if not tagged (and type incorrect?)</span></span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true"></a><span class="dv">61</span> 2a <span class="dv">00</span> <span class="dv">00</span> ori <span class="kw">r10</span>,<span class="kw">r9</span><span class="bn">,0x0 </span><span class="co">; Function address -> R10</span></span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true"></a><span class="dv">61</span> 0c <span class="dv">00</span> <span class="dv">00</span> ori <span class="kw">r12</span>,<span class="kw">r8</span><span class="bn">,0x0 </span><span class="co">; Funcptr type -> R12</span></span>
<span id="cb25-6"><a href="#cb25-6" aria-hidden="true"></a><span class="dv">60</span> e3 <span class="dv">00</span> <span class="dv">00</span> ori r3,r7<span class="bn">,0x0 </span><span class="co">; Setting callee parameter stack </span></span>
<span id="cb25-7"><a href="#cb25-7" aria-hidden="true"></a>e9 6a <span class="dv">00</span> <span class="dv">00</span> ld <span class="kw">r11</span>,<span class="bn">0x0</span>(<span class="kw">r10</span>) <span class="co">; Dereference function address to R11</span></span>
<span id="cb25-8"><a href="#cb25-8" aria-hidden="true"></a>e8 ab <span class="dv">00</span> <span class="dv">20</span> ld r5,<span class="bn">0x20</span>(<span class="kw">r11</span>)</span>
<span id="cb25-9"><a href="#cb25-9" aria-hidden="true"></a>7d <span class="dv">26</span> <span class="dv">28</span> <span class="dv">00</span> cmpd <span class="kw">cr2</span>,r6,r5</span>
<span id="cb25-10"><a href="#cb25-10" aria-hidden="true"></a><span class="dv">40</span> 8a <span class="dv">00</span> 1c bne <span class="kw">cr2</span>,label_error</span>
<span id="cb25-11"><a href="#cb25-11" aria-hidden="true"></a>e8 8b <span class="dv">00</span> <span class="dv">08</span> ld r4,<span class="bn">0x8</span>(<span class="kw">r11</span>) <span class="co">; Another deref from R11 to R4</span></span>
<span id="cb25-12"><a href="#cb25-12" aria-hidden="true"></a>7c <span class="dv">89</span> <span class="dv">03</span> a6 mtspr CTR,r4 <span class="co">; Set program counter from R4</span></span>
<span id="cb25-13"><a href="#cb25-13" aria-hidden="true"></a>e8 4b <span class="dv">00</span> <span class="dv">00</span> ld r2,<span class="bn">0x0</span>(<span class="kw">r11</span>)</span>
<span id="cb25-14"><a href="#cb25-14" aria-hidden="true"></a>4e <span class="dv">80</span> <span class="dv">04</span> <span class="dv">21</span> bctrl <span class="co">; Branch to CTR</span></span></code></pre></div>
<p>Based on our tests in the above case (and similar ones) LQ not only traps if the loaded pointer was not tagged, but also if the mask encoded in the instruction (third operand in the above disassembly) doesn’t correspond to the type of the loaded thick pointer.</p>
<h5 id="identifying-type-tags-and-masks">Identifying Type Tags and Masks</h5>
<p>When we take a look at the disassebly of a regular program shipped with the OS, we see two other common masks - output of <code>lq_masks.py</code> on QZSRAAU:</p>
<pre><code>lq_masks.py> Running...
LQ Mask: 0x2 - 133 instances found
LQ Mask: 0xF - 75 instances found
lq_masks.py> Finished!</code></pre>
<p>Based on the disassembly of our example programs we could observe that pointer types are set using two instructions:</p>
<ul>
<li><code>li</code> (Load Immediate) is used to load a single byte to a register. This byte is the type identifier.</li>
<li><code>rldicr</code> (Rotate Left Doubleword Immediate then Clear Right) is used to move the type byte to MSB, filling the other part of the value with zeroes.</li>
</ul>
<p>When we look for <code>li</code>-<code>rldicr</code> sequences in the QZSRAAU program we can identify the following type bytes - output on <code>tag_bytes.py</code> on QZSRAAU:</p>
<pre><code>tag_bytes.py> Running...
Tag: 0x80 - 64 instances found
Tag: 0x00 - 1 instances found
Tag: 0x01 - 1 instances found
Tag: 0xA2 - 24 instances found
tag_bytes.py> Finished!</code></pre>
<p>Based on the above observations we theorize the following relations between LQ mask values and type identifiers:</p>
<table>
<thead>
<tr class="header">
<th>Type Byte</th>
<th>LQ Mask</th>
<th>Comment</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>0x80</td>
<td>0xF</td>
<td>Union of sample code and QSZRAAU results.</td>
</tr>
<tr class="even">
<td>0xA1</td>
<td>0x1</td>
<td>See function pointer examples!</td>
</tr>
<tr class="odd">
<td>0xA2</td>
<td>0x2</td>
<td>See QZSRAAU results vs. example code</td>
</tr>
</tbody>
</table>
<p>The above results are partially confirmed by the internal PPCAS documentation:</p>
<ul>
<li>The 42nd bit of XER is set if the the MSB of the loaded typed pointer equals to <code>0xA || LQ mask</code> (<code>||</code> denotes concatenation). In the above example, the subsequent <code>txer</code> instruction traps if the 42nd bit (32+XBI) of XER is 0.</li>
<li>The <code>DECODE</code> operation performed by <code>lq</code> on the most significant two bits of the loaded thick pointer always results in a non-zero value. The <code>DECODE</code> output AND-ed to the 0xF mask thus always results in non-zero, setting the 41st bit of XER. A subsequent <code>txer</code> instruction with XBI=9 can then check this bit.</li>
</ul>
<p><a href="#TODO">Link to dynamic demonstration</a></p>
<h3 id="evaluation">Evaluation</h3>
<h4 id="data-only-exploitation---out-of-context-call">Data-Only Exploitation - Out-of-Context Call</h4>
<p>The following code is part of a deliberately exploitable sample program that demonstrates the exploitability of (some, highly constrained) memory corruption bugs (CRACKMEX.C):</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true"></a><span class="dt">int</span> main(){</span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true"></a> <span class="dt">void</span> (*adminCmd)(<span class="dt">char</span>*);</span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true"></a> Command commands[<span class="dv">2</span>];</span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true"></a> <span class="dt">char</span> param[<span class="dv">256</span>];</span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true"></a> <span class="dt">int</span> cmd = <span class="dv">0</span>;</span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true"></a></span>
<span id="cb28-7"><a href="#cb28-7" aria-hidden="true"></a> commands[<span class="dv">1</span>].name=<span class="st">"lower"</span>;</span>
<span id="cb28-8"><a href="#cb28-8" aria-hidden="true"></a> commands[<span class="dv">1</span>].exec=lower;</span>
<span id="cb28-9"><a href="#cb28-9" aria-hidden="true"></a> commands[<span class="dv">0</span>].name=<span class="st">"upper"</span>;</span>
<span id="cb28-10"><a href="#cb28-10" aria-hidden="true"></a> commands[<span class="dv">0</span>].exec=upper;</span>
<span id="cb28-11"><a href="#cb28-11" aria-hidden="true"></a></span>
<span id="cb28-12"><a href="#cb28-12" aria-hidden="true"></a> adminCmd = my_system;</span>
<span id="cb28-13"><a href="#cb28-13" aria-hidden="true"></a></span>
<span id="cb28-14"><a href="#cb28-14" aria-hidden="true"></a> <span class="co">// ...</span></span>
<span id="cb28-15"><a href="#cb28-15" aria-hidden="true"></a></span>
<span id="cb28-16"><a href="#cb28-16" aria-hidden="true"></a> <span class="cf">while</span>(cmd != <span class="dv">99</span>){</span>
<span id="cb28-17"><a href="#cb28-17" aria-hidden="true"></a> menu();</span>
<span id="cb28-18"><a href="#cb28-18" aria-hidden="true"></a> scanf(<span class="st">"%d"</span>, &cmd);</span>
<span id="cb28-19"><a href="#cb28-19" aria-hidden="true"></a> <span class="cf">if</span> (cmd == <span class="dv">99</span>) <span class="cf">break</span>;</span>
<span id="cb28-20"><a href="#cb28-20" aria-hidden="true"></a></span>
<span id="cb28-21"><a href="#cb28-21" aria-hidden="true"></a> printf(<span class="st">"Parameter: "</span>);</span>
<span id="cb28-22"><a href="#cb28-22" aria-hidden="true"></a> fflush(stdout);</span>
<span id="cb28-23"><a href="#cb28-23" aria-hidden="true"></a></span>
<span id="cb28-24"><a href="#cb28-24" aria-hidden="true"></a> <span class="co">// ...</span></span>
<span id="cb28-25"><a href="#cb28-25" aria-hidden="true"></a></span>
<span id="cb28-26"><a href="#cb28-26" aria-hidden="true"></a> fgets(param, <span class="dv">256</span>, stdin);</span>
<span id="cb28-27"><a href="#cb28-27" aria-hidden="true"></a></span>
<span id="cb28-28"><a href="#cb28-28" aria-hidden="true"></a> <span class="co">// ...</span></span>
<span id="cb28-29"><a href="#cb28-29" aria-hidden="true"></a></span>
<span id="cb28-30"><a href="#cb28-30" aria-hidden="true"></a> Command *tmpCmd = &(commands[cmd]);</span>
<span id="cb28-31"><a href="#cb28-31" aria-hidden="true"></a> printf(<span class="st">"%llx %llx %llx %llx</span><span class="sc">\n</span><span class="st">"</span>, *tmpCmd);</span>
<span id="cb28-32"><a href="#cb28-32" aria-hidden="true"></a> printf(<span class="st">"Invoking %s(%s)</span><span class="sc">\n</span><span class="st">"</span>, tmpCmd->name, param);</span>
<span id="cb28-33"><a href="#cb28-33" aria-hidden="true"></a> tmpCmd->exec(param);</span>
<span id="cb28-34"><a href="#cb28-34" aria-hidden="true"></a></span>
<span id="cb28-35"><a href="#cb28-35" aria-hidden="true"></a> }</span>
<span id="cb28-36"><a href="#cb28-36" aria-hidden="true"></a> <span class="cf">return</span> <span class="bn">0x1337</span>;</span>
<span id="cb28-37"><a href="#cb28-37" aria-hidden="true"></a>}</span></code></pre></div>
<p>In this example <code>upper()</code> and <code>lower()</code> are harmless functions, while <code>my_system()</code> is a simple wrapper around the built-in <code>system()</code> function that provides some console output for debugging.</p>
<p>As we can see, the <code>commands</code> array of function pointers can be trivially under/overindexed. By providing the value -1 to <code>cmd</code> it’s possible to invoke the <code>adminCmd</code> pointer also residing on the stack, achieving command execution:</p>
<pre><code>0) UPPERCASE
1) lowercase
99) Exit
> -1
Parameter:
===> wrkobj qgpl/crackemex</code></pre>
<p><a href="https://vimeo.com/976340326">Link to demo</a></p>
<h1 id="footnotes-and-references">Footnotes and References</h1>
<pre><code>Thorough referencing is WIP!</code></pre>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>https://www.devever.net/~hl/ppcas<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p>https://svalgaard.leif.org/as400/<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3" role="doc-endnote"><p>See ‘Chapter 7 - Accessing Arbitrary Data in Memory’ in Leif SvalGaard’s MI Programming<a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4" role="doc-endnote"><p>Soltis - Inside the AS/400, p. 203., 215.<a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5" role="doc-endnote"><p>https://www.ibm.com/docs/en/aix/7.2?topic=overview-register-usage-conventions<a href="#fnref5" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn6" role="doc-endnote"><p>This may remind astute readers of capability based addressing, which was present in AS/400 until V1R3, but is no longer in use in user-state programs, since pointer capabilities couldn’t be revoked. <span class="citation" data-cites="soltis:1996:inside">[@soltis:1996:inside]</span><a href="#fnref6" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</body>
</html>