Skip to content

Commit 2d679c6

Browse files
sandreimalxiord
authored andcommitted
Implement limits for Vec, String.
Enforces a maximum byte limit both during serialization and deserialization. Currently we use hardcoded values, but in the future we need to make this configurable at run time. Signed-off-by: Andrei Sandu <[email protected]>
1 parent 801dd8e commit 2d679c6

File tree

4 files changed

+115
-9
lines changed

4 files changed

+115
-9
lines changed

coverage_config_aarch64.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"coverage_score": 92.7, "exclude_path": "", "crate_features": ""}
1+
{"coverage_score": 92.2, "exclude_path": "", "crate_features": ""}

coverage_config_x86_64.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"coverage_score": 93.2, "exclude_path": "", "crate_features": ""}
1+
{"coverage_score": 92.8, "exclude_path": "", "crate_features": ""}

src/lib.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ extern crate vm_memory;
2121
extern crate vmm_sys_util;
2222

2323
pub mod crc;
24-
mod primitives;
24+
pub mod primitives;
2525
pub mod version_map;
2626

2727
use std::any::TypeId;
@@ -40,16 +40,33 @@ pub enum VersionizeError {
4040
Deserialize(String),
4141
/// A user generated semantic error.
4242
Semantic(String),
43+
/// String length exceeded.
44+
StringLength(usize),
45+
/// Vector length exceeded.
46+
VecLength(usize),
4347
}
4448

4549
impl std::fmt::Display for VersionizeError {
4650
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
4751
use VersionizeError::*;
52+
4853
match self {
4954
Io(e) => write!(f, "An IO error occured: {}", e),
5055
Serialize(e) => write!(f, "A serialization error occured: {}", e),
5156
Deserialize(e) => write!(f, "A deserialization error occured: {}", e),
5257
Semantic(e) => write!(f, "A user generated semantic error occured: {}", e),
58+
StringLength(bad_len) => write!(
59+
f,
60+
"String length exceeded {} > {} bytes",
61+
bad_len,
62+
primitives::MAX_STRING_LEN
63+
),
64+
VecLength(bad_len) => write!(
65+
f,
66+
"Vec length exceeded {} > {} bytes",
67+
bad_len,
68+
primitives::MAX_VEC_LEN
69+
),
5370
}
5471
}
5572
}

src/primitives.rs

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3+
//! Serialization support for primitive data types.
34
#![allow(clippy::float_cmp)]
45

56
use self::super::{VersionMap, Versionize, VersionizeError, VersionizeResult};
67
use vmm_sys_util::fam::{FamStruct, FamStructWrapper};
78

9+
/// Maximum string len in bytes (16KB).
10+
pub const MAX_STRING_LEN: usize = 16384;
11+
/// Maximum vec len in bytes (10MB).
12+
pub const MAX_VEC_LEN: usize = 10_485_760;
13+
814
/// Implements the Versionize trait for primitive types that also implement
915
/// serde's Serialize/Deserialize: use serde_bincode as a backend for
1016
/// serialization.
@@ -60,7 +66,53 @@ impl_versionize!(u64);
6066
impl_versionize!(f32);
6167
impl_versionize!(f64);
6268
impl_versionize!(char);
63-
impl_versionize!(String);
69+
70+
impl Versionize for String {
71+
#[inline]
72+
fn serialize<W: std::io::Write>(
73+
&self,
74+
writer: &mut W,
75+
version_map: &VersionMap,
76+
app_version: u16,
77+
) -> VersionizeResult<()> {
78+
// It is better to fail early at serialization time.
79+
if self.len() > MAX_STRING_LEN {
80+
return Err(VersionizeError::StringLength(self.len()));
81+
}
82+
83+
self.len().serialize(writer, version_map, app_version)?;
84+
writer
85+
.write_all(self.as_bytes())
86+
.map_err(|e| VersionizeError::Io(e.raw_os_error().unwrap_or(0)))?;
87+
Ok(())
88+
}
89+
90+
#[inline]
91+
fn deserialize<R: std::io::Read>(
92+
mut reader: &mut R,
93+
version_map: &VersionMap,
94+
app_version: u16,
95+
) -> VersionizeResult<Self> {
96+
let len = usize::deserialize(&mut reader, version_map, app_version)?;
97+
// Even if we fail in serialize, we still need to enforce this on the hot path
98+
// in case the len is corrupted.
99+
if len > MAX_STRING_LEN {
100+
return Err(VersionizeError::StringLength(len));
101+
}
102+
103+
let mut v = vec![0u8; len];
104+
reader
105+
.read_exact(v.as_mut_slice())
106+
.map_err(|e| VersionizeError::Io(e.raw_os_error().unwrap_or(0)))?;
107+
Ok(String::from_utf8(v)
108+
.map_err(|err| VersionizeError::Deserialize(format!("Utf8 error: {:?}", err)))?)
109+
}
110+
111+
// Not used yet.
112+
fn version() -> u16 {
113+
1
114+
}
115+
}
64116

65117
macro_rules! impl_versionize_array_with_size {
66118
($ty:literal) => {
@@ -239,15 +291,17 @@ where
239291
version_map: &VersionMap,
240292
app_version: u16,
241293
) -> VersionizeResult<()> {
294+
let bytes_len = self.len() * std::mem::size_of::<T>();
295+
if bytes_len > MAX_VEC_LEN {
296+
return Err(VersionizeError::VecLength(bytes_len));
297+
}
242298
// Serialize in the same fashion as bincode:
243299
// Write len.
244300
bincode::serialize_into(&mut writer, &self.len())
245301
.map_err(|ref err| VersionizeError::Serialize(format!("{:?}", err)))?;
246-
// Walk the vec and write each elemenet.
302+
// Walk the vec and write each element.
247303
for element in self {
248-
element
249-
.serialize(writer, version_map, app_version)
250-
.map_err(|ref err| VersionizeError::Serialize(format!("{:?}", err)))?;
304+
element.serialize(writer, version_map, app_version)?;
251305
}
252306
Ok(())
253307
}
@@ -259,8 +313,14 @@ where
259313
app_version: u16,
260314
) -> VersionizeResult<Self> {
261315
let mut v = Vec::new();
262-
let len: u64 = bincode::deserialize_from(&mut reader)
316+
let len: usize = bincode::deserialize_from(&mut reader)
263317
.map_err(|ref err| VersionizeError::Deserialize(format!("{:?}", err)))?;
318+
319+
let bytes_len = len * std::mem::size_of::<T>();
320+
if bytes_len > MAX_VEC_LEN {
321+
return Err(VersionizeError::VecLength(bytes_len));
322+
}
323+
264324
for _ in 0..len {
265325
let element: T = T::deserialize(reader, version_map, app_version)
266326
.map_err(|ref err| VersionizeError::Deserialize(format!("{:?}", err)))?;
@@ -935,4 +995,33 @@ mod tests {
935995
);
936996
assert_eq!(original_values, restored_values);
937997
}
998+
999+
#[test]
1000+
fn test_vec_limit() {
1001+
// We need extra 8 bytes for vector len.
1002+
let mut snapshot_mem = vec![0u8; MAX_VEC_LEN + 8];
1003+
let err = vec![123u8; MAX_VEC_LEN + 1]
1004+
.serialize(&mut snapshot_mem.as_mut_slice(), &VersionMap::new(), 1)
1005+
.unwrap_err();
1006+
assert_eq!(err, VersionizeError::VecLength(MAX_VEC_LEN + 1));
1007+
assert_eq!(
1008+
format!("{}", err),
1009+
"Vec length exceeded 10485761 > 10485760 bytes"
1010+
);
1011+
}
1012+
1013+
#[test]
1014+
fn test_string_limit() {
1015+
// We need extra 8 bytes for string len.
1016+
let mut snapshot_mem = vec![0u8; MAX_STRING_LEN + 8];
1017+
let err = String::from_utf8(vec![123u8; MAX_STRING_LEN + 1])
1018+
.unwrap()
1019+
.serialize(&mut snapshot_mem.as_mut_slice(), &VersionMap::new(), 1)
1020+
.unwrap_err();
1021+
assert_eq!(err, VersionizeError::StringLength(MAX_STRING_LEN + 1));
1022+
assert_eq!(
1023+
format!("{}", err),
1024+
"String length exceeded 16385 > 16384 bytes"
1025+
);
1026+
}
9381027
}

0 commit comments

Comments
 (0)