Skip to content

Commit c6732bb

Browse files
authored
wasmparser: Enforce the implementation limits for subtyping depth (#1558)
Originally forgot about this one. Limit is defined here: https://webassembly.github.io/gc/js-api/index.html#limits
1 parent 4679411 commit c6732bb

5 files changed

Lines changed: 141 additions & 3 deletions

File tree

crates/wasmparser/src/limits.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub const MAX_WASM_TAGS: usize = 1_000_000;
3737
pub const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE;
3838
pub const MAX_WASM_STRUCT_FIELDS: usize = 10_000;
3939
pub const MAX_WASM_CATCHES: usize = 10_000;
40+
pub const MAX_WASM_SUBTYPING_DEPTH: usize = 63;
4041

4142
pub const DEFAULT_WASM_PAGE_SIZE: u64 = 1 << 16;
4243

crates/wasmparser/src/validator/core.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ impl Module {
610610

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

613-
if let Some(supertype_index) = ty.supertype_idx {
613+
let depth = if let Some(supertype_index) = ty.supertype_idx {
614614
debug_assert!(supertype_index.is_canonical());
615615
let sup_id = self.at_packed_index(types, rec_group, supertype_index, offset)?;
616616
if types[sup_id].is_final {
@@ -619,7 +619,20 @@ impl Module {
619619
if !types.matches(id, sup_id) {
620620
bail!(offset, "sub type must match super type");
621621
}
622-
}
622+
let depth = types.get_subtyping_depth(sup_id) + 1;
623+
if usize::from(depth) > crate::limits::MAX_WASM_SUBTYPING_DEPTH {
624+
bail!(
625+
offset,
626+
"sub type hierarchy too deep: found depth {}, cannot exceed depth {}",
627+
depth,
628+
crate::limits::MAX_WASM_SUBTYPING_DEPTH,
629+
);
630+
}
631+
depth
632+
} else {
633+
0
634+
};
635+
types.set_subtyping_depth(id, depth);
623636

624637
Ok(())
625638
}

crates/wasmparser/src/validator/types.rs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2458,8 +2458,13 @@ pub struct TypeList {
24582458
core_type_to_rec_group: SnapshotList<RecGroupId>,
24592459
// The supertype of each core type.
24602460
//
2461-
// A secondary map from `coreTypeId` to `Option<CoreTypeId>`.
2461+
// A secondary map from `CoreTypeId` to `Option<CoreTypeId>`.
24622462
core_type_to_supertype: SnapshotList<Option<CoreTypeId>>,
2463+
// The subtyping depth of each core type. We use `u8::MAX` as a sentinel for
2464+
// an uninitialized entry.
2465+
//
2466+
// A secondary map from `CoreTypeId` to `u8`.
2467+
core_type_to_depth: Option<IndexMap<CoreTypeId, u8>>,
24632468
// A primary map from `RecGroupId` to the range of the rec group's elements
24642469
// within `core_types`.
24652470
rec_group_elements: SnapshotList<Range<CoreTypeId>>,
@@ -2499,6 +2504,7 @@ struct TypeListCheckpoint {
24992504
core_instances: usize,
25002505
core_type_to_rec_group: usize,
25012506
core_type_to_supertype: usize,
2507+
core_type_to_depth: usize,
25022508
rec_group_elements: usize,
25032509
canonical_rec_groups: usize,
25042510
}
@@ -2614,6 +2620,29 @@ impl TypeList {
26142620
self.core_type_to_supertype[id.index()]
26152621
}
26162622

2623+
/// Get the subtyping depth of the given type. A type without any supertype
2624+
/// has depth 0.
2625+
pub fn get_subtyping_depth(&self, id: CoreTypeId) -> u8 {
2626+
let depth = self
2627+
.core_type_to_depth
2628+
.as_ref()
2629+
.expect("cannot get subtype depth from a committed list")[id.index()];
2630+
debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
2631+
depth
2632+
}
2633+
2634+
/// Set the subtyping depth of the given type. This may only be done once
2635+
/// per type.
2636+
pub fn set_subtyping_depth(&mut self, id: CoreTypeId, depth: u8) {
2637+
debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
2638+
let map = self
2639+
.core_type_to_depth
2640+
.as_mut()
2641+
.expect("cannot set a subtype depth in a committed list");
2642+
debug_assert!(!map.contains_key(&id));
2643+
map.insert(id, depth);
2644+
}
2645+
26172646
/// Get the `CoreTypeId` for a canonicalized `PackedIndex`.
26182647
///
26192648
/// Panics when given a non-canonicalized `PackedIndex`.
@@ -2827,6 +2856,7 @@ impl TypeList {
28272856
core_instances,
28282857
core_type_to_rec_group,
28292858
core_type_to_supertype,
2859+
core_type_to_depth,
28302860
rec_group_elements,
28312861
canonical_rec_groups,
28322862
} = self;
@@ -2842,6 +2872,7 @@ impl TypeList {
28422872
core_instances: core_instances.len(),
28432873
core_type_to_rec_group: core_type_to_rec_group.len(),
28442874
core_type_to_supertype: core_type_to_supertype.len(),
2875+
core_type_to_depth: core_type_to_depth.as_ref().map(|m| m.len()).unwrap_or(0),
28452876
rec_group_elements: rec_group_elements.len(),
28462877
canonical_rec_groups: canonical_rec_groups.as_ref().map(|m| m.len()).unwrap_or(0),
28472878
}
@@ -2862,6 +2893,7 @@ impl TypeList {
28622893
core_instances,
28632894
core_type_to_rec_group,
28642895
core_type_to_supertype,
2896+
core_type_to_depth,
28652897
rec_group_elements,
28662898
canonical_rec_groups,
28672899
} = self;
@@ -2878,6 +2910,14 @@ impl TypeList {
28782910
core_type_to_supertype.truncate(checkpoint.core_type_to_supertype);
28792911
rec_group_elements.truncate(checkpoint.rec_group_elements);
28802912

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

0 commit comments

Comments
 (0)