Skip to content

Commit f13551e

Browse files
RestiosonFreax13
authored andcommitted
slice for safety
1 parent 05c0828 commit f13551e

File tree

2 files changed

+47
-7
lines changed

2 files changed

+47
-7
lines changed

src/structures/gdt.rs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use core::{cmp, fmt, mem};
99
// imports for intra-doc links
1010
#[cfg(doc)]
1111
use crate::registers::segmentation::{Segment, CS, SS};
12+
use crate::structures::tss::InvalidIoMap;
1213

1314
#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
1415
use core::sync::atomic::{AtomicU64 as EntryValue, Ordering};
@@ -439,10 +440,31 @@ impl Descriptor {
439440
/// being used.
440441
#[inline]
441442
pub unsafe fn tss_segment_unchecked(tss: *const TaskStateSegment) -> Descriptor {
442-
// TODO: Remove this with a call to a function that takes a method
443-
// instead of a static reference.
444443
// SAFETY: if iomap_size is zero, there are no requirements to uphold.
445-
unsafe { Self::tss_segment_with_iomap(&*tss, 0) }
444+
unsafe { Self::tss_segment_raw(tss, 0) }
445+
}
446+
447+
/// Creates a TSS system descriptor for the given TSS, setting up the IO permissions bitmap.
448+
pub fn tss_segment_with_iomap(
449+
tss: &'static TaskStateSegment,
450+
iomap: &'static [u8],
451+
) -> Result<Descriptor, InvalidIoMap> {
452+
if iomap.len() > 8193 {
453+
return Err(InvalidIoMap::TooLong { len: iomap.len() })
454+
}
455+
456+
let distance = iomap.as_ptr() as usize - tss as *const _ as usize;
457+
if distance > 0xdfff {
458+
return Err(InvalidIoMap::TooFarFromTss { distance })
459+
}
460+
461+
let last_byte = *iomap.last().unwrap_or(&0xff);
462+
if last_byte != 0xff {
463+
return Err(InvalidIoMap::InvalidTerminatingByte { byte: last_byte })
464+
}
465+
466+
// SAFETY: all invariants checked above
467+
Ok(unsafe { Self::tss_segment_raw(tss, iomap.len() as u16) })
446468
}
447469

448470
/// Creates a TSS system descriptor for the given TSS, setting up the IO permissions bitmap.
@@ -452,20 +474,20 @@ impl Descriptor {
452474
/// There must be a valid IO map at `(tss as *const u8).offset(tss.iomap_base)`
453475
/// of length `iomap_size`, with the terminating `0xFF` byte. Additionally, `iomap_base` must
454476
/// not exceed `0xDFFF`.
455-
pub unsafe fn tss_segment_with_iomap(
456-
tss: &'static TaskStateSegment,
477+
unsafe fn tss_segment_raw(
478+
tss: *const TaskStateSegment,
457479
iomap_size: u16,
458480
) -> Descriptor {
459481
use self::DescriptorFlags as Flags;
460482

461-
let ptr = tss as *const _ as u64;
483+
let ptr = tss as u64;
462484

463485
let mut low = Flags::PRESENT.bits();
464486
// base
465487
low.set_bits(16..40, ptr.get_bits(0..24));
466488
low.set_bits(56..64, ptr.get_bits(24..32));
467489
// limit (the `-1` is needed since the bound is inclusive)
468-
let iomap_limit = tss.iomap_base as u64 + iomap_size as u64;
490+
let iomap_limit = unsafe { (*tss).iomap_base } as u64 + iomap_size as u64;
469491
low.set_bits(
470492
0..16,
471493
cmp::max(mem::size_of::<TaskStateSegment>() as u64, iomap_limit) - 1,

src/structures/tss.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,24 @@ impl Default for TaskStateSegment {
5252
}
5353
}
5454

55+
/// The given IO permissions bitmap is invalid.
56+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
57+
pub enum InvalidIoMap {
58+
/// The IO permissions bitmap is too far from the TSS. It must be within `0xdfff` bytes of the
59+
/// start of the TSS.
60+
TooFarFromTss {
61+
distance: usize,
62+
},
63+
/// The final byte of the IO permissions bitmap was not 0xff
64+
InvalidTerminatingByte {
65+
byte: u8,
66+
},
67+
/// The IO permissions bitmap exceeds the maximum length (8193).
68+
TooLong {
69+
len: usize
70+
},
71+
}
72+
5573
#[cfg(test)]
5674
mod tests {
5775
use super::*;

0 commit comments

Comments
 (0)