Skip to content

Commit

Permalink
Libuser: Make buffer check alignment.
Browse files Browse the repository at this point in the history
Buffer should check that the address has the correct alignment for the
type T, otherwise we might get some nasty UB.
  • Loading branch information
roblabla committed Mar 18, 2019
1 parent 543e7ec commit e114a2b
Showing 1 changed file with 31 additions and 11 deletions.
42 changes: 31 additions & 11 deletions libuser/src/ipc/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,18 @@
use core::marker::PhantomData;
use crate::ipc::IPCBuffer;
use crate::error::{Error, LibuserError};
use core::mem::{size_of, align_of};

// TODO: Use plain to ensure T is a valid POD type
// BODY: Plain would give us two benefits: it would do the alignment and size
// BODY: checks for us, and it would give a type-system guarantee that our T
// BODY: is valid for any arbitrary type.

/// An incoming Pointer buffer, also known as a Type-X Buffer.
///
/// Note that `T` should be a POD type (in other word, it should be defined for
/// all bit values). This usually means that it should be a repr(C) struct and
/// only contain numeric fields.
pub struct InPointer<'a, T: ?Sized> {
/// Address of the InBuffer in the current address space.
addr: u64,
Expand All @@ -43,11 +53,14 @@ impl<'a, T> InPointer<'a, T> {
///
/// # Errors
///
/// Returns a PortRemoteDead error if the size does not match what was
/// expected
/// Returns an InvalidIpcBuffer error if the size does not match what was
/// expected.
///
/// Returns an InvalidIpcBuffer error if the address is not properly aligned.
pub fn new(buf: IPCBuffer) -> Result<InPointer<'_, T>, Error> {
assert!(buf.buftype().is_type_x());
if buf.size != core::mem::size_of::<T>() as u64 {
if buf.size != size_of::<T>() as u64 ||
buf.addr % (align_of::<T>() as u64) != 0 {
Err(LibuserError::InvalidIpcBuffer.into())
} else {
Ok(InPointer {
Expand Down Expand Up @@ -85,11 +98,12 @@ impl<'a, T> InPointer<'a, [T]> {
///
/// # Errors
///
/// Returns a PortRemoteDead error if the size does not match what was
/// Returns a InvalidIpcBuffer error if the size does not match what was
/// expected
pub fn new(buf: IPCBuffer) -> Result<InPointer<'_, [T]>, Error> {
assert!(buf.buftype().is_type_x());
if buf.size % core::mem::size_of::<T>() as u64 != 0 || buf.size == 0 {
if buf.size % size_of::<T>() as u64 != 0 || buf.size == 0 ||
buf.addr % (align_of::<T>() as u64) != 0 {
Err(LibuserError::InvalidIpcBuffer.into())
} else {
Ok(InPointer {
Expand All @@ -106,12 +120,16 @@ impl<'a, T> core::ops::Deref for InPointer<'a, [T]> {
fn deref(&self) -> &[T] {
unsafe {
core::slice::from_raw_parts(self.addr as usize as *const T,
self.size as usize / core::mem::size_of::<T>())
self.size as usize / size_of::<T>())
}
}
}

/// An incoming Buffer, also known as a Type-A Buffer.
///
/// Note that `T` should be a POD type (in other word, it should be defined for
/// all bit values). This usually means that it should be a repr(C) struct and
/// only contain numeric fields.
pub struct InBuffer<'a, T: ?Sized> {
/// Address of the InBuffer in the current address space.
addr: u64,
Expand All @@ -132,11 +150,12 @@ impl<'a, T> InBuffer<'a, T> {
///
/// # Errors
///
/// Returns a PortRemoteDead error if the size does not match what was
/// Returns a InvalidIpcBuffer error if the size does not match what was
/// expected
pub fn new(buf: IPCBuffer) -> Result<InBuffer<'_, T>, Error> {
assert!(buf.buftype().is_type_a());
if buf.size != core::mem::size_of::<T>() as u64 {
if buf.size != size_of::<T>() as u64 ||
buf.addr % (align_of::<T>() as u64) != 0 {
Err(LibuserError::InvalidIpcBuffer.into())
} else {
Ok(InBuffer {
Expand Down Expand Up @@ -175,11 +194,12 @@ impl<'a, T> InBuffer<'a, [T]> {
///
/// # Errors
///
/// Returns a PortRemoteDead error if the size does not match what was
/// Returns a InvalidIpcBuffer error if the size does not match what was
/// expected
pub fn new(buf: IPCBuffer) -> Result<InBuffer<'_, [T]>, Error> {
assert!(buf.buftype().is_type_a());
if buf.size % core::mem::size_of::<T>() as u64 != 0 || buf.size == 0 {
if buf.size % size_of::<T>() as u64 != 0 || buf.size == 0 ||
buf.addr % (align_of::<T>() as u64) != 0 {
Err(LibuserError::InvalidIpcBuffer.into())
} else {
Ok(InBuffer {
Expand All @@ -196,7 +216,7 @@ impl<'a, T> core::ops::Deref for InBuffer<'a, [T]> {
fn deref(&self) -> &[T] {
unsafe {
core::slice::from_raw_parts(self.addr as usize as *const T,
self.size as usize / core::mem::size_of::<T>())
self.size as usize / size_of::<T>())
}
}
}

0 comments on commit e114a2b

Please sign in to comment.