| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 use bindings::encoding::{Bits, Context, MojomNumeric}; | 5 use bindings::encoding::{Bits, Context, DataHeader, DataHeaderValue, DATA_HEADER
_SIZE, MojomNumeric}; |
| 6 use bindings::mojom::{MOJOM_NULL_POINTER, UNION_SIZE}; | 6 use bindings::mojom::{MojomEncodable, MOJOM_NULL_POINTER, UNION_SIZE}; |
| 7 use bindings::util; | 7 use bindings::util; |
| 8 | 8 |
| 9 use std::mem; | 9 use std::mem; |
| 10 use std::ptr; | 10 use std::ptr; |
| 11 use std::vec::Vec; | 11 use std::vec::Vec; |
| 12 | 12 |
| 13 use system; | 13 use system; |
| 14 use system::{Handle, CastHandle, UntypedHandle}; | 14 use system::{Handle, CastHandle, UntypedHandle}; |
| 15 | 15 |
| 16 #[derive(Debug, Eq, PartialEq)] |
| 17 pub enum ValidationError { |
| 18 DifferentSizedArraysInMap, |
| 19 IllegalHandle, |
| 20 IllegalMemoryRange, |
| 21 IllegalPointer, |
| 22 MessageHeaderInvalidFlags, |
| 23 MessageHeaderMissingRequestId, |
| 24 MessageHeaderUnknownMethod, |
| 25 MisalignedObject, |
| 26 UnexpectedArrayHeader, |
| 27 UnexpectedInvalidHandle, |
| 28 UnexpectedNullPointer, |
| 29 UnexpectedNullUnion, |
| 30 UnexpectedStructHeader, |
| 31 } |
| 32 |
| 33 impl ValidationError { |
| 34 pub fn as_str(self) -> &'static str { |
| 35 match self { |
| 36 ValidationError::DifferentSizedArraysInMap => "VALIDATION_ERROR_DIFF
ERENT_SIZED_ARRAYS_IN_MAP", |
| 37 ValidationError::IllegalHandle => "VALIDATION_ERROR_ILLEGAL_HANDLE", |
| 38 ValidationError::IllegalMemoryRange => "VALIDATION_ERROR_ILLEGAL_MEM
ORY_RANGE", |
| 39 ValidationError::IllegalPointer => "VALIDATION_ERROR_ILLEGAL_POINTER
", |
| 40 ValidationError::MessageHeaderInvalidFlags => "VALIDATION_ERROR_MESS
AGE_HEADER_INVALID_FLAGS", |
| 41 ValidationError::MessageHeaderMissingRequestId => "VALIDATION_ERROR_
MESSAGE_HEADER_MISSING_REQUEST_ID", |
| 42 ValidationError::MessageHeaderUnknownMethod => "VALIDATION_ERROR_MES
SAGE_HEADER_UNKNOWN_METHOD", |
| 43 ValidationError::MisalignedObject => "VALIDATION_ERROR_MISALIGNED_OB
JECT", |
| 44 ValidationError::UnexpectedArrayHeader => "VALIDATION_ERROR_UNEXPECT
ED_ARRAY_HEADER", |
| 45 ValidationError::UnexpectedInvalidHandle => "VALIDATION_ERROR_UNEXPE
CTED_INVALID_HANDLE", |
| 46 ValidationError::UnexpectedNullPointer => "VALIDATION_ERROR_UNEXPECT
ED_NULL_POINTER", |
| 47 ValidationError::UnexpectedNullUnion => "VALIDATION_ERROR_UNEXPECTED
_NULL_UNION", |
| 48 ValidationError::UnexpectedStructHeader => "VALIDATION_ERROR_UNEXPEC
TED_STRUCT_HEADER", |
| 49 } |
| 50 } |
| 51 } |
| 52 |
| 16 /// An decoding state represents the decoding logic for a single | 53 /// An decoding state represents the decoding logic for a single |
| 17 /// Mojom object that is NOT inlined, such as a struct or an array. | 54 /// Mojom object that is NOT inlined, such as a struct or an array. |
| 18 pub struct DecodingState<'slice> { | 55 pub struct DecodingState<'slice> { |
| 19 /// The buffer the state may write to. | 56 /// The buffer the state may write to. |
| 20 data: &'slice [u8], | 57 data: &'slice [u8], |
| 21 | 58 |
| 22 /// The offset of this serialized object into the overall buffer. | 59 /// The offset of this serialized object into the overall buffer. |
| 23 global_offset: usize, | 60 global_offset: usize, |
| 24 | 61 |
| 25 /// The current offset within 'data'. | 62 /// The current offset within 'data'. |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 self.offset += 8; | 182 self.offset += 8; |
| 146 } | 183 } |
| 147 (index < 0) | 184 (index < 0) |
| 148 } | 185 } |
| 149 | 186 |
| 150 /// Decode a pointer from the buffer as a global offset into the buffer. | 187 /// Decode a pointer from the buffer as a global offset into the buffer. |
| 151 /// | 188 /// |
| 152 /// The pointer in the buffer is an offset relative to the pointer to anothe
r | 189 /// The pointer in the buffer is an offset relative to the pointer to anothe
r |
| 153 /// location in the buffer. We convert that to an absolute offset with respe
ct | 190 /// location in the buffer. We convert that to an absolute offset with respe
ct |
| 154 /// to the buffer before returning. This is our defintion of a pointer. | 191 /// to the buffer before returning. This is our defintion of a pointer. |
| 155 pub fn decode_pointer(&mut self) -> u64 { | 192 pub fn decode_pointer(&mut self) -> Option<u64> { |
| 156 self.align_to_byte(); | 193 self.align_to_byte(); |
| 157 self.align_to_bytes(8); | 194 self.align_to_bytes(8); |
| 158 let current_location = (self.global_offset + self.offset) as u64; | 195 let current_location = (self.global_offset + self.offset) as u64; |
| 159 self.read::<u64>() + current_location | 196 let offset = self.read::<u64>(); |
| 197 if offset == MOJOM_NULL_POINTER { |
| 198 Some(MOJOM_NULL_POINTER) |
| 199 } else { |
| 200 offset.checked_add(current_location) |
| 201 } |
| 202 } |
| 203 |
| 204 /// A routine for decoding an array header. |
| 205 /// |
| 206 /// Must be called with offset zero (that is, it must be the first thing |
| 207 /// decoded). Performs numerous validation checks. |
| 208 pub fn decode_array_header<T: MojomEncodable>(&mut self) -> Result<DataHeade
r, ValidationError> { |
| 209 debug_assert_eq!(self.offset, 0); |
| 210 // Make sure we can read the size first... |
| 211 if self.data.len() < mem::size_of::<u32>() { |
| 212 return Err(ValidationError::UnexpectedArrayHeader); |
| 213 } |
| 214 let bytes = self.decode::<u32>(); |
| 215 if (bytes as usize) < DATA_HEADER_SIZE { |
| 216 return Err(ValidationError::UnexpectedArrayHeader); |
| 217 } |
| 218 let elems = self.decode::<u32>(); |
| 219 match T::embed_size(&Default::default()).checked_mul(elems as usize) { |
| 220 Some(value) => if (bytes as usize) < value.as_bytes() + DATA_HEADER_
SIZE { |
| 221 return Err(ValidationError::UnexpectedArrayHeader); |
| 222 }, |
| 223 None => return Err(ValidationError::UnexpectedArrayHeader), |
| 224 } |
| 225 Ok(DataHeader::new(bytes as usize, DataHeaderValue::Elements(elems))) |
| 226 } |
| 227 |
| 228 /// A routine for decoding an struct header. |
| 229 /// |
| 230 /// Must be called with offset zero (that is, it must be the first thing |
| 231 /// decoded). Performs numerous validation checks. |
| 232 pub fn decode_struct_header(&mut self, versions: &[(u32, u32)]) -> Result<Da
taHeader, ValidationError> { |
| 233 debug_assert_eq!(self.offset, 0); |
| 234 // Make sure we can read the size first... |
| 235 if self.data.len() < mem::size_of::<u32>() { |
| 236 return Err(ValidationError::UnexpectedStructHeader); |
| 237 } |
| 238 let bytes = self.decode::<u32>(); |
| 239 if (bytes as usize) < DATA_HEADER_SIZE { |
| 240 return Err(ValidationError::UnexpectedStructHeader); |
| 241 } |
| 242 let version = self.decode::<u32>(); |
| 243 // Versioning validation: versions are generated as a sorted array of tu
ples, so |
| 244 // to find the version we are given by the header we use a binary search
. |
| 245 match versions.binary_search_by(|val| val.0.cmp(&version)) { |
| 246 Ok(idx) => { |
| 247 let (_, size) = versions[idx]; |
| 248 if bytes != size { |
| 249 return Err(ValidationError::UnexpectedStructHeader); |
| 250 } |
| 251 }, |
| 252 Err(idx) => { |
| 253 if idx == 0 { |
| 254 panic!("Should be earliest version? Versions: {:?}, Version:
{}, Size: {}", versions, version, bytes); |
| 255 } |
| 256 let len = versions.len(); |
| 257 let (latest_version, _) = versions[len - 1]; |
| 258 let (_, size) = versions[idx - 1]; |
| 259 // If this is higher than any version we know, its okay for the
size to be bigger, |
| 260 // but if its a version we know about, it must match the size. |
| 261 if (version > latest_version && bytes < size) || (version <= lat
est_version && bytes != size) { |
| 262 return Err(ValidationError::UnexpectedStructHeader); |
| 263 } |
| 264 }, |
| 265 } |
| 266 Ok(DataHeader::new(bytes as usize, DataHeaderValue::Version(version))) |
| 160 } | 267 } |
| 161 } | 268 } |
| 162 | 269 |
| 163 /// A struct that will encode a given Mojom object and convert it into | 270 /// A struct that will encode a given Mojom object and convert it into |
| 164 /// bytes and a vector of handles. | 271 /// bytes and a vector of handles. |
| 165 pub struct Decoder<'slice> { | 272 pub struct Decoder<'slice> { |
| 166 bytes: usize, | 273 bytes: usize, |
| 167 buffer: Option<&'slice [u8]>, | 274 buffer: Option<&'slice [u8]>, |
| 168 states: Vec<DecodingState<'slice>>, | 275 states: Vec<DecodingState<'slice>>, |
| 169 handles: Vec<UntypedHandle>, | 276 handles: Vec<UntypedHandle>, |
| 277 handles_claimed: usize, // A length that claims all handles were claimed up
to this index |
| 278 max_offset: usize, // Represents the maximum value an offset may have |
| 170 } | 279 } |
| 171 | 280 |
| 172 impl<'slice> Decoder<'slice> { | 281 impl<'slice> Decoder<'slice> { |
| 173 /// Create a new Decoder. | 282 /// Create a new Decoder. |
| 174 pub fn new(buffer: &'slice [u8], handles: Vec<UntypedHandle>) -> Decoder<'sl
ice> { | 283 pub fn new(buffer: &'slice [u8], handles: Vec<UntypedHandle>) -> Decoder<'sl
ice> { |
| 284 let max_offset = buffer.len(); |
| 175 Decoder { | 285 Decoder { |
| 176 bytes: 0, | 286 bytes: 0, |
| 177 buffer: Some(buffer), | 287 buffer: Some(buffer), |
| 178 states: Vec::new(), | 288 states: Vec::new(), |
| 179 handles: handles, | 289 handles: handles, |
| 290 handles_claimed: 0, |
| 291 max_offset: max_offset, |
| 180 } | 292 } |
| 181 } | 293 } |
| 182 | 294 |
| 183 /// Claim space in the buffer to start decoding some object. | 295 /// Claim space in the buffer to start decoding some object. |
| 184 /// | 296 /// |
| 185 /// Creates a new decoding state for the object and returns a context. | 297 /// Creates a new decoding state for the object and returns a context. |
| 186 pub fn claim(&mut self, offset: usize) -> Option<Context> { | 298 pub fn claim(&mut self, offset: usize) -> Result<Context, ValidationError> { |
| 299 // Check if the layout order is sane |
| 187 if offset < self.bytes { | 300 if offset < self.bytes { |
| 188 panic!("Tried to claim already-claimed space!"); | 301 return Err(ValidationError::IllegalMemoryRange); |
| 302 } |
| 303 // Check for 8-byte alignment |
| 304 if offset & 7 != 0 { |
| 305 return Err(ValidationError::MisalignedObject); |
| 306 } |
| 307 // Bounds check on offset |
| 308 if offset > self.max_offset { |
| 309 return Err(ValidationError::IllegalPointer); |
| 189 } | 310 } |
| 190 let mut buffer = self.buffer.take().expect("No buffer?"); | 311 let mut buffer = self.buffer.take().expect("No buffer?"); |
| 191 let space = offset - self.bytes; | 312 let space = offset - self.bytes; |
| 192 buffer = &buffer[space..]; | 313 buffer = &buffer[space..]; |
| 314 // Make sure we can even read the bytes in the header |
| 315 if buffer.len() < mem::size_of::<u32>() { |
| 316 return Err(ValidationError::IllegalMemoryRange); |
| 317 } |
| 318 // Read the number of bytes in the memory region according to the data h
eader |
| 193 let mut read_size: u32 = 0; | 319 let mut read_size: u32 = 0; |
| 194 unsafe { | 320 unsafe { |
| 195 ptr::copy_nonoverlapping(mem::transmute::<*const u8, *const u32>(buf
fer.as_ptr()), | 321 ptr::copy_nonoverlapping(mem::transmute::<*const u8, *const u32>(buf
fer.as_ptr()), |
| 196 &mut read_size as *mut u32, | 322 &mut read_size as *mut u32, |
| 197 mem::size_of::<u32>()); | 323 mem::size_of::<u32>()); |
| 198 } | 324 } |
| 199 let size = u32::from_le(read_size) as usize; | 325 let size = u32::from_le(read_size) as usize; |
| 326 // Make sure the size we read is sane... |
| 327 if size > buffer.len() { |
| 328 return Err(ValidationError::IllegalMemoryRange); |
| 329 } |
| 200 // TODO(mknyszek): Check size for validation | 330 // TODO(mknyszek): Check size for validation |
| 201 let (claimed, unclaimed) = buffer.split_at(size); | 331 let (claimed, unclaimed) = buffer.split_at(size); |
| 202 self.states.push(DecodingState::new(claimed, offset)); | 332 self.states.push(DecodingState::new(claimed, offset)); |
| 203 self.buffer = Some(unclaimed); | 333 self.buffer = Some(unclaimed); |
| 204 self.bytes += space + size; | 334 self.bytes += space + size; |
| 205 Some(Context::new(self.states.len() - 1)) | 335 Ok(Context::new(self.states.len() - 1)) |
| 206 } | 336 } |
| 207 | 337 |
| 208 /// Claims a handle at some particular index in the given handles array. | 338 /// Claims a handle at some particular index in the given handles array. |
| 209 /// | 339 /// |
| 210 /// Returns the handle with all type information in-tact. | 340 /// Returns the handle with all type information in-tact. |
| 211 pub fn claim_handle<T: Handle + CastHandle>(&mut self, index: i32) -> T { | 341 pub fn claim_handle<T: Handle + CastHandle>(&mut self, index: i32) -> Result
<T, ValidationError> { |
| 212 let real_index = if index >= 0 { | 342 let real_index = if index >= 0 { |
| 213 index as usize | 343 index as usize |
| 214 } else { | 344 } else { |
| 215 panic!("Tried to claim null handle!"); | 345 return Err(ValidationError::UnexpectedInvalidHandle); |
| 216 }; | 346 }; |
| 217 // TODO(mknyszek): Check to make sure index is valid | 347 // If the index exceeds our number of handles or if we have already clai
med that handle |
| 348 if real_index >= self.handles.len() || real_index < self.handles_claimed
{ |
| 349 return Err(ValidationError::IllegalHandle); |
| 350 } |
| 351 self.handles_claimed = real_index + 1; |
| 218 let raw_handle = self.handles[real_index].get_native_handle(); | 352 let raw_handle = self.handles[real_index].get_native_handle(); |
| 219 unsafe { | 353 unsafe { |
| 220 // TODO(mknyszek): Return an error instead of panicking | |
| 221 self.handles[real_index].invalidate(); | 354 self.handles[real_index].invalidate(); |
| 222 T::from_untyped(system::acquire(raw_handle)) | 355 Ok(T::from_untyped(system::acquire(raw_handle))) |
| 223 } | 356 } |
| 224 } | 357 } |
| 225 | 358 |
| 226 /// Immutably borrow a decoding state via Context. | 359 /// Immutably borrow a decoding state via Context. |
| 227 pub fn get(&self, context: &Context) -> &DecodingState<'slice> { | 360 pub fn get(&self, context: &Context) -> &DecodingState<'slice> { |
| 228 &self.states[context.id()] | 361 &self.states[context.id()] |
| 229 } | 362 } |
| 230 | 363 |
| 231 /// Mutably borrow a decoding state via Context. | 364 /// Mutably borrow a decoding state via Context. |
| 232 pub fn get_mut(&mut self, context: &Context) -> &mut DecodingState<'slice> { | 365 pub fn get_mut(&mut self, context: &Context) -> &mut DecodingState<'slice> { |
| 233 &mut self.states[context.id()] | 366 &mut self.states[context.id()] |
| 234 } | 367 } |
| 235 } | 368 } |
| OLD | NEW |