Skip to content

Commit 9c2c635

Browse files
authored
Add max nest level limit to yaml parser (#5275)
This fixes an oom issue found in fuzzing run.
1 parent b57977b commit 9c2c635

File tree

5 files changed

+131
-0
lines changed

5 files changed

+131
-0
lines changed

src/AppInstallerCLITests/AppInstallerCLITests.vcxproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,9 @@
10401040
<CopyFileToFolders Include="TestData\ContainsEscapeControlCode.yaml">
10411041
<DeploymentContent>true</DeploymentContent>
10421042
</CopyFileToFolders>
1043+
<CopyFileToFolders Include="TestData\ContainsTooManyNestedLayers.yaml">
1044+
<DeploymentContent>true</DeploymentContent>
1045+
</CopyFileToFolders>
10431046
<CopyFileToFolders Include="TestData\ManifestV1_10-Bad-SchemaHeaderInvalid.yaml">
10441047
<DeploymentContent>true</DeploymentContent>
10451048
</CopyFileToFolders>

src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,9 @@
10531053
<CopyFileToFolders Include="TestData\ContainsEscapeControlCode.yaml">
10541054
<Filter>TestData</Filter>
10551055
</CopyFileToFolders>
1056+
<CopyFileToFolders Include="TestData\ContainsTooManyNestedLayers.yaml">
1057+
<Filter>TestData</Filter>
1058+
</CopyFileToFolders>
10561059
<CopyFileToFolders Include="TestData\ManifestV1_10-Bad-SchemaHeaderInvalid.yaml">
10571060
<Filter>TestData</Filter>
10581061
</CopyFileToFolders>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
-
2+
-
3+
-
4+
-
5+
-
6+
-
7+
-
8+
-
9+
-
10+
-
11+
-
12+
-
13+
-
14+
-
15+
-
16+
-
17+
-
18+
-
19+
-
20+
-
21+
-
22+
-
23+
-
24+
-
25+
-
26+
-
27+
-
28+
-
29+
-
30+
-
31+
-
32+
-
33+
-
34+
-
35+
-
36+
-
37+
-
38+
-
39+
-
40+
-
41+
-
42+
-
43+
-
44+
-
45+
-
46+
-
47+
-
48+
-
49+
-
50+
-
51+
-
52+
-
53+
-
54+
-
55+
-
56+
-
57+
-
58+
-
59+
-
60+
-
61+
-
62+
-
63+
-
64+
-
65+
-
66+
-
67+
-
68+
-
69+
-
70+
-
71+
-
72+
-
73+
-
74+
-
75+
-
76+
-
77+
-
78+
-
79+
-
80+
-
81+
-
82+
-
83+
-
84+
-
85+
-
86+
-
87+
-
88+
-
89+
-
90+
-
91+
-
92+
-
93+
-
94+
-
95+
-
96+
-
97+
-
98+
-
99+
-
100+
-
101+
- value

src/AppInstallerCLITests/Yaml.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,8 @@ TEST_CASE("YamlContainsEscapeControlCode", "[YAML]")
173173
{
174174
REQUIRE_THROWS_HR(Load(TestDataFile("ContainsEscapeControlCode.yaml")), APPINSTALLER_CLI_ERROR_LIBYAML_ERROR);
175175
}
176+
177+
TEST_CASE("YamlContainsTooManyNestedLayers", "[YAML]")
178+
{
179+
REQUIRE_THROWS_HR(Load(TestDataFile("ContainsTooManyNestedLayers.yaml")), APPINSTALLER_CLI_ERROR_YAML_DOC_BUILD_FAILED);
180+
}

src/AppInstallerSharedLib/YamlWrapper.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ namespace AppInstaller::YAML::Wrapper
151151
size_t childOffset = 0;
152152
};
153153

154+
static int YAML_DOCUMENT_NEST_LEVEL_LIMIT = 100;
155+
int nestLevel = 0;
156+
154157
std::stack<StackItem> resultStack;
155158
resultStack.emplace(root, &result);
156159

@@ -173,6 +176,12 @@ namespace AppInstaller::YAML::Wrapper
173176
break;
174177
case YAML_SEQUENCE_NODE:
175178
{
179+
if (stackItem.childOffset == 0)
180+
{
181+
// We've entered the sequence.
182+
nestLevel++;
183+
}
184+
176185
yaml_node_item_t* child = stackItem.yamlNode->data.sequence.items.start + stackItem.childOffset++;
177186
if (child < stackItem.yamlNode->data.sequence.items.top)
178187
{
@@ -184,11 +193,18 @@ namespace AppInstaller::YAML::Wrapper
184193
{
185194
// We've reached the end of the sequence
186195
pop = true;
196+
nestLevel--;
187197
}
188198
break;
189199
}
190200
case YAML_MAPPING_NODE:
191201
{
202+
if (stackItem.childOffset == 0)
203+
{
204+
// We've entered the mapping.
205+
nestLevel++;
206+
}
207+
192208
yaml_node_pair_t* child = stackItem.yamlNode->data.mapping.pairs.start + stackItem.childOffset++;
193209
if (child < stackItem.yamlNode->data.mapping.pairs.top)
194210
{
@@ -207,6 +223,7 @@ namespace AppInstaller::YAML::Wrapper
207223
{
208224
// We've reached the end of the mapping
209225
pop = true;
226+
nestLevel--;
210227
}
211228
break;
212229
}
@@ -216,6 +233,8 @@ namespace AppInstaller::YAML::Wrapper
216233
{
217234
resultStack.pop();
218235
}
236+
237+
THROW_HR_IF_MSG(APPINSTALLER_CLI_ERROR_YAML_DOC_BUILD_FAILED, nestLevel > YAML_DOCUMENT_NEST_LEVEL_LIMIT, "Too many layers of nested nodes.");
219238
}
220239

221240
return result;

0 commit comments

Comments
 (0)