Skip to content

Commit

Permalink
surtr: enable NX-bit and protect ymir text section
Browse files Browse the repository at this point in the history
Signed-off-by: smallkirby <ssmallkirby@gmail.com>
  • Loading branch information
smallkirby committed Aug 16, 2024
1 parent f267ef0 commit 3becda0
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 11 deletions.
6 changes: 6 additions & 0 deletions surtr/arch/x86/arch.zig
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
pub const page = @import("page.zig");

/// Enable NX-bit.
pub fn enableNxBit() void {
const efer_reg: *volatile u64 = @ptrFromInt(0xC000_0080);
efer_reg.* = efer_reg.* | (1 << 11);
}
33 changes: 25 additions & 8 deletions surtr/arch/x86/page.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const std = @import("std");
const log = std.log.scoped(.archp);
const uefi = std.os.uefi;
const elf = std.elf;
const BootServices = uefi.tables.BootServices;

const am = @import("asm.zig");
Expand Down Expand Up @@ -58,8 +59,16 @@ pub const Virt = u64;
const phys_virt_offset = 0x0;

pub const PageAttribute = enum {
ReadOnly,
ReadWrite,
/// RO
read_only,
/// RW
read_write,
/// RX
executable,

pub fn fromFlags(flags: u32) PageAttribute {
return if (flags & elf.PF_X != 0) .executable else if (flags & elf.PF_W != 0) .read_write else .read_only;
}
};

/// Make level-4 page table writable.
Expand Down Expand Up @@ -104,9 +113,10 @@ pub fn changeMap(virt: Virt, attr: PageAttribute) PageError!void {
if (!lv1_entry.present) return PageError.NotPresent;

lv1_entry.rw = switch (attr) {
PageAttribute.ReadOnly => false,
PageAttribute.ReadWrite => true,
.read_only, .executable => false,
.read_write => true,
};
lv1_entry.xd = attr != .executable;

flushTlbSingle(virt);
}
Expand Down Expand Up @@ -170,12 +180,13 @@ pub fn mapTo(virt: Virt, phys: Phys, attr: PageAttribute, bs: *BootServices) Pag
lv1_entry.* = Lv1PageTableEntry{
.present = true,
.rw = switch (attr) {
PageAttribute.ReadOnly => false,
PageAttribute.ReadWrite => true,
.read_only, .executable => false,
.read_write => true,
},
.us = false,
.pat = false,
.phys_addr = @truncate(phys >> page_shift),
.xd = attr != .executable,
};
}

Expand Down Expand Up @@ -374,7 +385,10 @@ const Lv2PageTableEntry = packed struct(u64) {
restart: bool = false,
/// When the entry maps a 2MiB page, physical address of the 2MiB page.
/// When the entry references a Page Table, 4KB aligned address of the Page Table.
phys_pt: u52,
phys_pt: u51,
/// If the entry maps a 2MiB page and the bit is set, the 2MiB page is not executable.
/// If the entry references a Page Table, the bit must be unset.
xd: bool = false,

/// Get a new PDT entry with the present bit set to false.
pub fn new_nopresent() Lv2PageTableEntry {
Expand Down Expand Up @@ -449,7 +463,10 @@ const Lv1PageTableEntry = packed struct(u64) {
/// Ignored except for HLAT paging.
restart: bool = false,
/// Physical address of the 4KiB page.
phys_addr: u52,
phys_addr: u51,
/// If the entry maps a 4KiB page and the bit is set, the 4KiB page is not executable.
/// If the entry references a Page Table, the bit must be unset.
xd: bool = false,

/// Get the physical address pointed by this entry.
pub inline fn address(self: Lv1PageTableEntry) Phys {
Expand Down
10 changes: 7 additions & 3 deletions surtr/boot.zig
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ pub fn main() uefi.Status {
}
log.info("Allocated memory for kernel image @ 0x{X:0>16} ~ 0x{X:0>16}", .{ kernel_start, kernel_start + pages_4kib * 4096 });

// Map memory for kernel image
// Map memory for kernel image.
arch.page.setLv4PageTableWritable(boot_service) catch |err| {
log.err("Failed to set page table writable: {?}", .{err});
return .LoadError;
Expand All @@ -141,7 +141,7 @@ pub fn main() uefi.Status {
arch.page.mapTo(
kernel_start_virt + 4096 * i,
kernel_start + 4096 * i,
.ReadWrite,
.read_write,
boot_service,
) catch |err| {
log.err("Failed to map memory for kernel image: {?}", .{err});
Expand Down Expand Up @@ -191,17 +191,21 @@ pub fn main() uefi.Status {
const page_start = phdr.p_vaddr & ~(@as(u64, 0xFFF));
const page_end = (phdr.p_vaddr + phdr.p_memsz + 0xFFF) & ~(@as(u64, 0xFFF));
const size = (page_end - page_start) / 4096;
const attribute = arch.page.PageAttribute.fromFlags(phdr.p_flags);
for (0..size) |i| {
arch.page.changeMap(
page_start + 4096 * i,
if (phdr.p_flags & elf.PF_W != 0) .ReadWrite else .ReadOnly,
attribute,
) catch |err| {
log.err("Failed to change memory protection: {?}", .{err});
return .LoadError;
};
}
}

// Enable NX-bit.
arch.enableNxBit();

// Clean up memory.
status = boot_service.freePool(header_buffer);
if (status != .Success) {
Expand Down

0 comments on commit 3becda0

Please sign in to comment.