rkyv/validation/archive/
validator.rs1use core::{
2 alloc::Layout, error::Error, fmt, marker::PhantomData, num::NonZeroUsize,
3 ops::Range,
4};
5
6use rancor::{fail, OptionExt, Source};
7
8use crate::validation::ArchiveContext;
9
10const PTR_WIDTH: usize = (usize::BITS / 4 + 2) as usize;
11
12struct Pointer(pub usize);
13
14impl fmt::Display for Pointer {
15 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16 write!(f, "{:#0w$x}", self.0, w = PTR_WIDTH)
17 }
18}
19
20#[derive(Debug)]
21struct UnalignedPointer {
22 address: usize,
23 align: usize,
24}
25
26impl fmt::Display for UnalignedPointer {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 write!(
29 f,
30 "unaligned pointer: ptr {} unaligned for alignment {}",
31 Pointer(self.address),
32 self.align,
33 )
34 }
35}
36
37impl Error for UnalignedPointer {}
38
39#[derive(Debug)]
40struct InvalidSubtreePointer {
41 address: usize,
42 size: usize,
43 subtree_range: Range<usize>,
44}
45
46impl fmt::Display for InvalidSubtreePointer {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 write!(
49 f,
50 "subtree pointer overran range: ptr {} size {} in range {}..{}",
51 Pointer(self.address),
52 self.size,
53 Pointer(self.subtree_range.start),
54 Pointer(self.subtree_range.end),
55 )
56 }
57}
58
59impl Error for InvalidSubtreePointer {}
60
61#[derive(Debug)]
62struct ExceededMaximumSubtreeDepth;
63
64impl fmt::Display for ExceededMaximumSubtreeDepth {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 write!(
67 f,
68 "pushed a subtree range that exceeded the maximum subtree depth",
69 )
70 }
71}
72
73impl Error for ExceededMaximumSubtreeDepth {}
74
75#[derive(Debug)]
76struct RangePoppedTooManyTimes;
77
78impl fmt::Display for RangePoppedTooManyTimes {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 write!(f, "subtree range popped too many times")
81 }
82}
83
84impl Error for RangePoppedTooManyTimes {}
85
86#[derive(Debug)]
87struct RangePoppedOutOfOrder;
88
89impl fmt::Display for RangePoppedOutOfOrder {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 write!(f, "subtree range popped out of order")
92 }
93}
94
95impl Error for RangePoppedOutOfOrder {}
96
97#[derive(Debug)]
99pub struct ArchiveValidator<'a> {
100 subtree_range: Range<usize>,
101 max_subtree_depth: Option<NonZeroUsize>,
102 _phantom: PhantomData<&'a [u8]>,
103}
104
105impl<'a> ArchiveValidator<'a> {
106 #[inline]
108 pub fn new(bytes: &'a [u8]) -> Self {
109 Self::with_max_depth(bytes, None)
110 }
111
112 #[inline]
115 pub fn with_max_depth(
116 bytes: &'a [u8],
117 max_subtree_depth: Option<NonZeroUsize>,
118 ) -> Self {
119 let Range { start, end } = bytes.as_ptr_range();
120 Self {
121 subtree_range: Range {
122 start: start as usize,
123 end: end as usize,
124 },
125 max_subtree_depth,
126 _phantom: PhantomData,
127 }
128 }
129}
130
131unsafe impl<E: Source> ArchiveContext<E> for ArchiveValidator<'_> {
132 fn check_subtree_ptr(
133 &mut self,
134 ptr: *const u8,
135 layout: &Layout,
136 ) -> Result<(), E> {
137 let start = ptr as usize;
138 let end = ptr.wrapping_add(layout.size()) as usize;
139 if end < start
140 || start < self.subtree_range.start
141 || end > self.subtree_range.end
142 {
143 fail!(InvalidSubtreePointer {
144 address: start,
145 size: layout.size(),
146 subtree_range: self.subtree_range.clone(),
147 });
148 } else if start & (layout.align() - 1) != 0 {
149 fail!(UnalignedPointer {
150 address: ptr as usize,
151 align: layout.align(),
152 });
153 } else {
154 Ok(())
155 }
156 }
157
158 unsafe fn push_subtree_range(
159 &mut self,
160 root: *const u8,
161 end: *const u8,
162 ) -> Result<Range<usize>, E> {
163 if let Some(max_subtree_depth) = &mut self.max_subtree_depth {
164 *max_subtree_depth = NonZeroUsize::new(max_subtree_depth.get() - 1)
165 .into_trace(ExceededMaximumSubtreeDepth)?;
166 }
167
168 let result = Range {
169 start: end as usize,
170 end: self.subtree_range.end,
171 };
172 self.subtree_range.end = root as usize;
173 Ok(result)
174 }
175
176 unsafe fn pop_subtree_range(
177 &mut self,
178 range: Range<usize>,
179 ) -> Result<(), E> {
180 if range.start < self.subtree_range.end {
181 fail!(RangePoppedOutOfOrder);
182 }
183 self.subtree_range = range;
184 if let Some(max_subtree_depth) = &mut self.max_subtree_depth {
185 *max_subtree_depth = max_subtree_depth
186 .checked_add(1)
187 .into_trace(RangePoppedTooManyTimes)?;
188 }
189 Ok(())
190 }
191}