Skip to content

Commit a3d1bb1

Browse files
authored
contracts: Prevent contracts from allocating a too large buffer (#7818)
* Prevent contracts from allocating a too large buffer * Fix possible integer overflow
1 parent e97f753 commit a3d1bb1

File tree

2 files changed

+23
-11
lines changed

2 files changed

+23
-11
lines changed

src/schedule.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ pub struct Limits {
110110
pub code_size: u32,
111111
}
112112

113+
impl Limits {
114+
/// The maximum memory size in bytes that a contract can occupy.
115+
pub fn max_memory_size(&self) -> u32 {
116+
self.memory_pages * 64 * 1024
117+
}
118+
}
119+
113120
/// Describes the weight for all categories of supported wasm instructions.
114121
///
115122
/// There there is one field for each wasm instruction that describes the weight to

src/wasm/runtime.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@ use crate::{
2323
gas::{Gas, GasMeter, Token, GasMeterResult, ChargedAmount},
2424
wasm::env_def::ConvertibleToWasm,
2525
};
26-
use sp_sandbox;
2726
use parity_wasm::elements::ValueType;
28-
use frame_system;
29-
use frame_support::dispatch::DispatchError;
27+
use frame_support::{dispatch::DispatchError, ensure};
3028
use sp_std::prelude::*;
3129
use codec::{Decode, DecodeAll, Encode};
3230
use sp_runtime::traits::SaturatedConversion;
@@ -420,6 +418,7 @@ where
420418
pub fn read_sandbox_memory(&self, ptr: u32, len: u32)
421419
-> Result<Vec<u8>, DispatchError>
422420
{
421+
ensure!(len <= self.schedule.limits.max_memory_size(), Error::<E::T>::OutOfBounds);
423422
let mut buf = vec![0u8; len as usize];
424423
self.memory.get(ptr, buf.as_mut_slice())
425424
.map_err(|_| Error::<E::T>::OutOfBounds)?;
@@ -1179,17 +1178,23 @@ define_env!(Env, <E: Ext>,
11791178
let rent_allowance: BalanceOf<<E as Ext>::T> =
11801179
ctx.read_sandbox_memory_as(rent_allowance_ptr, rent_allowance_len)?;
11811180
let delta = {
1181+
const KEY_SIZE: usize = 32;
1182+
11821183
// We can eagerly allocate because we charged for the complete delta count already
1183-
let mut delta = Vec::with_capacity(delta_count as usize);
1184+
// We still need to make sure that the allocation isn't larger than the memory
1185+
// allocator can handle.
1186+
ensure!(
1187+
delta_count
1188+
.saturating_mul(KEY_SIZE as u32) <= ctx.schedule.limits.max_memory_size(),
1189+
Error::<E::T>::OutOfBounds,
1190+
);
1191+
let mut delta = vec![[0; KEY_SIZE]; delta_count as usize];
11841192
let mut key_ptr = delta_ptr;
11851193

1186-
for _ in 0..delta_count {
1187-
const KEY_SIZE: usize = 32;
1188-
1189-
// Read the delta into the provided buffer and collect it into the buffer.
1190-
let mut delta_key: StorageKey = [0; KEY_SIZE];
1191-
ctx.read_sandbox_memory_into_buf(key_ptr, &mut delta_key)?;
1192-
delta.push(delta_key);
1194+
for i in 0..delta_count {
1195+
// Read the delta into the provided buffer
1196+
// This cannot panic because of the loop condition
1197+
ctx.read_sandbox_memory_into_buf(key_ptr, &mut delta[i as usize])?;
11931198

11941199
// Offset key_ptr to the next element.
11951200
key_ptr = key_ptr.checked_add(KEY_SIZE as u32).ok_or(Error::<E::T>::OutOfBounds)?;

0 commit comments

Comments
 (0)