Skip to content

Commit fdf9d4b

Browse files
committed
Integrate latest changes from main
Merges branch 'main' into next and adjust the code accordingly. Changes the config serialization format.
2 parents fd7b2cf + 66637c1 commit fdf9d4b

File tree

11 files changed

+291
-69
lines changed

11 files changed

+291
-69
lines changed

Cargo.lock

Lines changed: 35 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ exclude = ["examples/basic", "examples/test_framework"]
2727
anyhow = "1.0.32"
2828
fatfs = "0.3.4"
2929
gpt = "3.0.0"
30+
raw-cpuid = { version = "10.2.0", optional = true }
31+
rand = { version = "0.8.4", optional = true, default-features = false }
32+
rand_chacha = { version = "0.3.1", optional = true, default-features = false }
3033

3134
# [dependencies.bootloader-x86_64-uefi]
3235
# version = "0.1.0"

Changelog.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Unreleased
22

3+
# 0.10.12 – 2022-02-06
4+
5+
- Add support for position independent executables ([#206](https://github.com/rust-osdev/bootloader/pull/206))
6+
- Add optional ASLR ([#221](https://github.com/rust-osdev/bootloader/pull/221))
7+
- Logger: nicer font rendering into framebuffer ([#213](https://github.com/rust-osdev/bootloader/pull/213))
8+
- Fix warnings on latest nightly (`maybe_uninit_extra` is no longer feature-gated) ([#222](https://github.com/rust-osdev/bootloader/pull/222))
9+
- Rework `UsedLevel4Entries` ([#219](https://github.com/rust-osdev/bootloader/pull/219))
10+
- Add small doc-comment to entry_point! macro ([#220](https://github.com/rust-osdev/bootloader/pull/220))
11+
312
# 0.10.11 – 2022-01-09
413

514
- Remove feature flag for `lang_items`, `asm` and `global_asm` ([#210](https://github.com/rust-osdev/bootloader/pull/210))

api/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ fn main() {
1919
(68, 10),
2020
(78, 9),
2121
(87, 9),
22+
(96, 1),
2223
];
2324

2425
let mut code = String::new();

api/src/config.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ impl BootloaderConfig {
3535
0x3D,
3636
];
3737
#[doc(hidden)]
38-
pub const SERIALIZED_LEN: usize = 96;
38+
pub const SERIALIZED_LEN: usize = 97;
3939

4040
/// Creates a new default configuration with the following values:
4141
///
@@ -69,6 +69,7 @@ impl BootloaderConfig {
6969
pre_release,
7070
} = version;
7171
let Mappings {
72+
aslr,
7273
kernel_stack,
7374
boot_info,
7475
framebuffer,
@@ -120,6 +121,7 @@ impl BootloaderConfig {
120121
Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
121122
},
122123
);
124+
let buf = concat_96_1(buf, [(*aslr) as u8]);
123125

124126
buf
125127
}
@@ -174,8 +176,14 @@ impl BootloaderConfig {
174176
let (&physical_memory, s) = split_array_ref(s);
175177
let (&page_table_recursive_some, s) = split_array_ref(s);
176178
let (&page_table_recursive, s) = split_array_ref(s);
179+
let (&[alsr], s) = split_array_ref(s);
177180

178181
let mappings = Mappings {
182+
aslr: match alsr {
183+
1 => true,
184+
0 => false,
185+
_ => return Err(()),
186+
},
179187
kernel_stack: Mapping::deserialize(&kernel_stack)?,
180188
boot_info: Mapping::deserialize(&boot_info)?,
181189
framebuffer: Mapping::deserialize(&framebuffer)?,
@@ -306,6 +314,12 @@ impl Default for ApiVersion {
306314
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
307315
#[non_exhaustive]
308316
pub struct Mappings {
317+
/// Whether to randomize non-statically configured addresses.
318+
/// The kernel base address will be randomized when it's compiled as
319+
/// a position independent executable.
320+
///
321+
/// Defaults to `false`.
322+
pub aslr: bool,
309323
/// Configures how the kernel stack should be mapped.
310324
pub kernel_stack: Mapping,
311325
/// Specifies where the [`crate::BootInfo`] struct should be placed in virtual memory.
@@ -332,6 +346,7 @@ impl Mappings {
332346
/// enabled.
333347
pub const fn new_default() -> Self {
334348
Self {
349+
aslr: false,
335350
kernel_stack: Mapping::new_default(),
336351
boot_info: Mapping::new_default(),
337352
framebuffer: Mapping::new_default(),
@@ -345,6 +360,7 @@ impl Mappings {
345360
let phys = rand::random();
346361
let recursive = rand::random();
347362
Self {
363+
aslr: rand::random(),
348364
kernel_stack: Mapping::random(),
349365
boot_info: Mapping::random(),
350366
framebuffer: Mapping::random(),

common/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ uefi = "0.13"
1616
usize_conversions = "0.2.0"
1717
x86_64 = { version = "0.14.8" }
1818
xmas-elf = "0.8.0"
19+
raw-cpuid = "10.2.0"
20+
rand = { version = "0.8.4", default-features = false }
21+
rand_chacha = { version = "0.3.1", default-features = false }
1922

2023
[dependencies.noto-sans-mono-bitmap]
2124
version = "0.1.2"

common/src/entropy.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng};
2+
use raw_cpuid::CpuId;
3+
use x86_64::instructions::{port::Port, random::RdRand};
4+
5+
/// Gather entropy from various sources to seed a RNG.
6+
pub fn build_rng() -> ChaCha20Rng {
7+
const ENTROPY_SOURCES: [fn() -> [u8; 32]; 3] = [rd_rand_entropy, tsc_entropy, pit_entropy];
8+
9+
// Collect entropy from different sources and xor them all together.
10+
let mut seed = [0; 32];
11+
for entropy_source in ENTROPY_SOURCES {
12+
let entropy = entropy_source();
13+
14+
for (seed, entropy) in seed.iter_mut().zip(entropy) {
15+
*seed ^= entropy;
16+
}
17+
}
18+
19+
// Construct the RNG.
20+
ChaCha20Rng::from_seed(seed)
21+
}
22+
23+
/// Gather entropy by requesting random numbers with `RDRAND` instruction if it's available.
24+
///
25+
/// This function provides excellent entropy (unless you don't trust the CPU vendors).
26+
fn rd_rand_entropy() -> [u8; 32] {
27+
let mut entropy = [0; 32];
28+
29+
// Check if the CPU supports `RDRAND`.
30+
if let Some(rd_rand) = RdRand::new() {
31+
for i in 0..4 {
32+
if let Some(value) = get_random_64(rd_rand) {
33+
entropy[i * 8..(i + 1) * 8].copy_from_slice(&value.to_ne_bytes());
34+
}
35+
}
36+
}
37+
38+
entropy
39+
}
40+
41+
/// Try to fetch a 64 bit random value with a retry count limit of 10.
42+
///
43+
/// This function is a port of the C implementation provided in Intel's Software Developer's Manual, Volume 1, 7.3.17.1.
44+
fn get_random_64(rd_rand: RdRand) -> Option<u64> {
45+
const RETRY_LIMIT: u32 = 10;
46+
for _ in 0..RETRY_LIMIT {
47+
if let Some(value) = rd_rand.get_u64() {
48+
return Some(value);
49+
}
50+
}
51+
None
52+
}
53+
54+
/// Gather entropy by reading the current time with the `RDTSC` instruction if it's available.
55+
///
56+
/// This function doesn't provide particulary good entropy, but it's better than nothing.
57+
fn tsc_entropy() -> [u8; 32] {
58+
let mut entropy = [0; 32];
59+
60+
// Check if the CPU supports `RDTSC`.
61+
let cpu_id = CpuId::new();
62+
if let Some(feature_info) = cpu_id.get_feature_info() {
63+
if !feature_info.has_tsc() {
64+
for i in 0..4 {
65+
let value = unsafe {
66+
// SAFETY: We checked that the cpu supports `RDTSC` and we run in ring 0.
67+
core::arch::x86_64::_rdtsc()
68+
};
69+
entropy[i * 8..(i + 1) * 8].copy_from_slice(&value.to_ne_bytes());
70+
}
71+
}
72+
}
73+
74+
entropy
75+
}
76+
77+
/// Gather entropy by reading the current count of PIT channel 1-3.
78+
///
79+
/// This function doesn't provide particulary good entropy, but it's always available.
80+
fn pit_entropy() -> [u8; 32] {
81+
let mut entropy = [0; 32];
82+
83+
for (i, entropy_byte) in entropy.iter_mut().enumerate() {
84+
// Cycle through channels 1-3.
85+
let channel = i % 3;
86+
87+
let mut port = Port::<u8>::new(0x40 + channel as u16);
88+
let value = unsafe {
89+
// SAFETY: It's safe to read from ports 0x40-0x42.
90+
port.read()
91+
};
92+
93+
*entropy_byte = value;
94+
}
95+
96+
entropy
97+
}

0 commit comments

Comments
 (0)