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