From: ardb@kernel.org
To: linux-efi@vger.kernel.org
Cc: Ard Biesheuvel <ardb@google.com>, Marc Zyngier <maz@kernel.org>,
Will Deacon <will@kernel.org>,
Quentin Perret <qperret@google.com>,
David Brazdil <dbrazdil@google.com>,
Fuad Tabba <tabba@google.com>, Kees Cook <keescook@chromium.org>
Subject: [RFC PATCH v0 5/6] Remap code section of loaded kernel and boot it
Date: Mon, 14 Mar 2022 09:26:43 +0100 [thread overview]
Message-ID: <20220314082644.3436071-6-ardb@kernel.org> (raw)
In-Reply-To: <20220314082644.3436071-1-ardb@kernel.org>
From: Ard Biesheuvel <ardb@google.com>
Implement the bare minimum needed to discover the size of the
text/rodata region of the loaded image, and use it to remap this region
read-only so that we can execute it while WXN protections are enabled.
Then, boot the loaded image by jumping to the start of it.
---
src/cmo.rs | 37 ++++++++++++++++++++
src/main.rs | 22 ++++++++++++
src/pecoff.rs | 23 ++++++++++++
3 files changed, 82 insertions(+)
diff --git a/src/cmo.rs b/src/cmo.rs
new file mode 100644
index 000000000000..49456222c705
--- /dev/null
+++ b/src/cmo.rs
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+use core::arch::asm;
+
+const CTR_IDC: u64 = 1 << 28;
+
+const CTR_DMINLINE_SHIFT: u64 = 16;
+const CTR_DMINLINE_MASK: u64 = 0xf;
+
+pub fn dcache_clean_to_pou(base: *const u8, size: isize) {
+ let ctr = unsafe {
+ let mut l: u64;
+ asm!("mrs {reg}, ctr_el0", // CTR: cache type register
+ reg = out(reg) l,
+ options(pure, nomem, nostack, preserves_flags),
+ );
+ l
+ };
+
+ // Perform the clean only if needed for coherency with the I side
+ if (ctr & CTR_IDC) == 0 {
+ let line_shift = 2 + ((ctr >> CTR_DMINLINE_SHIFT) & CTR_DMINLINE_MASK);
+ let line_size: isize = 1 << line_shift;
+ let num_lines = (size + line_size - 1) >> line_shift;
+ let mut offset: isize = 0;
+
+ for _ in 1..=num_lines {
+ unsafe {
+ asm!("dc cvau, {reg}",
+ reg = in(reg) base.offset(offset),
+ options(nomem, nostack, preserves_flags),
+ );
+ }
+ offset += line_size;
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 048d1b4842cb..81208c18d094 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,11 +6,13 @@
#![allow(incomplete_features)]
#![feature(specialization)]
+mod cmo;
mod console;
mod cstring;
mod fwcfg;
mod pagealloc;
mod paging;
+mod pecoff;
use core::{arch::global_asm, panic::PanicInfo};
use linked_list_allocator::LockedHeap;
@@ -29,6 +31,8 @@ extern "C" {
static _dtb_end: u8;
}
+type EntryFn = unsafe extern "C" fn(*const u8, u64, u64, u64) -> !;
+
const LOAD_ADDRESS: *mut u8 = 0x43210000 as _;
#[no_mangle]
@@ -97,9 +101,27 @@ extern "C" fn efilite_main(base: usize, mapped: usize, used: usize) {
.load_kernel_image(LOAD_ADDRESS)
.expect("Failed to load kernel image");
+ let pe_image = pecoff::Parser::from_ptr(LOAD_ADDRESS);
+
+ // Clean the code region of the loaded image to the PoU so we
+ // can safely fetch instructions from it once the PXN/UXN
+ // attributes are cleared
+ let code_size = pe_image.get_code_size();
+ cmo::dcache_clean_to_pou(LOAD_ADDRESS, code_size as isize);
+
// Switch back to the initial ID map so we can remap
// the loaded kernel image with different permissions
paging::deactivate();
+
+ // Remap the text/rodata part of the image read-only so we will
+ // be able to execute it with WXN protections enabled
+ paging::map_range(LOAD_ADDRESS as u64, code_size, nor_flags);
+ paging::activate();
+
+ unsafe {
+ let entrypoint: EntryFn = core::mem::transmute(LOAD_ADDRESS);
+ entrypoint(&_dtb as *const _, 0, 0, 0);
+ }
}
#[no_mangle]
diff --git a/src/pecoff.rs b/src/pecoff.rs
new file mode 100644
index 000000000000..b9b82fc5cc53
--- /dev/null
+++ b/src/pecoff.rs
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+pub struct Parser {
+ base_of_code: u64,
+ size_of_code: u64,
+}
+
+impl Parser {
+ pub fn from_ptr(ptr: *const u8) -> Parser {
+ // TODO check magic number, arch, etc
+ // TODO deal with variable PE header offset
+ let pehdr_offset = 64;
+
+ Parser {
+ base_of_code: unsafe { *(ptr.offset(pehdr_offset + 28) as *const u32) } as u64,
+ size_of_code: unsafe { *(ptr.offset(pehdr_offset + 44) as *const u32) } as u64,
+ }
+ }
+
+ pub fn get_code_size(&self) -> u64 {
+ return self.base_of_code + self.size_of_code;
+ }
+}
--
2.30.2
next prev parent reply other threads:[~2022-03-14 8:27 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-03-14 8:26 [RFC PATCH v0 0/6] Minimal Linux/arm64 VM firmware (written in Rust) ardb
2022-03-14 8:26 ` [RFC PATCH v0 1/6] Implement a bare metal Rust runtime on top of QEMU's mach-virt ardb
2022-03-14 8:26 ` [RFC PATCH v0 2/6] Add DTB processing ardb
2022-03-14 8:26 ` [RFC PATCH v0 3/6] Add paging code to manage the full ID map ardb
2022-03-14 8:26 ` [RFC PATCH v0 4/6] Discover QEMU fwcfg device and use it to load the kernel ardb
2022-03-14 8:26 ` ardb [this message]
2022-03-14 8:26 ` [RFC PATCH v0 6/6] Temporarily pass the kaslr seed via register X1 ardb
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220314082644.3436071-6-ardb@kernel.org \
--to=ardb@kernel.org \
--cc=ardb@google.com \
--cc=dbrazdil@google.com \
--cc=keescook@chromium.org \
--cc=linux-efi@vger.kernel.org \
--cc=maz@kernel.org \
--cc=qperret@google.com \
--cc=tabba@google.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.