Skip to content

Commit

Permalink
wasmparser: Enforce the implementation limits for subtyping depth (#1558
Browse files Browse the repository at this point in the history
)

Originally forgot about this one.

Limit is defined here: https://webassembly.github.io/gc/js-api/index.html#limits
  • Loading branch information
fitzgen authored May 14, 2024
1 parent 4679411 commit c6732bb
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 3 deletions.
1 change: 1 addition & 0 deletions crates/wasmparser/src/limits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub const MAX_WASM_TAGS: usize = 1_000_000;
pub const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE;
pub const MAX_WASM_STRUCT_FIELDS: usize = 10_000;
pub const MAX_WASM_CATCHES: usize = 10_000;
pub const MAX_WASM_SUBTYPING_DEPTH: usize = 63;

pub const DEFAULT_WASM_PAGE_SIZE: u64 = 1 << 16;

Expand Down
17 changes: 15 additions & 2 deletions crates/wasmparser/src/validator/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ impl Module {

self.check_composite_type(&ty.composite_type, features, offset)?;

if let Some(supertype_index) = ty.supertype_idx {
let depth = if let Some(supertype_index) = ty.supertype_idx {
debug_assert!(supertype_index.is_canonical());
let sup_id = self.at_packed_index(types, rec_group, supertype_index, offset)?;
if types[sup_id].is_final {
Expand All @@ -619,7 +619,20 @@ impl Module {
if !types.matches(id, sup_id) {
bail!(offset, "sub type must match super type");
}
}
let depth = types.get_subtyping_depth(sup_id) + 1;
if usize::from(depth) > crate::limits::MAX_WASM_SUBTYPING_DEPTH {
bail!(
offset,
"sub type hierarchy too deep: found depth {}, cannot exceed depth {}",
depth,
crate::limits::MAX_WASM_SUBTYPING_DEPTH,
);
}
depth
} else {
0
};
types.set_subtyping_depth(id, depth);

Ok(())
}
Expand Down
44 changes: 43 additions & 1 deletion crates/wasmparser/src/validator/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2458,8 +2458,13 @@ pub struct TypeList {
core_type_to_rec_group: SnapshotList<RecGroupId>,
// The supertype of each core type.
//
// A secondary map from `coreTypeId` to `Option<CoreTypeId>`.
// A secondary map from `CoreTypeId` to `Option<CoreTypeId>`.
core_type_to_supertype: SnapshotList<Option<CoreTypeId>>,
// The subtyping depth of each core type. We use `u8::MAX` as a sentinel for
// an uninitialized entry.
//
// A secondary map from `CoreTypeId` to `u8`.
core_type_to_depth: Option<IndexMap<CoreTypeId, u8>>,
// A primary map from `RecGroupId` to the range of the rec group's elements
// within `core_types`.
rec_group_elements: SnapshotList<Range<CoreTypeId>>,
Expand Down Expand Up @@ -2499,6 +2504,7 @@ struct TypeListCheckpoint {
core_instances: usize,
core_type_to_rec_group: usize,
core_type_to_supertype: usize,
core_type_to_depth: usize,
rec_group_elements: usize,
canonical_rec_groups: usize,
}
Expand Down Expand Up @@ -2614,6 +2620,29 @@ impl TypeList {
self.core_type_to_supertype[id.index()]
}

/// Get the subtyping depth of the given type. A type without any supertype
/// has depth 0.
pub fn get_subtyping_depth(&self, id: CoreTypeId) -> u8 {
let depth = self
.core_type_to_depth
.as_ref()
.expect("cannot get subtype depth from a committed list")[id.index()];
debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
depth
}

/// Set the subtyping depth of the given type. This may only be done once
/// per type.
pub fn set_subtyping_depth(&mut self, id: CoreTypeId, depth: u8) {
debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
let map = self
.core_type_to_depth
.as_mut()
.expect("cannot set a subtype depth in a committed list");
debug_assert!(!map.contains_key(&id));
map.insert(id, depth);
}

/// Get the `CoreTypeId` for a canonicalized `PackedIndex`.
///
/// Panics when given a non-canonicalized `PackedIndex`.
Expand Down Expand Up @@ -2827,6 +2856,7 @@ impl TypeList {
core_instances,
core_type_to_rec_group,
core_type_to_supertype,
core_type_to_depth,
rec_group_elements,
canonical_rec_groups,
} = self;
Expand All @@ -2842,6 +2872,7 @@ impl TypeList {
core_instances: core_instances.len(),
core_type_to_rec_group: core_type_to_rec_group.len(),
core_type_to_supertype: core_type_to_supertype.len(),
core_type_to_depth: core_type_to_depth.as_ref().map(|m| m.len()).unwrap_or(0),
rec_group_elements: rec_group_elements.len(),
canonical_rec_groups: canonical_rec_groups.as_ref().map(|m| m.len()).unwrap_or(0),
}
Expand All @@ -2862,6 +2893,7 @@ impl TypeList {
core_instances,
core_type_to_rec_group,
core_type_to_supertype,
core_type_to_depth,
rec_group_elements,
canonical_rec_groups,
} = self;
Expand All @@ -2878,6 +2910,14 @@ impl TypeList {
core_type_to_supertype.truncate(checkpoint.core_type_to_supertype);
rec_group_elements.truncate(checkpoint.rec_group_elements);

if let Some(core_type_to_depth) = core_type_to_depth {
assert_eq!(
core_type_to_depth.len(),
checkpoint.core_type_to_depth,
"checkpointing does not support resetting `core_type_to_depth` (it would require a \
proper immutable and persistent hash map) so adding new groups is disallowed"
);
}
if let Some(canonical_rec_groups) = canonical_rec_groups {
assert_eq!(
canonical_rec_groups.len(),
Expand Down Expand Up @@ -2914,6 +2954,7 @@ impl TypeList {
core_instances: self.core_instances.commit(),
core_type_to_rec_group: self.core_type_to_rec_group.commit(),
core_type_to_supertype: self.core_type_to_supertype.commit(),
core_type_to_depth: None,
rec_group_elements: self.rec_group_elements.commit(),
canonical_rec_groups: None,
}
Expand Down Expand Up @@ -3006,6 +3047,7 @@ impl Default for TypeAlloc {
},
next_resource_id: 0,
};
ret.list.core_type_to_depth = Some(Default::default());
ret.list.canonical_rec_groups = Some(Default::default());
ret
}
Expand Down
70 changes: 70 additions & 0 deletions tests/local/gc/gc-subtyping-too-deep.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
(assert_invalid
(module
(type (;0;) (sub (struct)))
(type (;1;) (sub 0 (struct)))
(type (;2;) (sub 1 (struct)))
(type (;3;) (sub 2 (struct)))
(type (;4;) (sub 3 (struct)))
(type (;5;) (sub 4 (struct)))
(type (;6;) (sub 5 (struct)))
(type (;7;) (sub 6 (struct)))
(type (;8;) (sub 7 (struct)))
(type (;9;) (sub 8 (struct)))
(type (;10;) (sub 9 (struct)))
(type (;11;) (sub 10 (struct)))
(type (;12;) (sub 11 (struct)))
(type (;13;) (sub 12 (struct)))
(type (;14;) (sub 13 (struct)))
(type (;15;) (sub 14 (struct)))
(type (;16;) (sub 15 (struct)))
(type (;17;) (sub 16 (struct)))
(type (;18;) (sub 17 (struct)))
(type (;19;) (sub 18 (struct)))
(type (;20;) (sub 19 (struct)))
(type (;21;) (sub 20 (struct)))
(type (;22;) (sub 21 (struct)))
(type (;23;) (sub 22 (struct)))
(type (;24;) (sub 23 (struct)))
(type (;25;) (sub 24 (struct)))
(type (;26;) (sub 25 (struct)))
(type (;27;) (sub 26 (struct)))
(type (;28;) (sub 27 (struct)))
(type (;29;) (sub 28 (struct)))
(type (;30;) (sub 29 (struct)))
(type (;31;) (sub 30 (struct)))
(type (;32;) (sub 31 (struct)))
(type (;33;) (sub 32 (struct)))
(type (;34;) (sub 33 (struct)))
(type (;35;) (sub 34 (struct)))
(type (;36;) (sub 35 (struct)))
(type (;37;) (sub 36 (struct)))
(type (;38;) (sub 37 (struct)))
(type (;39;) (sub 38 (struct)))
(type (;40;) (sub 39 (struct)))
(type (;41;) (sub 40 (struct)))
(type (;42;) (sub 41 (struct)))
(type (;43;) (sub 42 (struct)))
(type (;44;) (sub 43 (struct)))
(type (;45;) (sub 44 (struct)))
(type (;46;) (sub 45 (struct)))
(type (;47;) (sub 46 (struct)))
(type (;48;) (sub 47 (struct)))
(type (;49;) (sub 48 (struct)))
(type (;50;) (sub 49 (struct)))
(type (;51;) (sub 50 (struct)))
(type (;52;) (sub 51 (struct)))
(type (;53;) (sub 52 (struct)))
(type (;54;) (sub 53 (struct)))
(type (;55;) (sub 54 (struct)))
(type (;56;) (sub 55 (struct)))
(type (;57;) (sub 56 (struct)))
(type (;58;) (sub 57 (struct)))
(type (;59;) (sub 58 (struct)))
(type (;60;) (sub 59 (struct)))
(type (;61;) (sub 60 (struct)))
(type (;62;) (sub 61 (struct)))
(type (;63;) (sub 62 (struct)))
(type (;64;) (sub 63 (struct)))
)
"sub type hierarchy too deep: found depth 64, cannot exceed depth 63"
)
12 changes: 12 additions & 0 deletions tests/snapshots/local/gc/gc-subtyping-too-deep.wast.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"source_filename": "tests/local/gc/gc-subtyping-too-deep.wast",
"commands": [
{
"type": "assert_invalid",
"line": 2,
"filename": "gc-subtyping-too-deep.0.wasm",
"text": "sub type hierarchy too deep: found depth 64, cannot exceed depth 63",
"module_type": "binary"
}
]
}

0 comments on commit c6732bb

Please sign in to comment.