Skip to content

Commit

Permalink
Improved: Info on how the 'swap' space is used in docs.
Browse files Browse the repository at this point in the history
  • Loading branch information
Sewer56 committed May 6, 2024
1 parent 4ff730d commit 1a86982
Showing 1 changed file with 62 additions and 12 deletions.
74 changes: 62 additions & 12 deletions docs/dev/design/common.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ If calling convention conversion is needed, the layout looks like this:
- Wrapper
```

#### Example
#### Example (When Atomically Overwriteable)

!!! info "Using ARM64 [Assembly Hook](./assembly-hooks/overview.md) as an example."

Expand All @@ -105,26 +105,72 @@ add x1, x1
mov x0, x2
```

The memory would look like this when hook is enabled.
Since the size of the swap space is less than 16 bytes (assuming 4 byte instructions),
the memory would look like this when the hook is enabled:

```asm
swap: ; Currently Applied (Hook)
mov x0, x1
add x0, x2
b back_to_code
add x1, x1
mov x0, x2
b back_to_code ; 12 bytes total
```

#### Example (Not Atomically Overwriteable)

Now, let's consider an example where the swap space is larger than the amount
of bytes that can be atomically written (over 16 bytes, in this ARM64 case)

If the *'OriginalCode'* was:

```asm
mov x0, x1
add x0, x2
sub x0, x3
mul x0, x4
add x0, x5
```

And the *'HookCode'* was:

```asm
add x1, x1
mov x0, x2
sub x1, x3
mul x1, x4
add x1, x5
```

The memory would look like this when the hook is enabled:

```asm
swap: ; Currently Applied (Hook)
add x1, x1
mov x0, x2
sub x1, x3
mul x1, x4
add x1, x5
b back_to_code ; 24 bytes total
hook: ; HookCode
add x1, x1
mov x0, x2
sub x1, x3
mul x1, x4
add x1, x5
b back_to_code
original: ; OriginalCode
mov x0, x1
add x0, x2
sub x0, x3
mul x0, x4
add x0, x5
b back_to_code
```

(When `sizeof(swap)` is larger than biggest possible atomic write.)
Therefore, the `hook` and `original` code are stored separately. When the hook is being enabled/disabled the
`swap` space will contain a temporary branch to either the `hook` or `original` before being overwritten.
(To support atomic hook/unhook)

### Heap (Props) Layout

Expand Down Expand Up @@ -257,21 +303,25 @@ And inserting a jmp produces:
0x0: jmp disabled ; 2 bytes
```

It's possible that the CPU's Instruction Pointer was at `0x1`` at the time of the overwrite, making the
It's possible that the CPU's Instruction Pointer was at `0x1` at the time of the overwrite, making the
`mov ebp, esp` instruction invalid.

### What Happens in Practice

In practice, modern x86 CPUs (1990 onwards) from Intel, AMD and VIA prefetch instruction in batches
of 16 bytes. We place our stubs generated by the various hooks on 16-byte boundaries for this
!!! tip "In practice, modern x86 CPUs (1990 onwards) from Intel, AMD and VIA prefetch instruction in batches of 16 bytes."

And in the recent years, this has been increased to 32 bytes.

We place our stubs generated by the various hooks on 32-byte boundaries for this
(and optimisation) reasons.

So, by the time we change the code, the CPU has already prefetched the instructions we are atomically
overwriting.

In other words, it is simply not possible to perfectly time a write such that a thread at `0x1`
(`mov ebp, esp`) would read an invalid instruction, as that instruction was prefetched and is being
executed from local thread cache.
In other words, it is simply not possible to perfectly time a write such that a thread at
Instruction Pointer `0x1` (`mov ebp, esp`) [as in example above] would read an invalid instruction.

Because that instruction was prefetched and is being executed from local thread cache.

### What is Safe

Expand Down

0 comments on commit 1a86982

Please sign in to comment.