Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/chp1/about_the_team.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Listed alphabetically:
* [tshepang](https://github.com/tshepang)
* [U007D](https://github.com/U007D)
* [Vishal Lama](https://github.com/vishallama)
* [w3irdrobot](https://github.com/w3irdrobot)

<br>

Expand Down
2 changes: 1 addition & 1 deletion src/chp16_appendix/crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ In practice, most implementations encrypt a byte (8 bits) at a time because mode
By contrast, **block ciphers** need to break data up into fixed-size chunks.
For the popular Advanced Encryption Standard (AES)[^AES], a block must be 128 bits (16 bytes).

While both stream and block ciphers accomplish the same goal, stream ciphers tend have a smaller memory footprint and faster runtimes[^Perf].
While both stream and block ciphers accomplish the same goal, stream ciphers tend to have a smaller memory footprint and faster runtimes[^Perf].
So they're often used for low-resource embedded systems and real-time data processing.

The "smarts" of any stream cipher algorithm is how it turns a finite-size key (RC4 lets Alice and Bob choose anywhere from 40 to 2,048 bits) into a **keystream** as long as the input data (which could be arbitrarily long, maybe we need to encrypt a 10 GB file).
Expand Down
2 changes: 1 addition & 1 deletion src/chp2/static_assurance_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Generally speaking:

* *Failure to terminate* means the analysis never outputs a result. This can be due to "state explosion" - a combinatorial growth in complexity of the problem the analysis is trying to reason about. To avoid spinning forever, many commercial tools reduce complexity via approximation. Which, again, risks false positives.

Designing an static analysis algorithm practical enough to terminate (no state explosion) yet clever enough to never produce a false positive (no over-approximation) is, surprisingly often, impossible.
Designing a static analysis algorithm practical enough to terminate (no state explosion) yet clever enough to never produce a false positive (no over-approximation) is, surprisingly often, impossible.
Not "impossible given our current knowledge and computational power".
Provably impossible, as in the problem is mathematically *undecidable*[^AliasPaper][^AliasPaper2].

Expand Down
2 changes: 1 addition & 1 deletion src/chp3/rust_5_own_2.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ That's a solid starting point for high assurance software.

> **Computers and Humans Exploring Software Security (CHESS)**
>
> CHESS was DARPA research program[^CHESS] on "the effectiveness of enabling computers and humans to collaboratively reason over software artifacts...with the goal of finding 0-day vulnerabilities at a scale and speed appropriate for the complex software ecosystem upon which the U.S. Government, military, and economy depend"[^CHESSDesc].
> CHESS was a DARPA research program[^CHESS] on "the effectiveness of enabling computers and humans to collaboratively reason over software artifacts...with the goal of finding 0-day vulnerabilities at a scale and speed appropriate for the complex software ecosystem upon which the U.S. Government, military, and economy depend"[^CHESSDesc].
>
> It's a response to the fact that in-depth security assessments are a **difficult to scale expert process**.
> Rust was not considered a solution under the CHESS program.
Expand Down
2 changes: 1 addition & 1 deletion src/chp3/rust_6_error.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ Including implicit cases like this one.
One goal of testing is to show that a program is robust enough to not hit such assertions in practice, due to checks and/or mitigations.
Some number of fatal assertions will always be present, but thorough testing can give us confidence that a program avoids them.

Now in certain cases, we may be able to remove problem potential entirely.
Now in certain cases, we may be able to remove potential problems entirely.
For example, we could have initialized the array using an iterator to eliminate the possibility of an out-of-bounds index:

```rust,noplaypen
Expand Down
2 changes: 1 addition & 1 deletion src/chp4/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ But after finishing the chapter, maybe you'll start viewing memory primarily thr
* Develop a mental model of memory safety, type safety, and binary exploitation
* Learn to debug Rust code using Mozilla `rr`[^RR] (an enhanced variant of `gdb`[^GDB])
* Understand how attackers exploit heap memory corruption bugs, step-by-step
* Write your first an introductory exploit or two, bypassing modern protections!
* Write an introductory exploit or two, bypassing modern protections!
* Understand how Rust actually provides memory safety, including current limitations
* Understand how modern, language-agnostic exploit mitigations work (and how they can fail)

Expand Down
2 changes: 1 addition & 1 deletion src/chp4/assure_stack_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Lets visualize how a code snippet uses the stack, to make the push/pop discussio

* We're interested in how this program uses stack memory at runtime, adding the attribute `#[inline(never)]` to ensure the compiler allocates a stack frame each time either `recursive_count_down` or `square` is called.

* "Inlining" is an opportunistic compiler optimization can avoids function call overhead, including stack frame allocation and caller-register preservation [^Inlining]. It's not always applicable and as programmer we don't directly decide where it is. So forgoing it is a realistic case to prepare for.
* "Inlining" is an opportunistic compiler optimization that avoids function call overhead, including stack frame allocation and caller-register preservation [^Inlining]. It's not always applicable and as programmer we don't directly decide where it is. So forgoing it is a realistic case to prepare for.

If run with `cargo run -- 2`, this program outputs:

Expand Down
4 changes: 2 additions & 2 deletions src/chp4/attack_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Be it C, C++, or `unsafe` Rust.

For a more concrete discussion of memory and type safety, we'll examine three C snippets and visualize the violations therein. Note:

* None of the three snippets are, to the best our knowledge, *exploitable*. These small programs break safety, but not in manner unfortunate enough to enable a break of data-code isolation.
* None of the three snippets are, to the best our knowledge, *exploitable*. These small programs break safety, but not in a manner unfortunate enough to enable a break of data-code isolation.

This distinction is intensional.
We're starting by learning to identify bugs, even if innocuous.
Expand Down Expand Up @@ -416,7 +416,7 @@ In this type safety example, it happens to be hardcoded and thus stored in stati

> **What if we're not talking about binaries?**
>
> We're focused on binary exploitation in this chapter, but that the data-is-code concept applies generally.
> We're focused on binary exploitation in this chapter, but the data-is-code concept applies generally.
> Let's pick on Java for a moment.
>
> The Java language is ubiquitous in enterprise and shares its runtime with languages like Kotlin, Clojure, and Scala.
Expand Down
6 changes: 3 additions & 3 deletions src/chp4/sw_stack_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Both topics are the subjects of entire technical books, so we'll visually diagra
</p>

Main memory, a physical machine's Random Access Memory (RAM), supports all non-trivial runtime computation.
The bit-patterns it stores and operates on representations two distinct items:
The bit-patterns it stores and operates on represent two distinct items:

* **Data** - Variable-length sequences of bytes representing any information: hardcoded strings, colors codes, numbers, entire image and video files, etc. Each byte can be addressed individually, even if word-aligned accesses are often preferable for performance.

Expand Down Expand Up @@ -114,7 +114,7 @@ Fortunately, we don't have to consider or understand such minutia when programmi
The jobs of various registers are, by contrast, important for a working mental model.
In addition to the IP, the two special purpose registers worth noting are:

* The **Stack Pointer (`SP`)** register - the address denoting the bottom of the current stack frame. A stack frame is akin to function's in-RAM "notepad" for computing and saving *function-local* results.
* The **Stack Pointer (`SP`)** register - the address denoting the bottom of the current stack frame. A stack frame is akin to a function's in-RAM "notepad" for computing and saving *function-local* results.

* In the statement `let x = 3 + 6;`, `x` will be computed using registers, then the value `9` will be stored on the stack[^RegisterAlloc]. This allows the CPU to re-use its small, fixed set of `GP*` registers for new computations when multiple functions are called in a program.

Expand Down Expand Up @@ -185,7 +185,7 @@ It's important you commit it to memory, pun intended.
> The kernel runs in "ring 0", the most privileged mode available.
> It can read/write from/to any processes's memory, directly access hardware, and control special CPU features.
>
> Rings 2 and 3 are almost never used in practice[^RingProt].
> Rings 1 and 2 are almost never used in practice[^RingProt].
> These modes were intended for device drivers, special programs that allow a kernel to communicate with vendor-specific hardware.
> In reality most device drivers are loaded directly into the kernel, running alongside it in ring 0 (creating a major OS attack surface[^MSKernBlocklist]).
>
Expand Down