1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use std::ops::Range;
pub use rust_cheri_compressed_cap::{CompressedCapability, Cc128, Cc128Cap, wrappers::CheriRVFuncs};
use anyhow::Result;
use crate::processor::exceptions::{CapabilityException,CapOrRegister};
use std::convert::TryInto;
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub enum SafeTaggedCap {
RawData{ top: u64, bot: u64 },
ValidCap(Cc128Cap)
}
impl SafeTaggedCap {
pub fn from_integer(data: u128) -> Self {
SafeTaggedCap::RawData { top: (data >> 64) as u64, bot: data as u64 }
}
pub fn to_integer(&self) -> u128 {
let (top, bot) = match *self {
SafeTaggedCap::RawData{top, bot} => (top, bot),
SafeTaggedCap::ValidCap(cap) => {
let pebst = Cc128::compress_raw(&cap);
let cursor = cap.address();
(pebst, cursor)
}
};
((top as u128) << 64) | (bot as u128)
}
pub fn from_tagged_mem(top: u64, bot: u64, tag: bool) -> Self {
if tag {
let pebst = top;
let addr = bot;
SafeTaggedCap::ValidCap(Cc128::decompress_mem(pebst, addr, tag))
} else {
SafeTaggedCap::RawData{ top, bot }
}
}
pub fn from_cap(cap: Cc128Cap) -> Self {
if cap.tag() {
SafeTaggedCap::ValidCap(cap)
} else {
let pebst = Cc128::compress_raw(&cap);
SafeTaggedCap::RawData{ top: pebst, bot: cap.address() }
}
}
pub fn to_cap(&self) -> Cc128Cap {
match self {
SafeTaggedCap::ValidCap(cap) => *cap,
SafeTaggedCap::RawData{ top, bot } => Cc128::decompress_raw(*top, *bot, false)
}
}
pub fn unwrap_cap(&self) -> Cc128Cap {
match self {
SafeTaggedCap::ValidCap(cap) => *cap,
SafeTaggedCap::RawData{..} => panic!("unwrap_cap called on RawData")
}
}
}
impl Default for SafeTaggedCap {
fn default() -> Self {
SafeTaggedCap::RawData{ top: 0, bot: 0 }
}
}
pub fn cap_bounds_range(cap: Cc128Cap) -> Range<u64> {
let b = cap.bounds();
Range { start: b.0, end: b.1.try_into().unwrap() }
}
pub fn check_capability<TData>(cap: Cc128Cap, expected_perms: u32) -> Result<()> {
check_obj_bounds_against_capability::<TData>(
cap.address(),
cap,
expected_perms
)
}
pub fn check_obj_bounds_against_capability<TData>(addr: u64, cap: Cc128Cap, expected_perms: u32) -> Result<()> {
let size = std::mem::size_of::<TData>() as u64;
check_bounds_against_capability(
Range{
start: addr,
end: addr + size
},
cap,
expected_perms
)
}
pub fn check_bounds_against_capability(bounds: Range<u64>, cap: Cc128Cap, expected_perms: u32) -> Result<()> {
if !cap.tag() {
bail!(CapabilityException::TagViolation{ cap: CapOrRegister::Cap(cap) })
} else if cap.permissions() & expected_perms != expected_perms {
bail!(CapabilityException::PermissionViolation{ cap: CapOrRegister::Cap(cap), perms: expected_perms })
} else if !cap_bounds_range(cap).contains(&bounds.start)
|| !cap_bounds_range(cap).contains(&(bounds.end - 1)) {
bail!(CapabilityException::BoundsViolation{ cap: CapOrRegister::Cap(cap), size: (bounds.end - bounds.start) as usize })
} else if cap.is_sealed() {
bail!(CapabilityException::SealViolation{ cap: CapOrRegister::Cap(cap) })
} else {
Ok(())
}
}