aboutsummaryrefslogtreecommitdiff
path: root/src/priv-cfi.adoc
blob: 082ceb76ae2549c1311064589406aa6baffc40c0 (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
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
[[priv-cfi]]
== Control-flow Integrity (CFI)

Control-flow Integrity (CFI) capabilities help defend against Return-Oriented
Programming (ROP) and Call/Jump-Oriented Programming (COP/JOP) style
control-flow subversion attacks. The Zicfiss and Zicfilp extensions provide
backward-edge and forward-edge control flow integrity respectively. Please see
the Control-flow Integrity chapter of the Unprivileged ISA specification for further
details on these CFI capabilities and the associated Unprivileged ISA.

[[priv-forward]]
=== Landing Pad (Zicfilp)

This section specifies the Privileged ISA for the Zicfilp extension.

[[FCIFIACT]]
==== Landing-Pad-Enabled (LPE) State

The term `xLPE` is used to determine if forward-edge CFI using landing pads
provided by the Zicfilp extension is enabled at a privilege mode.

When S-mode is implemented, it is determined as follows:

.`xLPE` determination when S-mode is implemented
[width=100%]
[%header, cols="^4,^12"]
|===
|Privilege Mode| xLPE
|  M           | `mseccfg.MLPE`
|  S or HS     | `menvcfg.LPE`
|  VS          | `henvcfg.LPE`
|  U or VU     | `senvcfg.LPE`
|===

When S-mode is not implemented, it is determined as follows:

.`xLPE` determination when S-mode is not implemented
[width=100%]
[%header, cols="^4,^12"]
|===
|Privilege Mode| xLPE
|  M           | `mseccfg.MLPE`
|  U           | `menvcfg.LPE`
|===

[NOTE]
====
The Zicfilp must be explicitly enabled for use at each privilege mode.

Programs compiled with the `LPAD` instruction continue to function correctly,
but without forward-edge CFI protection, when the Zicfilp extension is not
implemented or is not enabled.
====

<<<

[[ZICFILP_FORWARD_TRAPS]]
==== Preserving Expected Landing Pad State on Traps

A trap may need to be delivered to the same or to a higher privilege mode upon
completion of `JALR`/`C.JALR`/`C.JR`, but before the instruction at the target
of indirect call/jump was decoded, due to:

* Asynchronous interrupts.
* Synchronous exceptions with priority higher than that of a software-check
  exception with `__x__tval` set to "landing pad fault (code=2)" (See
  <<exception-priority>> of Privileged Specification).

The software-check exception caused by Zicfilp has higher priority than an
illegal-instruction exception but lower priority than instruction access-fault.

The software-check exception due to the instruction not being an `LPAD`
instruction when `ELP` is `LP_EXPECTED` or an software-check exception caused by
the `LPAD` instruction itself (See <<LP_INST>>) leads to a trap being delivered
to the same or to a higher privilege mode.

In such cases, the `ELP` prior to the trap, the previous `ELP`, must be
preserved by the trap delivery such that it can be restored on a return from the
trap. To store the previous `ELP` state on trap delivery to M-mode, an `MPELP`
bit is provided in the `mstatus` CSR. To store the previous `ELP` state on trap
delivery to S/HS-mode, an `SPELP` bit is provided in the `mstatus` CSR. The
`SPELP` bit in `mstatus` can be accessed through the `sstatus` CSR. To store
the previous `ELP` state on traps to VS-mode, a `SPELP` bit is defined in the
`vsstatus` (VS-modes version of `sstatus`). To store the previous `ELP` state on
transition to Debug Mode, a `pelp` bit is defined in the `dcsr` register.

When a trap is taken into privilege mode `x`, the `__x__PELP` is set to `ELP`
and `ELP` is set to `NO_LP_EXPECTED`.

An `MRET` or `SRET` instruction is used to return from a trap in M-mode or
S-mode, respectively.  When executing an `__x__RET` instruction, if `__x__PP`
holds the value `y`, then `ELP` is set to the value of `__x__PELP` if `__y__LPE`
is 1; otherwise, it is set to `NO_LP_EXPECTED`; `__x__PELP` is set to
`NO_LP_EXPECTED`.

Upon entry into Debug Mode, the `pelp` bit in `dcsr` is updated with the `ELP`
at the privilege level the hart was previously in, and the `ELP` is set to
`NO_LP_EXPECTED`. When a hart resumes from Debug Mode, if `dcsr.prv` holds the
value `y`, then `ELP` is set to the value of `pelp` if `__y__LPE` is 1;
otherwise, it is set to `NO_LP_EXPECTED`.

When the Smrnmi extension is implemented, a `MNPELP` field (bit 9)
is provided in the `mnstatus` CSR to hold the previous `ELP` state on a trap to
the RNMI handler. When a RNMI trap is delivered, the `MNPELP` is set to `ELP`
and `ELP` set to `NO_LP_EXPECTED`. Upon a `MNRET`, if the `mnstatus.MNPP` holds
the value `y`, then `ELP` is set to the value of `MNPELP` if `yLPE` is 1;
otherwise, it is set to `NO_LP_EXPECTED`.

[NOTE]
====
The trap handler in privilege mode `x` must save the `__x__PELP` bit and the
`x7` register before performing an indirect call/jump if `xLPE=1`. If the
privilege mode `x` can respond to interrupts and `xLPE=1`, then the trap handler
should also save these values before enabling interrupts.

The trap handler in privilege mode `x` must restore the saved `__x__PELP` bit
and the `x7` register before executing the `__x__RET` instruction to return from
a trap.
====

<<<

[[priv-backward]]
=== Shadow Stack (Zicfiss)

This section specifies the Privileged ISA for the Zicfiss extension.

==== Shadow Stack Pointer (`ssp`) CSR access control

Attempts to access the `ssp` CSR may result in either an illegal-instruction
exception or a virtual instruction exception, contingent upon the state of the
*__x__*`envcfg.SSE` fields. The conditions are specified as follows:

* If the privilege mode is less than M and `menvcfg.SSE` is 0, an
  illegal-instruction exception is raised.
* Otherwise, if in U-mode and `senvcfg.SSE` is 0, an illegal-instruction
  exception is raised.
* Otherwise, if in VS-mode and `henvcfg.SSE` is 0, a virtual instruction
  exception is raised.
* Otherwise, if in VU-mode and either `henvcfg.SSE` or `senvcfg.SSE` is 0,
  a virtual instruction exception is raised.
* Otherwise, the access is allowed.

==== Shadow-Stack-Enabled (SSE) State

The term `xSSE` is used to determine if backward-edge CFI using shadow stacks
provided by the Zicfiss extension is enabled at a privilege mode.

When S-mode is implemented, it is determined as follows:

.`xSSE` determination when S-mode is implemented
[width=100%]
[%header, cols="^4,^12"]
|===
|Privilege Mode| `xSSE`
|  M           | `0`
|  S or HS     | `menvcfg.SSE`
|  VS          | `henvcfg.SSE`
|  U or VU     | `senvcfg.SSE`
|===

When S-mode is not implemented, then `xSSE` is 0 at both M and U privilege modes.

[NOTE]
====
Activating Zicfiss in U-mode must be done explicitly per process. Not activating
Zicfiss at U-mode for a process when that application is not compiled with
Zicfiss allows it to invoke shared libraries that may contain Zicfiss
instructions. The Zicfiss instructions in the shared library revert to their
Zimop/Zcmop-defined behavior in this case.

When Zicfiss is enabled in S-mode it is benign to use an operating system that is
not compiled with Zicfiss instructions. Such an operating system that does
not use backward-edge CFI for S-mode execution may still activate Zicfiss for
U-mode applications.

When programs that use Zicfiss instructions are installed on a processor that
supports the Zicfiss extension but the extension is not enabled at the privilege
mode where the program executes, the program continues to function correctly but
without backward-edge CFI protection as the Zicfiss instructions will revert to
their Zimop/Zcmop-defined behavior.

When programs that use Zicfiss instructions are installed on a processor that
does not support the Zicfiss extension but supports the Zimop and Zcmop
extensions, the programs continues to function correctly but without
backward-edge CFI protection as the Zicfiss instructions will revert to their
Zimop/Zcmop-defined behavior.

On processors that do not support Zimop/Zcmop extensions, all Zimop/Zcmop code
points including those used for Zicfiss instructions may cause an
illegal-instruction exception. Execution of programs that use these instructions
on such machines is not supported.

Activating Zicfiss in M-mode is currently not supported. Additionally, when
S-mode is not implemented, activation in U-mode is also not supported. These
functionalities may be introduced in a future standard extension.
====

NOTE: Changes to `xSSE` take effect immediately; address-translation caches
need not be synchronized with SFENCE.VMA, HFENCE.GVMA, or HFENCE.VVMA
instructions.


[[SSMP]]
==== Shadow Stack Memory Protection

To protect shadow stack memory, the memory is associated with a new page type –
the Shadow Stack (SS) page – in the single-stage and VS-stage page tables. The
encoding `R=0`, `W=1`, and `X=0`, is defined to represent an SS page. When
`menvcfg.SSE=0`, this encoding remains reserved. Similarly, when `V=1` and
`henvcfg.SSE=0`, this encoding remains reserved at `VS` and `VU` levels.

If `satp.MODE` (or `vsatp.MODE` when `V=1`) is set to `Bare` and the effective
privilege mode is below M, shadow stack memory accesses are prohibited, and
shadow stack instructions will raise a store/AMO access-fault exception. When
the effective privilege mode is M, any memory access by an `SSAMOSWAP.W/D`
instruction will result in a store/AMO access-fault exception.

Memory mapped as an SS page cannot be written to by instructions other than
`SSAMOSWAP.W/D`, `SSPUSH`, and `C.SSPUSH`. Attempts will raise a store/AMO
access-fault exception. Implicit accesses, including instruction fetches to an SS
page, are not permitted. Such accesses will raise an access-fault exception
appropriate to the access type. However, the shadow stack is readable by all
instructions that only load from memory.

[NOTE]
====
Stores to shadow stack pages by instructions other than `SSAMOSWAP`, `SSPUSH`,
and `C.SSPUSH` will trigger a store/AMO access-fault exception, not a store/AMO
page-fault exception, signaling a fatal error. A store/AMO page-fault suggests
that the operating system could address and rectify the fault, which is not
feasible in this scenario. Hence, the page fault handler must decode the opcode
of the faulting instruction to discern whether the fault was caused by a
non-shadow-stack instruction writing to an SS page (a fatal condition) or by a
shadow stack instruction to a non-resident page (a recoverable condition). The
performance-critical nature of operating system page fault handlers necessitates
triggering an access-fault instead of a page fault, allowing for a
straightforward distinction between fatal conditions and recoverable faults.

Operating systems must ensure that no writable, non-shadow-stack alias virtual
address mappings exist for the physical memory backing the shadow stack.
Furthermore, in systems where an address-misaligned exception supersedes the
access-fault exception, handlers emulating misaligned stores must be designed to
cause an access-fault exception when the store is directed to a shadow stack
page.

All instructions that perform load operations are allowed to read from the
shadow stack. This feature facilitates debugging and performance profiling by
allowing examination of the link register values backed up in the shadow stack.
====

[NOTE]
====
As of the drafting of this specification, instruction fetches are the sole type
of implicit access subjected to single- or VS-stage address translation.
====

If a shadow stack (SS) instruction raises an access-fault, page-fault, or
guest-page-fault exception that is supposed to indicate the original instruction
type (load or store/AMO), then the reported exception cause is respectively a
store/AMO access fault (code 7), a store/AMO page fault (code 15), or a
store/AMO guest-page fault (code 23). For shadow stack instructions, the
reported instruction type is always as though it were a store or AMO, even for
instructions `SSPOPCHK` and `C.SSPOPCHK` that only read from memory and do not
write to it.

[NOTE]
====
When Zicfiss is implemented, the existing "store/AMO" exceptions can be thought
of as "store/AMO/SS" exceptions, indicating that the trapping instruction is
either a store, an AMO, or a shadow stack instruction.
====

[NOTE]
====
The H (hypervisor) extension specifies that when a guest-page fault is caused by
an implicit memory access of VS-stage address translation, the reported
exception is either a load or store/AMO guest-page fault based not on the
original instruction type but rather on whether the memory access attempted for
VS-stage translation was a read or a write of memory. VS-stage address
translation can thus cause a shadow stack instruction to raise a load
guest-page-fault exception.
====

Shadow stack instructions are restricted to accessing shadow stack
(`pte.xwr=010b`) pages. Should a shadow stack instruction access a page that is
not designated as a shadow stack page and is not marked as read-only
(`pte.xwr=001`), a store/AMO access-fault exception will be invoked. Conversely,
if the page being accessed by a shadow stack instruction is a read-only page, a
store/AMO page-fault exception will be triggered.


[NOTE]
====
Shadow stack loads and stores will trigger a store/AMO page-fault if the
accessed page is read-only, to support copy-on-write (COW) of a shadow stack
page. If the page has been marked read-only for COW tracking, the page fault
handler responds by creating a copy of the page and updates the `pte.xwr` to
`010b`, thereby designating each copy as a shadow stack page. Conversely, if
the access targets a genuinely read-only page, the fault being reported as a
store/AMO page-fault signals to the operating system that the fault is fatal
and non-recoverable. Reporting the fault as a store/AMO page-fault, even for
`SSPOPCHK` initiated memory access, aids in the determination of fatality; if
these were reported as load page-faults, access to a truly read-only page
might be mistakenly treated as a recoverable fault, leading to the faulting
instruction being retried indefinitely. The PTE does not provide a read-only
shadow stack encoding.

Attempts by shadow stack instructions to access pages marked as read-write,
read-write-execute, read-execute, or execute-only result in a store/AMO
access-fault exception, similarly indicating a fatal condition.

Shadow stacks should be bounded at each end by guard pages to prevent accidental
underflows or overflows from one shadow stack into another. Conventionally, a
guard page for a stack is a page that is not accessible by the process that owns
the stack.
====

<<<

If the virtual address in `ssp` is not `XLEN` aligned, then the `SSPUSH`/
`C.SSPUSH`/`SSPOPCHK`/`C.SSPOPCHK` instructions cause a store/AMO access-fault
exception.

[NOTE]
====
Misaligned accesses to shadow stack are not required and enforcing alignment is
more secure to detect errors in the program. An access-fault exception is raised
instead of address-misaligned exception in such cases to indicate fatality and
that the instruction must not be emulated by a trap handler.
====

Correct execution of shadow stack instructions that access memory requires the
the accessed memory to be idempotent. If the memory referenced by 
`SSPUSH`/`C.SSPUSH`/`SSPOPCHK`/`C.SSPOPCHK`/`SSAMOSWAP.W/D` instructions is not
idempotent, then the instructions cause a store/AMO access-fault exception. 

[NOTE]
====
The `SSPOPCHK` instruction performs a load followed by a check of the loaded
data value with the link register as source. If the check against the link
register faults, and the instruction is restarted by the trap handler, then the
instruction will perform a load again. If the memory from which the load is
performed is non-idempotent, then the second load may cause unexpected side
effects. Shadow stack instructions that access the shadow stack require the
memory referenced by `ssp` to be idempotent to avoid such concerns. Locating
shadow stacks in non-idempotent memory, such as non-idempotent device memory,
is not an expected usage, and requiring memory referenced to be idempotent
does not pose a significant restriction.
====

The `U` and `SUM` bit enforcement is performed normally for shadow stack
instruction initiated memory accesses. The state of the `MXR` bit does not
affect read access to a shadow stack page as the shadow stack page is always
readable by all instructions that load from memory.

The G-stage address translation and protections remain unaffected by the Zicfiss
extension. The `xwr == 010b` encoding in the G-stage PTE remains reserved. When
G-stage page tables are active, the shadow stack instructions that access memory
require the G-stage page table to have read-write permission for the accessed
memory; else a store/AMO guest-page fault exception is raised.

[NOTE]
====
A future extension may define a shadow stack encoding in the G-stage page table
to support use cases such as a hypervisor enforcing shadow stack protections for
its guests.
====

Svpbmt and Svnapot extensions are supported for shadow stack pages.

The PMA checks are extended to require memory referenced by shadow stack
instructions to be idempotent. The PMP checks are extended to require read-write
permission for memory accessed by shadow stack instructions. If the PMP does not
provide read-write permissions or if the accessed memory is not idempotent then
a store/AMO access-fault exception is raised.

The `SSAMOSWAP.W/D` instructions require the PMA of the accessed memory range to
provide AMOSwap level support.