Skip to content

Commit

Permalink
Verify meta layers aren't recursive to any depth
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
charles-lunarg committed Dec 10, 2024
1 parent c331688 commit eab3603
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 11 deletions.
41 changes: 30 additions & 11 deletions loader/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -2165,10 +2165,24 @@ void loader_get_fullpath(const char *file, const char *in_dirs, size_t out_size,
}

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

if (NULL == already_checked_meta_layers) {
already_checked_meta_layers = loader_stack_alloc(sizeof(bool) * instance_layers->count);
if (already_checked_meta_layers == NULL) {
return false;
}
memset(already_checked_meta_layers, 0, sizeof(bool) * instance_layers->count);
}

// Mark this meta layer as 'already checked', indicating which layers have already been recursed.
already_checked_meta_layers[prop_index] = true;

for (uint32_t comp_layer = 0; comp_layer < prop->component_layer_names.count; comp_layer++) {
struct loader_layer_properties *comp_prop =
loader_find_layer_property(prop->component_layer_names.list[comp_layer], instance_layers);
Expand Down Expand Up @@ -2203,22 +2217,27 @@ bool verify_meta_layer_component_layers(const struct loader_instance *inst, stru
return false;
}
if (comp_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
for (uint32_t sub_comp_layer = 0; sub_comp_layer < comp_prop->component_layer_names.count; sub_comp_layer++) {
if (!strcmp(prop->info.layerName, comp_prop->component_layer_names.list[sub_comp_layer])) {
loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
"verify_meta_layer_component_layers: Recursive depedency between Meta-layer %s and Meta-layer %s. "
"Skipping this layer.",
prop->info.layerName, prop->component_layer_names.list[comp_layer]);
return false;
size_t comp_prop_index = INT32_MAX;
// Make sure we haven't verified this meta layer before
for (uint32_t i = 0; i < instance_layers->count; i++) {
if (strcmp(comp_prop->info.layerName, instance_layers->list[i].info.layerName) == 0) {
comp_prop_index = i;
}
}
if (comp_prop_index != INT32_MAX && already_checked_meta_layers[comp_prop_index]) {
loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
"verify_meta_layer_component_layers: Recursive depedency between Meta-layer %s and Meta-layer %s. "
"Skipping this layer.",
instance_layers->list[prop_index].info.layerName, comp_prop->info.layerName);
return false;
}

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

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

// If this is a meta-layer, make sure it is valid
if (prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
if (verify_meta_layer_component_layers(inst, prop, instance_layers)) {
if (verify_meta_layer_component_layers(inst, i, instance_layers, NULL)) {
// If any meta layer is valid, update its extension list to include the extensions from its component layers.
res = update_meta_layer_extensions_from_component_layers(inst, prop, instance_layers);
if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
Expand Down
Binary file not shown.
5 changes: 5 additions & 0 deletions tests/loader_fuzz_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ TEST(BadJsonInput, ClusterFuzzTestCase_5801855065915392) {
// Causes a leak - instance_create_fuzzer: Direct-leak in print_string_ptr
execute_instance_create_fuzzer("clusterfuzz-testcase-minimized-instance_create_fuzzer-5801855065915392");
}
TEST(BadJsonInput, ClusterFuzzTestCase_6353004288081920) {
// Does crash with ASAN and UBSAN
// Stack overflow due to recursive meta layers
execute_instance_create_fuzzer("clusterfuzz-testcase-minimized-instance_create_fuzzer-6353004288081920");
}
TEST(BadJsonInput, ClusterFuzzTestCase_6465902356791296) {
// Does crash with UBSAN
// Doesn't crash with ASAN
Expand Down

0 comments on commit eab3603

Please sign in to comment.