Skip to content

Commit eab3603

Browse files
Verify meta layers aren't recursive to any depth
By keeping track of which layers have already been processed, the loader will now catch a recursive meta layers to any arbitrary depth. This prevents stack overflows in verify_meta_layer_component_layers due to the recurive nature of the function.
1 parent c331688 commit eab3603

File tree

3 files changed

+35
-11
lines changed

3 files changed

+35
-11
lines changed

loader/loader.c

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2165,10 +2165,24 @@ void loader_get_fullpath(const char *file, const char *in_dirs, size_t out_size,
21652165
}
21662166

21672167
// Verify that all component layers in a meta-layer are valid.
2168-
bool verify_meta_layer_component_layers(const struct loader_instance *inst, struct loader_layer_properties *prop,
2169-
struct loader_layer_list *instance_layers) {
2168+
// This function is potentially recursive so we pass in an array of "already checked" (length of the instance_layers->count) meta
2169+
// layers, preventing a stack overflow verifying meta layers that are each other's component layers
2170+
bool verify_meta_layer_component_layers(const struct loader_instance *inst, size_t prop_index,
2171+
struct loader_layer_list *instance_layers, bool *already_checked_meta_layers) {
2172+
struct loader_layer_properties *prop = &instance_layers->list[prop_index];
21702173
loader_api_version meta_layer_version = loader_make_version(prop->info.specVersion);
21712174

2175+
if (NULL == already_checked_meta_layers) {
2176+
already_checked_meta_layers = loader_stack_alloc(sizeof(bool) * instance_layers->count);
2177+
if (already_checked_meta_layers == NULL) {
2178+
return false;
2179+
}
2180+
memset(already_checked_meta_layers, 0, sizeof(bool) * instance_layers->count);
2181+
}
2182+
2183+
// Mark this meta layer as 'already checked', indicating which layers have already been recursed.
2184+
already_checked_meta_layers[prop_index] = true;
2185+
21722186
for (uint32_t comp_layer = 0; comp_layer < prop->component_layer_names.count; comp_layer++) {
21732187
struct loader_layer_properties *comp_prop =
21742188
loader_find_layer_property(prop->component_layer_names.list[comp_layer], instance_layers);
@@ -2203,22 +2217,27 @@ bool verify_meta_layer_component_layers(const struct loader_instance *inst, stru
22032217
return false;
22042218
}
22052219
if (comp_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
2206-
for (uint32_t sub_comp_layer = 0; sub_comp_layer < comp_prop->component_layer_names.count; sub_comp_layer++) {
2207-
if (!strcmp(prop->info.layerName, comp_prop->component_layer_names.list[sub_comp_layer])) {
2208-
loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2209-
"verify_meta_layer_component_layers: Recursive depedency between Meta-layer %s and Meta-layer %s. "
2210-
"Skipping this layer.",
2211-
prop->info.layerName, prop->component_layer_names.list[comp_layer]);
2212-
return false;
2220+
size_t comp_prop_index = INT32_MAX;
2221+
// Make sure we haven't verified this meta layer before
2222+
for (uint32_t i = 0; i < instance_layers->count; i++) {
2223+
if (strcmp(comp_prop->info.layerName, instance_layers->list[i].info.layerName) == 0) {
2224+
comp_prop_index = i;
22132225
}
22142226
}
2227+
if (comp_prop_index != INT32_MAX && already_checked_meta_layers[comp_prop_index]) {
2228+
loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2229+
"verify_meta_layer_component_layers: Recursive depedency between Meta-layer %s and Meta-layer %s. "
2230+
"Skipping this layer.",
2231+
instance_layers->list[prop_index].info.layerName, comp_prop->info.layerName);
2232+
return false;
2233+
}
22152234

22162235
loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
22172236
"verify_meta_layer_component_layers: Adding meta-layer %s which also contains meta-layer %s",
22182237
prop->info.layerName, comp_prop->info.layerName);
22192238

22202239
// Make sure if the layer is using a meta-layer in its component list that we also verify that.
2221-
if (!verify_meta_layer_component_layers(inst, comp_prop, instance_layers)) {
2240+
if (!verify_meta_layer_component_layers(inst, comp_prop_index, instance_layers, already_checked_meta_layers)) {
22222241
loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
22232242
"Meta-layer %s component layer %s can not find all component layers."
22242243
" Skipping this layer.",
@@ -2292,7 +2311,7 @@ VkResult verify_all_meta_layers(struct loader_instance *inst, const struct loade
22922311

22932312
// If this is a meta-layer, make sure it is valid
22942313
if (prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
2295-
if (verify_meta_layer_component_layers(inst, prop, instance_layers)) {
2314+
if (verify_meta_layer_component_layers(inst, i, instance_layers, NULL)) {
22962315
// If any meta layer is valid, update its extension list to include the extensions from its component layers.
22972316
res = update_meta_layer_extensions_from_component_layers(inst, prop, instance_layers);
22982317
if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {

tests/loader_fuzz_tests.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ TEST(BadJsonInput, ClusterFuzzTestCase_5801855065915392) {
168168
// Causes a leak - instance_create_fuzzer: Direct-leak in print_string_ptr
169169
execute_instance_create_fuzzer("clusterfuzz-testcase-minimized-instance_create_fuzzer-5801855065915392");
170170
}
171+
TEST(BadJsonInput, ClusterFuzzTestCase_6353004288081920) {
172+
// Does crash with ASAN and UBSAN
173+
// Stack overflow due to recursive meta layers
174+
execute_instance_create_fuzzer("clusterfuzz-testcase-minimized-instance_create_fuzzer-6353004288081920");
175+
}
171176
TEST(BadJsonInput, ClusterFuzzTestCase_6465902356791296) {
172177
// Does crash with UBSAN
173178
// Doesn't crash with ASAN

0 commit comments

Comments
 (0)