Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add and enable several x86_64 security features #63

Draft
wants to merge 28 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
21cd9e0
meta: Force SMAP to be available, if qemu can provide it.
Dennisbonke Mar 27, 2022
c485413
arch: Add utility functions for SMAP
Dennisbonke Mar 27, 2022
aa44060
arch: Handle SMAP violations in page faults
Dennisbonke Mar 27, 2022
976d225
drivers/tty: Wrap userspace accesses for SMAP
Dennisbonke Mar 27, 2022
8c3caec
syscalls/fs: Wrap enough syscalls for aero_shell
Dennisbonke Mar 27, 2022
b0bc7c5
syscalls/ipc: Wrap enough syscalls for aero_shell
Dennisbonke Mar 27, 2022
1252874
syscalls/process: Wrap enough syscalls for aero_shell
Dennisbonke Mar 27, 2022
073b032
userland: Wrap some userspace access for SMAP
Dennisbonke Mar 27, 2022
5ce6160
userland: Wrap more userspace access for SMAP
Dennisbonke Mar 27, 2022
7e9f846
arch: Initialize CPU features after initial logging is enabled
Dennisbonke Mar 27, 2022
83f21d3
arch: Enable SMAP
Dennisbonke Mar 27, 2022
5f6a5c4
aero_shell: Add missing newline to uptime
Dennisbonke Mar 27, 2022
2957940
chdir: Fix SMAP violation
Dennisbonke Mar 27, 2022
4920a7b
mkdir: Fix SMAP violation
Dennisbonke Mar 27, 2022
762cc9c
rmdir: Fix SMAP violation
Dennisbonke Mar 27, 2022
5a701b4
uname: Fix SMAP violation
Dennisbonke Mar 27, 2022
3aeabdd
binutils: Only build the needed things for host-binutils
Dennisbonke Mar 27, 2022
d7fcf8d
signals: Fix SMAP violations
Dennisbonke Mar 28, 2022
bbeb33f
tty: Fix more SMAP violations
Dennisbonke Mar 28, 2022
50e5479
fs: Fix pipe and access SMAP violations
Dennisbonke Mar 28, 2022
d1a71cc
syscall/log: Fix SMAP violation
Dennisbonke Mar 28, 2022
046a2ad
time: Fix several SMAP violations
Dennisbonke Mar 28, 2022
8c5bd39
aero.py: Request SMEP and UMIP if possible
Dennisbonke Mar 28, 2022
aee1c6a
unwind: Fix SMAP violation
Dennisbonke Mar 28, 2022
9d030f4
x86_64: Enable write protect
Dennisbonke Mar 28, 2022
857014b
unlink: Fix SMAP violation
Dennisbonke Mar 28, 2022
df63f69
x86_64: Enable SMEP
Dennisbonke Mar 28, 2022
eaae9d2
x86_64: Enable UMIP
Dennisbonke Mar 28, 2022
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
6 changes: 3 additions & 3 deletions aero.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,11 +470,11 @@ def run_in_emulator(args, iso_path):
print("Running with KVM acceleration enabled")

if platform.system() == 'Darwin':
qemu_args += ['-accel', 'hvf', '-cpu', 'qemu64,+la57' if args.la57 else 'qemu64']
qemu_args += ['-accel', 'hvf', '-cpu', 'qemu64,+la57,+smap,+smep,+umip' if args.la57 else 'qemu64,+smap,+smep,+umip']
else:
qemu_args += ['-enable-kvm', '-cpu', 'host,+la57' if args.la57 else 'host']
qemu_args += ['-enable-kvm', '-cpu', 'host,+la57,+smap,+smep,+umip' if args.la57 else 'host,+smap,+smep,+umip']
else:
qemu_args += ["-cpu", "qemu64,+la57" if args.la57 else "qemu64"]
qemu_args += ["-cpu", "qemu64,+la57,+smap,+smep,+umip" if args.la57 else "qemu64,+smap,+smep,+umip"]

run_command(['qemu-system-x86_64', *qemu_args])

Expand Down
4 changes: 2 additions & 2 deletions bootstrap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,9 @@ tools:
# -g blows up the binary size.
- 'CFLAGS=-pipe'
compile:
- args: ['make', '-j@PARALLELISM@']
- args: ['make', '-j@PARALLELISM@', 'all-binutils', 'all-gas', 'all-ld']
install:
- args: ['make', 'install']
- args: ['make', 'install-binutils', 'install-gas', 'install-ld']

- name: host-gcc
from_source: gcc
Expand Down
33 changes: 33 additions & 0 deletions src/aero_kernel/src/arch/x86_64/controlregs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
* along with Aero. If not, see <https://www.gnu.org/licenses/>.
*/

use core::sync::atomic::{AtomicUsize, Ordering};

use crate::mem::paging::{PhysAddr, PhysFrame, VirtAddr};

bitflags::bitflags! {
Expand Down Expand Up @@ -273,3 +275,34 @@ pub fn read_cr2() -> VirtAddr {
VirtAddr::new(value)
}
}

/// Returns true if Supervisor Mode Access Prevention (SMAP) is supported by the CPU and is enabled in Cr4.
#[inline]
pub fn smap_enabled() -> bool {
read_cr4().contains(Cr4Flags::SUPERVISOR_MODE_ACCESS_PREVENTION)
}

#[inline]
pub fn with_userspace_access<F, R>(f: F) -> R
where
F: FnOnce() -> R,
{
static REF_COUNT: AtomicUsize = AtomicUsize::new(0);
if smap_enabled() {
unsafe {
asm!("stac");
}
REF_COUNT.fetch_add(1, Ordering::Acquire);
};
let r = f();
if smap_enabled() {
REF_COUNT.fetch_sub(1, Ordering::Release);

if REF_COUNT.load(Ordering::Relaxed) == 0 {
unsafe {
asm!("clac");
}
}
};
r
}
21 changes: 19 additions & 2 deletions src/aero_kernel/src/arch/x86_64/interrupts/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,23 @@ pub(super) fn page_fault(stack: &mut InterruptErrorStack) {
log::error!("stack: {:#x?}", stack);
};

if reason.contains(PageFaultErrorCode::PROTECTION_VIOLATION) && !reason.contains(PageFaultErrorCode::USER_MODE) {
if controlregs::smap_enabled() {
unwind::prepare_panic();

log::error!("SMAP violation page fault");
print_info();

controlregs::with_userspace_access(||unwind::unwind_stack_trace());

unsafe {
loop {
super::halt();
}
}
}
}

if accessed_address < userland_last_address && scheduler::is_initialized()
|| stack.stack.iret.is_user()
{
Expand Down Expand Up @@ -130,7 +147,7 @@ pub(super) fn page_fault(stack: &mut InterruptErrorStack) {
scheduler::get_scheduler().log_ptable();
}

unwind::unwind_stack_trace();
controlregs::with_userspace_access(||unwind::unwind_stack_trace());

let task = scheduler::get_scheduler().current_task();
task.signal(aero_syscall::signal::SIGSEGV);
Expand All @@ -147,7 +164,7 @@ pub(super) fn page_fault(stack: &mut InterruptErrorStack) {
log::error!("Page fault");
print_info();

unwind::unwind_stack_trace();
controlregs::with_userspace_access(||unwind::unwind_stack_trace());

unsafe {
loop {
Expand Down
43 changes: 40 additions & 3 deletions src/aero_kernel/src/arch/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,16 +146,16 @@ extern "C" fn x86_64_aero_main(boot_info: &'static StivaleStruct) -> ! {
.unwrap()
});

// Initialize the CPU specific features.
init_cpu();

// We initialize the COM ports before doing anything else.
//
// This will help printing panics and logs before or when the debug renderer
// is initialized and if serial output is avaliable.
drivers::uart_16550::init();
logger::init();

// Initialize the CPU specific features.
init_cpu();

// Parse the kernel command line.
let command_line: &'static _ = boot_info.command_line().map_or("", |cmd| unsafe {
let cmdline = PhysAddr::new(cmd.command_line).as_hhdm_virt();
Expand Down Expand Up @@ -251,13 +251,50 @@ pub fn init_cpu() {

cr0.remove(controlregs::Cr0Flags::EMULATE_COPROCESSOR);
cr0.insert(controlregs::Cr0Flags::MONITOR_COPROCESSOR);
cr0.insert(controlregs::Cr0Flags::WRITE_PROTECT);

controlregs::write_cr0(cr0);
}

{
// Check if SMAP is supported.
let has_smap = CpuId::new()
.get_extended_feature_info()
.map_or(false, |i| i.has_smap());

// Check if SMEP is supported.
let has_smep = CpuId::new()
.get_extended_feature_info()
.map_or(false, |i| i.has_smep());

// Check if UMIP is supported.
let has_umip = CpuId::new()
.get_extended_feature_info()
.map_or(false, |i| i.has_umip());

let mut cr4 = controlregs::read_cr4();

if has_smap {
log::info!("SMAP is supported, enabling SMAP.");
cr4.insert(controlregs::Cr4Flags::SUPERVISOR_MODE_ACCESS_PREVENTION);
} else {
log::info!("SMAP is not supported.");
}

if has_smep {
log::info!("SMEP is supported, enabling SMEP.");
cr4.insert(controlregs::Cr4Flags::SUPERVISOR_MODE_EXECUTION_PROTECTION);
} else {
log::info!("SMEP is not supported.");
}

if has_umip {
log::info!("UMIP is supported, enabling UMIP.");
cr4.insert(controlregs::Cr4Flags::USER_MODE_INSTRUCTION_PREVENTION);
} else {
log::info!("UMIP is not supported.");
}

cr4.insert(controlregs::Cr4Flags::OSFXSR);
cr4.insert(controlregs::Cr4Flags::OSXMMEXCPT_ENABLE);

Expand Down
5 changes: 3 additions & 2 deletions src/aero_kernel/src/arch/x86_64/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use crate::userland;
use crate::userland::scheduler;
use crate::utils::StackHelper;
use crate::arch::controlregs;

use super::interrupts::InterruptStack;

Expand Down Expand Up @@ -107,11 +108,11 @@ pub fn sigreturn(stack: &mut InterruptStack) -> usize {

let current_task = scheduler::get_scheduler().current_task();

current_task.signals().set_mask(
controlregs::with_userspace_access(||current_task.signals().set_mask(
aero_syscall::signal::SigProcMask::Set,
signal_frame.sigmask,
None,
);
));

writer.get_by(REDZONE_SIZE);

Expand Down
17 changes: 9 additions & 8 deletions src/aero_kernel/src/drivers/tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::fs::inode;
use crate::fs::inode::INodeInterface;
use crate::mem::paging::VirtAddr;
use crate::utils::sync::{BlockQueue, Mutex};
use crate::arch::controlregs;

use super::keyboard::KeyCode;
use super::keyboard::KeyboardListener;
Expand Down Expand Up @@ -234,11 +235,11 @@ impl INodeInterface for Tty {

if buffer.len() > stdin.front_buffer.len() {
for (i, c) in stdin.front_buffer.drain(..).enumerate() {
buffer[i] = c;
controlregs::with_userspace_access(||buffer[i] = c);
}
} else {
for (i, c) in stdin.front_buffer.drain(..buffer.len()).enumerate() {
buffer[i] = c;
controlregs::with_userspace_access(||buffer[i] = c);
}
}

Expand All @@ -264,13 +265,13 @@ impl INodeInterface for Tty {

let (rows, cols) = crate::rendy::get_rows_cols();

winsize.ws_row = rows as u16;
winsize.ws_col = cols as u16;
controlregs::with_userspace_access(||winsize.ws_row = rows as u16);
controlregs::with_userspace_access(||winsize.ws_col = cols as u16);

let (xpixel, ypixel) = crate::rendy::get_resolution();

winsize.ws_xpixel = xpixel as u16;
winsize.ws_ypixel = ypixel as u16;
controlregs::with_userspace_access(||winsize.ws_xpixel = xpixel as u16);
controlregs::with_userspace_access(||winsize.ws_ypixel = ypixel as u16);

Ok(0x00)
}
Expand All @@ -282,7 +283,7 @@ impl INodeInterface for Tty {
let lock = TERMIOS.lock_irq();
let this = &*lock;

*termios = this.clone();
controlregs::with_userspace_access(||*termios = this.clone());
Ok(0x00)
}

Expand All @@ -299,7 +300,7 @@ impl INodeInterface for Tty {
let mut lock = TERMIOS.lock_irq();
let this = &mut *lock;

*this = termios.clone();
controlregs::with_userspace_access(||*this = termios.clone());
Ok(0x00)
}

Expand Down
32 changes: 17 additions & 15 deletions src/aero_kernel/src/syscall/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
use aero_syscall::prelude::FdFlags;
use aero_syscall::{AeroSyscallError, OpenFlags};

use crate::arch::controlregs;

use crate::fs::inode::DirEntry;
use crate::fs::pipe::Pipe;
use crate::fs::{self, lookup_path, LookupMode};
Expand All @@ -39,8 +41,8 @@ pub fn write(fd: usize, buffer: usize, size: usize) -> Result<usize, AeroSyscall
.flags
.intersects(OpenFlags::O_WRONLY | OpenFlags::O_RDWR)
{
let buffer = validate_slice(buffer as *const u8, size).ok_or(AeroSyscallError::EINVAL)?;
Ok(handle.write(buffer)?)
let buffer = controlregs::with_userspace_access(||validate_slice(buffer as *const u8, size).ok_or(AeroSyscallError::EINVAL))?;
Ok(controlregs::with_userspace_access(||handle.write(buffer))?)
} else {
Err(AeroSyscallError::EACCES)
}
Expand All @@ -57,8 +59,8 @@ pub fn read(fd: usize, buffer: usize, size: usize) -> Result<usize, AeroSyscallE
.flags
.intersects(OpenFlags::O_RDONLY | OpenFlags::O_RDWR)
{
let buffer = validate_slice_mut(buffer as *mut u8, size).ok_or(AeroSyscallError::EINVAL)?;
Ok(handle.read(buffer)?)
let buffer = controlregs::with_userspace_access(||validate_slice_mut(buffer as *mut u8, size).ok_or(AeroSyscallError::EINVAL))?;
Ok(controlregs::with_userspace_access(||handle.read(buffer))?)
} else {
Err(AeroSyscallError::EACCES)
}
Expand All @@ -71,7 +73,7 @@ pub fn open(_fd: usize, path: usize, len: usize, mode: usize) -> Result<usize, A
flags.insert(OpenFlags::O_RDONLY);
}

let path = validate_str(path as *const u8, len).ok_or(AeroSyscallError::EINVAL)?;
let path = controlregs::with_userspace_access(||validate_str(path as *const u8, len).ok_or(AeroSyscallError::EINVAL))?;
let path = Path::new(path);

let mut lookup_mode = LookupMode::None;
Expand All @@ -80,7 +82,7 @@ pub fn open(_fd: usize, path: usize, len: usize, mode: usize) -> Result<usize, A
lookup_mode = LookupMode::Create;
}

let inode = fs::lookup_path_with_mode(path, lookup_mode)?;
let inode = controlregs::with_userspace_access(||fs::lookup_path_with_mode(path, lookup_mode))?;

if flags.contains(OpenFlags::O_DIRECTORY) && !inode.inode().metadata()?.is_directory() {
return Err(AeroSyscallError::ENOTDIR);
Expand Down Expand Up @@ -118,7 +120,7 @@ pub fn getdents(fd: usize, buffer: usize, size: usize) -> Result<usize, AeroSysc
.ok_or(AeroSyscallError::EBADFD)?;

let buffer = validate_slice_mut(buffer as *mut u8, size).ok_or(AeroSyscallError::EINVAL)?;
Ok(handle.get_dents(buffer)?)
Ok(controlregs::with_userspace_access(||handle.get_dents(buffer))?)
}

pub fn close(fd: usize) -> Result<usize, AeroSyscallError> {
Expand All @@ -136,7 +138,7 @@ pub fn close(fd: usize) -> Result<usize, AeroSyscallError> {
}

pub fn chdir(path: usize, size: usize) -> Result<usize, AeroSyscallError> {
let buffer = validate_str(path as *mut u8, size).ok_or(AeroSyscallError::EINVAL)?;
let buffer = controlregs::with_userspace_access(||validate_str(path as *mut u8, size).ok_or(AeroSyscallError::EINVAL))?;
let inode = fs::lookup_path(Path::new(buffer))?;

if !inode.inode().metadata()?.is_directory() {
Expand All @@ -149,7 +151,7 @@ pub fn chdir(path: usize, size: usize) -> Result<usize, AeroSyscallError> {
}

pub fn mkdirat(dfd: usize, path: usize, size: usize) -> Result<usize, AeroSyscallError> {
let path_str = validate_str(path as *mut u8, size).ok_or(AeroSyscallError::EINVAL)?;
let path_str = controlregs::with_userspace_access(||validate_str(path as *mut u8, size).ok_or(AeroSyscallError::EINVAL))?;
let path = Path::new(path_str);

// NOTE: If the pathname given in pathname is relative, then it is interpreted
Expand Down Expand Up @@ -197,7 +199,7 @@ pub fn mkdir(path: usize, size: usize) -> Result<usize, AeroSyscallError> {
}

pub fn rmdir(path: usize, size: usize) -> Result<usize, AeroSyscallError> {
let path_str = validate_str(path as *mut u8, size).ok_or(AeroSyscallError::EINVAL)?;
let path_str = controlregs::with_userspace_access(||validate_str(path as *mut u8, size).ok_or(AeroSyscallError::EINVAL))?;
let path = Path::new(path_str);

let (_, child) = path.parent_and_basename();
Expand All @@ -224,7 +226,7 @@ pub fn getcwd(buffer: usize, size: usize) -> Result<usize, AeroSyscallError> {
let buffer = validate_slice_mut(buffer as *mut u8, size).ok_or(AeroSyscallError::EINVAL)?;
let cwd = scheduler::get_scheduler().current_task().get_cwd();

buffer[..cwd.len()].copy_from_slice(cwd.as_bytes());
controlregs::with_userspace_access(||buffer[..cwd.len()].copy_from_slice(cwd.as_bytes()));
Ok(cwd.len())
}

Expand Down Expand Up @@ -275,8 +277,8 @@ pub fn pipe(fds: usize, flags: usize) -> Result<usize, AeroSyscallError> {
Ok(fd2) => fd2,
};

fds[0] = fd1;
fds[1] = fd2;
controlregs::with_userspace_access(||fds[0] = fd1);
controlregs::with_userspace_access(||fds[1] = fd2);

Ok(0x00)
}
Expand All @@ -287,7 +289,7 @@ pub fn unlink(
path_size: usize,
flags: usize,
) -> Result<usize, AeroSyscallError> {
let path_str = validate_str(path as *mut u8, path_size).ok_or(AeroSyscallError::EINVAL)?;
let path_str = controlregs::with_userspace_access(||validate_str(path as *mut u8, path_size).ok_or(AeroSyscallError::EINVAL))?;
let path = Path::new(path_str);

// TODO: Make use of the open flags.
Expand Down Expand Up @@ -319,7 +321,7 @@ pub fn access(
_mode: usize,
_flags: usize,
) -> Result<usize, AeroSyscallError> {
let path_str = validate_str(path as *mut u8, path_size).ok_or(AeroSyscallError::EINVAL)?;
let path_str = controlregs::with_userspace_access(||validate_str(path as *mut u8, path_size).ok_or(AeroSyscallError::EINVAL))?;
let path = Path::new(path_str);

if fd as isize == aero_syscall::AT_FDCWD {
Expand Down
Loading