15db71995Sopenharmony_ci/*
25db71995Sopenharmony_ci *
35db71995Sopenharmony_ci * Copyright (c) 2014-2023 The Khronos Group Inc.
45db71995Sopenharmony_ci * Copyright (c) 2014-2023 Valve Corporation
55db71995Sopenharmony_ci * Copyright (c) 2014-2023 LunarG, Inc.
65db71995Sopenharmony_ci *
75db71995Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
85db71995Sopenharmony_ci * you may not use this file except in compliance with the License.
95db71995Sopenharmony_ci * You may obtain a copy of the License at
105db71995Sopenharmony_ci *
115db71995Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
125db71995Sopenharmony_ci *
135db71995Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
145db71995Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
155db71995Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
165db71995Sopenharmony_ci * See the License for the specific language governing permissions and
175db71995Sopenharmony_ci * limitations under the License.
185db71995Sopenharmony_ci *
195db71995Sopenharmony_ci * Author: Jon Ashburn <jon@lunarg.com>
205db71995Sopenharmony_ci * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
215db71995Sopenharmony_ci * Author: Chia-I Wu <olvaffe@gmail.com>
225db71995Sopenharmony_ci * Author: Chia-I Wu <olv@lunarg.com>
235db71995Sopenharmony_ci * Author: Mark Lobodzinski <mark@LunarG.com>
245db71995Sopenharmony_ci * Author: Lenny Komow <lenny@lunarg.com>
255db71995Sopenharmony_ci * Author: Charles Giessen <charles@lunarg.com>
265db71995Sopenharmony_ci *
275db71995Sopenharmony_ci */
285db71995Sopenharmony_ci
295db71995Sopenharmony_ci#include "loader_environment.h"
305db71995Sopenharmony_ci
315db71995Sopenharmony_ci#include "allocation.h"
325db71995Sopenharmony_ci#include "loader.h"
335db71995Sopenharmony_ci#include "log.h"
345db71995Sopenharmony_ci
355db71995Sopenharmony_ci#include <ctype.h>
365db71995Sopenharmony_ci#include "param/sys_param.h"
375db71995Sopenharmony_ci
385db71995Sopenharmony_ci// Environment variables
395db71995Sopenharmony_ci#if COMMON_UNIX_PLATFORMS
405db71995Sopenharmony_ci
415db71995Sopenharmony_cibool is_high_integrity() { return geteuid() != getuid() || getegid() != getgid(); }
425db71995Sopenharmony_ci
435db71995Sopenharmony_cichar *loader_getenv(const char *name, const struct loader_instance *inst) {
445db71995Sopenharmony_ci    if (NULL == name) return NULL;
455db71995Sopenharmony_ci#if defined(__OHOS__)
465db71995Sopenharmony_ci    CachedHandle g_Handle = CachedParameterCreate(name, "");
475db71995Sopenharmony_ci    int changed = 0;
485db71995Sopenharmony_ci    const char *res = CachedParameterGetChanged(g_Handle, &changed);
495db71995Sopenharmony_ci    loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_INFO_BIT, 0, "loader_getenv name:%s, res:%s", name, res);
505db71995Sopenharmony_ci    if (res == NULL || res[0] == '\0') {
515db71995Sopenharmony_ci        return NULL;
525db71995Sopenharmony_ci    }
535db71995Sopenharmony_ci    return (char *)res;
545db71995Sopenharmony_ci#else
555db71995Sopenharmony_ci    // No allocation of memory necessary for Linux, but we should at least touch
565db71995Sopenharmony_ci    // the inst pointer to get rid of compiler warnings.
575db71995Sopenharmony_ci    (void)inst;
585db71995Sopenharmony_ci    return getenv(name);
595db71995Sopenharmony_ci#endif
605db71995Sopenharmony_ci}
615db71995Sopenharmony_ci
625db71995Sopenharmony_cichar *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
635db71995Sopenharmony_ci#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
645db71995Sopenharmony_ci    // Apple does not appear to have a secure getenv implementation.
655db71995Sopenharmony_ci    // The main difference between secure getenv and getenv is that secure getenv
665db71995Sopenharmony_ci    // returns NULL if the process is being run with elevated privileges by a normal user.
675db71995Sopenharmony_ci    // The idea is to prevent the reading of malicious environment variables by a process
685db71995Sopenharmony_ci    // that can do damage.
695db71995Sopenharmony_ci    // This algorithm is derived from glibc code that sets an internal
705db71995Sopenharmony_ci    // variable (__libc_enable_secure) if the process is running under setuid or setgid.
715db71995Sopenharmony_ci    return is_high_integrity() ? NULL : loader_getenv(name, inst);
725db71995Sopenharmony_ci#elif defined(__Fuchsia__)
735db71995Sopenharmony_ci    return loader_getenv(name, inst);
745db71995Sopenharmony_ci#else
755db71995Sopenharmony_ci    // Linux
765db71995Sopenharmony_ci    char *out;
775db71995Sopenharmony_ci#if defined(HAVE_SECURE_GETENV) && !defined(LOADER_USE_UNSAFE_FILE_SEARCH)
785db71995Sopenharmony_ci    (void)inst;
795db71995Sopenharmony_ci    out = secure_getenv(name);
805db71995Sopenharmony_ci#elif defined(HAVE___SECURE_GETENV) && !defined(LOADER_USE_UNSAFE_FILE_SEARCH)
815db71995Sopenharmony_ci    (void)inst;
825db71995Sopenharmony_ci    out = __secure_getenv(name);
835db71995Sopenharmony_ci#else
845db71995Sopenharmony_ci    out = loader_getenv(name, inst);
855db71995Sopenharmony_ci#if !defined(LOADER_USE_UNSAFE_FILE_SEARCH)
865db71995Sopenharmony_ci    loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Loader is using non-secure environment variable lookup for %s", name);
875db71995Sopenharmony_ci#endif
885db71995Sopenharmony_ci#endif
895db71995Sopenharmony_ci    return out;
905db71995Sopenharmony_ci#endif
915db71995Sopenharmony_ci}
925db71995Sopenharmony_ci
935db71995Sopenharmony_civoid loader_free_getenv(char *val, const struct loader_instance *inst) {
945db71995Sopenharmony_ci    // No freeing of memory necessary for Linux, but we should at least touch
955db71995Sopenharmony_ci    // the val and inst pointers to get rid of compiler warnings.
965db71995Sopenharmony_ci    (void)val;
975db71995Sopenharmony_ci    (void)inst;
985db71995Sopenharmony_ci}
995db71995Sopenharmony_ci
1005db71995Sopenharmony_ci#elif defined(WIN32)
1015db71995Sopenharmony_ci
1025db71995Sopenharmony_cibool is_high_integrity() {
1035db71995Sopenharmony_ci    HANDLE process_token;
1045db71995Sopenharmony_ci    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_QUERY_SOURCE, &process_token)) {
1055db71995Sopenharmony_ci        // Maximum possible size of SID_AND_ATTRIBUTES is maximum size of a SID + size of attributes DWORD.
1065db71995Sopenharmony_ci        uint8_t mandatory_label_buffer[SECURITY_MAX_SID_SIZE + sizeof(DWORD)];
1075db71995Sopenharmony_ci        DWORD buffer_size;
1085db71995Sopenharmony_ci        if (GetTokenInformation(process_token, TokenIntegrityLevel, mandatory_label_buffer, sizeof(mandatory_label_buffer),
1095db71995Sopenharmony_ci                                &buffer_size) != 0) {
1105db71995Sopenharmony_ci            const TOKEN_MANDATORY_LABEL *mandatory_label = (const TOKEN_MANDATORY_LABEL *)mandatory_label_buffer;
1115db71995Sopenharmony_ci            const DWORD sub_authority_count = *GetSidSubAuthorityCount(mandatory_label->Label.Sid);
1125db71995Sopenharmony_ci            const DWORD integrity_level = *GetSidSubAuthority(mandatory_label->Label.Sid, sub_authority_count - 1);
1135db71995Sopenharmony_ci
1145db71995Sopenharmony_ci            CloseHandle(process_token);
1155db71995Sopenharmony_ci            return integrity_level >= SECURITY_MANDATORY_HIGH_RID;
1165db71995Sopenharmony_ci        }
1175db71995Sopenharmony_ci
1185db71995Sopenharmony_ci        CloseHandle(process_token);
1195db71995Sopenharmony_ci    }
1205db71995Sopenharmony_ci
1215db71995Sopenharmony_ci    return false;
1225db71995Sopenharmony_ci}
1235db71995Sopenharmony_ci
1245db71995Sopenharmony_cichar *loader_getenv(const char *name, const struct loader_instance *inst) {
1255db71995Sopenharmony_ci    int name_utf16_size = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
1265db71995Sopenharmony_ci    if (name_utf16_size <= 0) {
1275db71995Sopenharmony_ci        return NULL;
1285db71995Sopenharmony_ci    }
1295db71995Sopenharmony_ci    wchar_t *name_utf16 = (wchar_t *)loader_stack_alloc(name_utf16_size * sizeof(wchar_t));
1305db71995Sopenharmony_ci    if (MultiByteToWideChar(CP_UTF8, 0, name, -1, name_utf16, name_utf16_size) != name_utf16_size) {
1315db71995Sopenharmony_ci        return NULL;
1325db71995Sopenharmony_ci    }
1335db71995Sopenharmony_ci
1345db71995Sopenharmony_ci    DWORD val_size = GetEnvironmentVariableW(name_utf16, NULL, 0);
1355db71995Sopenharmony_ci    // val_size DOES include the null terminator, so for any set variable
1365db71995Sopenharmony_ci    // will always be at least 1. If it's 0, the variable wasn't set.
1375db71995Sopenharmony_ci    if (val_size == 0) {
1385db71995Sopenharmony_ci        return NULL;
1395db71995Sopenharmony_ci    }
1405db71995Sopenharmony_ci
1415db71995Sopenharmony_ci    wchar_t *val = (wchar_t *)loader_stack_alloc(val_size * sizeof(wchar_t));
1425db71995Sopenharmony_ci    if (GetEnvironmentVariableW(name_utf16, val, val_size) != val_size - 1) {
1435db71995Sopenharmony_ci        return NULL;
1445db71995Sopenharmony_ci    }
1455db71995Sopenharmony_ci
1465db71995Sopenharmony_ci    int val_utf8_size = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0, NULL, NULL);
1475db71995Sopenharmony_ci    if (val_utf8_size <= 0) {
1485db71995Sopenharmony_ci        return NULL;
1495db71995Sopenharmony_ci    }
1505db71995Sopenharmony_ci    char *val_utf8 = (char *)loader_instance_heap_alloc(inst, val_utf8_size * sizeof(char), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
1515db71995Sopenharmony_ci    if (val_utf8 == NULL) {
1525db71995Sopenharmony_ci        return NULL;
1535db71995Sopenharmony_ci    }
1545db71995Sopenharmony_ci    if (WideCharToMultiByte(CP_UTF8, 0, val, -1, val_utf8, val_utf8_size, NULL, NULL) != val_utf8_size) {
1555db71995Sopenharmony_ci        loader_instance_heap_free(inst, val_utf8);
1565db71995Sopenharmony_ci        return NULL;
1575db71995Sopenharmony_ci    }
1585db71995Sopenharmony_ci    return val_utf8;
1595db71995Sopenharmony_ci}
1605db71995Sopenharmony_ci
1615db71995Sopenharmony_cichar *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
1625db71995Sopenharmony_ci    if (NULL == name) return NULL;
1635db71995Sopenharmony_ci#if !defined(LOADER_USE_UNSAFE_FILE_SEARCH)
1645db71995Sopenharmony_ci    if (is_high_integrity()) {
1655db71995Sopenharmony_ci        loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
1665db71995Sopenharmony_ci                   "Loader is running with elevated permissions. Environment variable %s will be ignored", name);
1675db71995Sopenharmony_ci        return NULL;
1685db71995Sopenharmony_ci    }
1695db71995Sopenharmony_ci#endif
1705db71995Sopenharmony_ci
1715db71995Sopenharmony_ci    return loader_getenv(name, inst);
1725db71995Sopenharmony_ci}
1735db71995Sopenharmony_ci
1745db71995Sopenharmony_civoid loader_free_getenv(char *val, const struct loader_instance *inst) { loader_instance_heap_free(inst, (void *)val); }
1755db71995Sopenharmony_ci
1765db71995Sopenharmony_ci#else
1775db71995Sopenharmony_ci
1785db71995Sopenharmony_ci#warning \
1795db71995Sopenharmony_ci    "This platform does not support environment variables! If this is not intended, please implement the stubs functions loader_getenv and loader_free_getenv"
1805db71995Sopenharmony_ci
1815db71995Sopenharmony_cichar *loader_getenv(const char *name, const struct loader_instance *inst) {
1825db71995Sopenharmony_ci    // stub func
1835db71995Sopenharmony_ci    (void)inst;
1845db71995Sopenharmony_ci    (void)name;
1855db71995Sopenharmony_ci    return NULL;
1865db71995Sopenharmony_ci}
1875db71995Sopenharmony_civoid loader_free_getenv(char *val, const struct loader_instance *inst) {
1885db71995Sopenharmony_ci    // stub func
1895db71995Sopenharmony_ci    (void)val;
1905db71995Sopenharmony_ci    (void)inst;
1915db71995Sopenharmony_ci}
1925db71995Sopenharmony_ci
1935db71995Sopenharmony_ci#endif
1945db71995Sopenharmony_ci
1955db71995Sopenharmony_ci// Determine the type of filter string based on the contents of it.
1965db71995Sopenharmony_ci// This will properly check against:
1975db71995Sopenharmony_ci//  - substrings "*string*"
1985db71995Sopenharmony_ci//  - prefixes "string*"
1995db71995Sopenharmony_ci//  - suffixes "*string"
2005db71995Sopenharmony_ci//  - full string names "string"
2015db71995Sopenharmony_ci// It will also return the correct start and finish to remove any star '*' characters for the actual string compare
2025db71995Sopenharmony_civoid determine_filter_type(const char *filter_string, enum loader_filter_string_type *filter_type, const char **new_start,
2035db71995Sopenharmony_ci                           size_t *new_length) {
2045db71995Sopenharmony_ci    size_t filter_length = strlen(filter_string);
2055db71995Sopenharmony_ci    bool star_begin = false;
2065db71995Sopenharmony_ci    bool star_end = false;
2075db71995Sopenharmony_ci    if ('~' == filter_string[0]) {
2085db71995Sopenharmony_ci        // One of the special identifiers like: ~all~, ~implicit~, or ~explicit~
2095db71995Sopenharmony_ci        *filter_type = FILTER_STRING_SPECIAL;
2105db71995Sopenharmony_ci        *new_start = filter_string;
2115db71995Sopenharmony_ci        *new_length = filter_length;
2125db71995Sopenharmony_ci    } else {
2135db71995Sopenharmony_ci        if ('*' == filter_string[0]) {
2145db71995Sopenharmony_ci            // Only the * means everything
2155db71995Sopenharmony_ci            if (filter_length == 1) {
2165db71995Sopenharmony_ci                *filter_type = FILTER_STRING_SPECIAL;
2175db71995Sopenharmony_ci                *new_start = filter_string;
2185db71995Sopenharmony_ci                *new_length = filter_length;
2195db71995Sopenharmony_ci            } else {
2205db71995Sopenharmony_ci                star_begin = true;
2215db71995Sopenharmony_ci            }
2225db71995Sopenharmony_ci        }
2235db71995Sopenharmony_ci        if ('*' == filter_string[filter_length - 1]) {
2245db71995Sopenharmony_ci            // Not really valid, but just catch this case so if someone accidentally types "**" it will also mean everything
2255db71995Sopenharmony_ci            if (filter_length == 2) {
2265db71995Sopenharmony_ci                *filter_type = FILTER_STRING_SPECIAL;
2275db71995Sopenharmony_ci                *new_start = filter_string;
2285db71995Sopenharmony_ci                *new_length = filter_length;
2295db71995Sopenharmony_ci            } else {
2305db71995Sopenharmony_ci                star_end = true;
2315db71995Sopenharmony_ci            }
2325db71995Sopenharmony_ci        }
2335db71995Sopenharmony_ci        if (star_begin && star_end) {
2345db71995Sopenharmony_ci            *filter_type = FILTER_STRING_SUBSTRING;
2355db71995Sopenharmony_ci            *new_start = &filter_string[1];
2365db71995Sopenharmony_ci            *new_length = filter_length - 2;
2375db71995Sopenharmony_ci        } else if (star_begin) {
2385db71995Sopenharmony_ci            *new_start = &filter_string[1];
2395db71995Sopenharmony_ci            *new_length = filter_length - 1;
2405db71995Sopenharmony_ci            *filter_type = FILTER_STRING_SUFFIX;
2415db71995Sopenharmony_ci        } else if (star_end) {
2425db71995Sopenharmony_ci            *filter_type = FILTER_STRING_PREFIX;
2435db71995Sopenharmony_ci            *new_start = filter_string;
2445db71995Sopenharmony_ci            *new_length = filter_length - 1;
2455db71995Sopenharmony_ci        } else {
2465db71995Sopenharmony_ci            *filter_type = FILTER_STRING_FULLNAME;
2475db71995Sopenharmony_ci            *new_start = filter_string;
2485db71995Sopenharmony_ci            *new_length = filter_length;
2495db71995Sopenharmony_ci        }
2505db71995Sopenharmony_ci    }
2515db71995Sopenharmony_ci}
2525db71995Sopenharmony_ci
2535db71995Sopenharmony_ci// Parse the provided filter string provided by the envrionment variable into the appropriate filter
2545db71995Sopenharmony_ci// struct variable.
2555db71995Sopenharmony_ciVkResult parse_generic_filter_environment_var(const struct loader_instance *inst, const char *env_var_name,
2565db71995Sopenharmony_ci                                              struct loader_envvar_filter *filter_struct) {
2575db71995Sopenharmony_ci    VkResult result = VK_SUCCESS;
2585db71995Sopenharmony_ci    memset(filter_struct, 0, sizeof(struct loader_envvar_filter));
2595db71995Sopenharmony_ci    char *parsing_string = NULL;
2605db71995Sopenharmony_ci    char *env_var_value = loader_secure_getenv(env_var_name, inst);
2615db71995Sopenharmony_ci    if (NULL == env_var_value) {
2625db71995Sopenharmony_ci        return result;
2635db71995Sopenharmony_ci    }
2645db71995Sopenharmony_ci    const size_t env_var_len = strlen(env_var_value);
2655db71995Sopenharmony_ci    if (env_var_len == 0) {
2665db71995Sopenharmony_ci        goto out;
2675db71995Sopenharmony_ci    }
2685db71995Sopenharmony_ci    // Allocate a separate string since scan_for_next_comma modifies the original string
2695db71995Sopenharmony_ci    parsing_string = loader_instance_heap_calloc(inst, env_var_len + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2705db71995Sopenharmony_ci    if (NULL == parsing_string) {
2715db71995Sopenharmony_ci        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
2725db71995Sopenharmony_ci                   "parse_generic_filter_environment_var: Failed to allocate space for parsing env var \'%s\'", env_var_name);
2735db71995Sopenharmony_ci        result = VK_ERROR_OUT_OF_HOST_MEMORY;
2745db71995Sopenharmony_ci        goto out;
2755db71995Sopenharmony_ci    }
2765db71995Sopenharmony_ci
2775db71995Sopenharmony_ci    for (uint32_t iii = 0; iii < env_var_len; ++iii) {
2785db71995Sopenharmony_ci        parsing_string[iii] = (char)tolower(env_var_value[iii]);
2795db71995Sopenharmony_ci    }
2805db71995Sopenharmony_ci    parsing_string[env_var_len] = '\0';
2815db71995Sopenharmony_ci
2825db71995Sopenharmony_ci    char *context = NULL;
2835db71995Sopenharmony_ci    char *token = thread_safe_strtok(parsing_string, ",", &context);
2845db71995Sopenharmony_ci    while (NULL != token) {
2855db71995Sopenharmony_ci        enum loader_filter_string_type cur_filter_type;
2865db71995Sopenharmony_ci        const char *actual_start;
2875db71995Sopenharmony_ci        size_t actual_len;
2885db71995Sopenharmony_ci        determine_filter_type(token, &cur_filter_type, &actual_start, &actual_len);
2895db71995Sopenharmony_ci        if (actual_len > VK_MAX_EXTENSION_NAME_SIZE) {
2905db71995Sopenharmony_ci            loader_strncpy(filter_struct->filters[filter_struct->count].value, VK_MAX_EXTENSION_NAME_SIZE, actual_start,
2915db71995Sopenharmony_ci                           VK_MAX_EXTENSION_NAME_SIZE);
2925db71995Sopenharmony_ci        } else {
2935db71995Sopenharmony_ci            loader_strncpy(filter_struct->filters[filter_struct->count].value, VK_MAX_EXTENSION_NAME_SIZE, actual_start,
2945db71995Sopenharmony_ci                           actual_len);
2955db71995Sopenharmony_ci        }
2965db71995Sopenharmony_ci        filter_struct->filters[filter_struct->count].length = actual_len;
2975db71995Sopenharmony_ci        filter_struct->filters[filter_struct->count++].type = cur_filter_type;
2985db71995Sopenharmony_ci        if (filter_struct->count >= MAX_ADDITIONAL_FILTERS) {
2995db71995Sopenharmony_ci            break;
3005db71995Sopenharmony_ci        }
3015db71995Sopenharmony_ci        token = thread_safe_strtok(NULL, ",", &context);
3025db71995Sopenharmony_ci    }
3035db71995Sopenharmony_ci
3045db71995Sopenharmony_ciout:
3055db71995Sopenharmony_ci
3065db71995Sopenharmony_ci    loader_instance_heap_free(inst, parsing_string);
3075db71995Sopenharmony_ci    loader_free_getenv(env_var_value, inst);
3085db71995Sopenharmony_ci    return result;
3095db71995Sopenharmony_ci}
3105db71995Sopenharmony_ci
3115db71995Sopenharmony_ci// Parse the disable layer string.  The layer disable has some special behavior because we allow it to disable
3125db71995Sopenharmony_ci// all layers (either with "~all~", "*", or "**"), all implicit layers (with "~implicit~"), and all explicit layers
3135db71995Sopenharmony_ci// (with "~explicit~"), in addition to the other layer filtering behavior.
3145db71995Sopenharmony_ciVkResult parse_layers_disable_filter_environment_var(const struct loader_instance *inst,
3155db71995Sopenharmony_ci                                                     struct loader_envvar_disable_layers_filter *disable_struct) {
3165db71995Sopenharmony_ci    VkResult result = VK_SUCCESS;
3175db71995Sopenharmony_ci    memset(disable_struct, 0, sizeof(struct loader_envvar_disable_layers_filter));
3185db71995Sopenharmony_ci    char *parsing_string = NULL;
3195db71995Sopenharmony_ci    char *env_var_value = loader_secure_getenv(VK_LAYERS_DISABLE_ENV_VAR, inst);
3205db71995Sopenharmony_ci    if (NULL == env_var_value) {
3215db71995Sopenharmony_ci        goto out;
3225db71995Sopenharmony_ci    }
3235db71995Sopenharmony_ci    const size_t env_var_len = strlen(env_var_value);
3245db71995Sopenharmony_ci    if (env_var_len == 0) {
3255db71995Sopenharmony_ci        goto out;
3265db71995Sopenharmony_ci    }
3275db71995Sopenharmony_ci    // Allocate a separate string since scan_for_next_comma modifies the original string
3285db71995Sopenharmony_ci    parsing_string = loader_instance_heap_calloc(inst, env_var_len + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
3295db71995Sopenharmony_ci    if (NULL == parsing_string) {
3305db71995Sopenharmony_ci        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
3315db71995Sopenharmony_ci                   "parse_layers_disable_filter_environment_var: Failed to allocate space for parsing env var "
3325db71995Sopenharmony_ci                   "\'VK_LAYERS_DISABLE_ENV_VAR\'");
3335db71995Sopenharmony_ci        result = VK_ERROR_OUT_OF_HOST_MEMORY;
3345db71995Sopenharmony_ci        goto out;
3355db71995Sopenharmony_ci    }
3365db71995Sopenharmony_ci
3375db71995Sopenharmony_ci    for (uint32_t iii = 0; iii < env_var_len; ++iii) {
3385db71995Sopenharmony_ci        parsing_string[iii] = (char)tolower(env_var_value[iii]);
3395db71995Sopenharmony_ci    }
3405db71995Sopenharmony_ci    parsing_string[env_var_len] = '\0';
3415db71995Sopenharmony_ci
3425db71995Sopenharmony_ci    char *context = NULL;
3435db71995Sopenharmony_ci    char *token = thread_safe_strtok(parsing_string, ",", &context);
3445db71995Sopenharmony_ci    while (NULL != token) {
3455db71995Sopenharmony_ci        uint32_t cur_count = disable_struct->additional_filters.count;
3465db71995Sopenharmony_ci        enum loader_filter_string_type cur_filter_type;
3475db71995Sopenharmony_ci        const char *actual_start;
3485db71995Sopenharmony_ci        size_t actual_len;
3495db71995Sopenharmony_ci        determine_filter_type(token, &cur_filter_type, &actual_start, &actual_len);
3505db71995Sopenharmony_ci        if (cur_filter_type == FILTER_STRING_SPECIAL) {
3515db71995Sopenharmony_ci            if (!strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_1, token) || !strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_2, token) ||
3525db71995Sopenharmony_ci                !strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_3, token)) {
3535db71995Sopenharmony_ci                disable_struct->disable_all = true;
3545db71995Sopenharmony_ci            } else if (!strcmp(VK_LOADER_DISABLE_IMPLICIT_LAYERS_VAR, token)) {
3555db71995Sopenharmony_ci                disable_struct->disable_all_implicit = true;
3565db71995Sopenharmony_ci            } else if (!strcmp(VK_LOADER_DISABLE_EXPLICIT_LAYERS_VAR, token)) {
3575db71995Sopenharmony_ci                disable_struct->disable_all_explicit = true;
3585db71995Sopenharmony_ci            }
3595db71995Sopenharmony_ci        } else {
3605db71995Sopenharmony_ci            if (actual_len > VK_MAX_EXTENSION_NAME_SIZE) {
3615db71995Sopenharmony_ci                loader_strncpy(disable_struct->additional_filters.filters[cur_count].value, VK_MAX_EXTENSION_NAME_SIZE,
3625db71995Sopenharmony_ci                               actual_start, VK_MAX_EXTENSION_NAME_SIZE);
3635db71995Sopenharmony_ci            } else {
3645db71995Sopenharmony_ci                loader_strncpy(disable_struct->additional_filters.filters[cur_count].value, VK_MAX_EXTENSION_NAME_SIZE,
3655db71995Sopenharmony_ci                               actual_start, actual_len);
3665db71995Sopenharmony_ci            }
3675db71995Sopenharmony_ci            disable_struct->additional_filters.filters[cur_count].length = actual_len;
3685db71995Sopenharmony_ci            disable_struct->additional_filters.filters[cur_count].type = cur_filter_type;
3695db71995Sopenharmony_ci            disable_struct->additional_filters.count++;
3705db71995Sopenharmony_ci            if (disable_struct->additional_filters.count >= MAX_ADDITIONAL_FILTERS) {
3715db71995Sopenharmony_ci                break;
3725db71995Sopenharmony_ci            }
3735db71995Sopenharmony_ci        }
3745db71995Sopenharmony_ci        token = thread_safe_strtok(NULL, ",", &context);
3755db71995Sopenharmony_ci    }
3765db71995Sopenharmony_ciout:
3775db71995Sopenharmony_ci    loader_instance_heap_free(inst, parsing_string);
3785db71995Sopenharmony_ci    loader_free_getenv(env_var_value, inst);
3795db71995Sopenharmony_ci    return result;
3805db71995Sopenharmony_ci}
3815db71995Sopenharmony_ci
3825db71995Sopenharmony_ci// Parses the filter environment variables to determine if we have any special behavior
3835db71995Sopenharmony_ciVkResult parse_layer_environment_var_filters(const struct loader_instance *inst, struct loader_envvar_all_filters *layer_filters) {
3845db71995Sopenharmony_ci    VkResult res = parse_generic_filter_environment_var(inst, VK_LAYERS_ENABLE_ENV_VAR, &layer_filters->enable_filter);
3855db71995Sopenharmony_ci    if (VK_SUCCESS != res) {
3865db71995Sopenharmony_ci        return res;
3875db71995Sopenharmony_ci    }
3885db71995Sopenharmony_ci    res = parse_layers_disable_filter_environment_var(inst, &layer_filters->disable_filter);
3895db71995Sopenharmony_ci    if (VK_SUCCESS != res) {
3905db71995Sopenharmony_ci        return res;
3915db71995Sopenharmony_ci    }
3925db71995Sopenharmony_ci    res = parse_generic_filter_environment_var(inst, VK_LAYERS_ALLOW_ENV_VAR, &layer_filters->allow_filter);
3935db71995Sopenharmony_ci    if (VK_SUCCESS != res) {
3945db71995Sopenharmony_ci        return res;
3955db71995Sopenharmony_ci    }
3965db71995Sopenharmony_ci    return res;
3975db71995Sopenharmony_ci}
3985db71995Sopenharmony_ci
3995db71995Sopenharmony_ci// Check to see if the provided layer name matches any of the filter strings.
4005db71995Sopenharmony_ci// This will properly check against:
4015db71995Sopenharmony_ci//  - substrings "*string*"
4025db71995Sopenharmony_ci//  - prefixes "string*"
4035db71995Sopenharmony_ci//  - suffixes "*string"
4045db71995Sopenharmony_ci//  - full string names "string"
4055db71995Sopenharmony_cibool check_name_matches_filter_environment_var(const char *name, const struct loader_envvar_filter *filter_struct) {
4065db71995Sopenharmony_ci    bool ret_value = false;
4075db71995Sopenharmony_ci    const size_t name_len = strlen(name);
4085db71995Sopenharmony_ci    char lower_name[VK_MAX_EXTENSION_NAME_SIZE];
4095db71995Sopenharmony_ci    for (uint32_t iii = 0; iii < name_len; ++iii) {
4105db71995Sopenharmony_ci        lower_name[iii] = (char)tolower(name[iii]);
4115db71995Sopenharmony_ci    }
4125db71995Sopenharmony_ci    lower_name[name_len] = '\0';
4135db71995Sopenharmony_ci    for (uint32_t filt = 0; filt < filter_struct->count; ++filt) {
4145db71995Sopenharmony_ci        // Check if the filter name is longer (this is with all special characters removed), and if it is
4155db71995Sopenharmony_ci        // continue since it can't match.
4165db71995Sopenharmony_ci        if (filter_struct->filters[filt].length > name_len) {
4175db71995Sopenharmony_ci            continue;
4185db71995Sopenharmony_ci        }
4195db71995Sopenharmony_ci        switch (filter_struct->filters[filt].type) {
4205db71995Sopenharmony_ci            case FILTER_STRING_SPECIAL:
4215db71995Sopenharmony_ci                if (!strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_1, filter_struct->filters[filt].value) ||
4225db71995Sopenharmony_ci                    !strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_2, filter_struct->filters[filt].value) ||
4235db71995Sopenharmony_ci                    !strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_3, filter_struct->filters[filt].value)) {
4245db71995Sopenharmony_ci                    ret_value = true;
4255db71995Sopenharmony_ci                }
4265db71995Sopenharmony_ci                break;
4275db71995Sopenharmony_ci
4285db71995Sopenharmony_ci            case FILTER_STRING_SUBSTRING:
4295db71995Sopenharmony_ci                if (NULL != strstr(lower_name, filter_struct->filters[filt].value)) {
4305db71995Sopenharmony_ci                    ret_value = true;
4315db71995Sopenharmony_ci                }
4325db71995Sopenharmony_ci                break;
4335db71995Sopenharmony_ci
4345db71995Sopenharmony_ci            case FILTER_STRING_SUFFIX:
4355db71995Sopenharmony_ci                if (0 == strncmp(lower_name + name_len - filter_struct->filters[filt].length, filter_struct->filters[filt].value,
4365db71995Sopenharmony_ci                                 filter_struct->filters[filt].length)) {
4375db71995Sopenharmony_ci                    ret_value = true;
4385db71995Sopenharmony_ci                }
4395db71995Sopenharmony_ci                break;
4405db71995Sopenharmony_ci
4415db71995Sopenharmony_ci            case FILTER_STRING_PREFIX:
4425db71995Sopenharmony_ci                if (0 == strncmp(lower_name, filter_struct->filters[filt].value, filter_struct->filters[filt].length)) {
4435db71995Sopenharmony_ci                    ret_value = true;
4445db71995Sopenharmony_ci                }
4455db71995Sopenharmony_ci                break;
4465db71995Sopenharmony_ci
4475db71995Sopenharmony_ci            case FILTER_STRING_FULLNAME:
4485db71995Sopenharmony_ci                if (0 == strncmp(lower_name, filter_struct->filters[filt].value, name_len)) {
4495db71995Sopenharmony_ci                    ret_value = true;
4505db71995Sopenharmony_ci                }
4515db71995Sopenharmony_ci                break;
4525db71995Sopenharmony_ci        }
4535db71995Sopenharmony_ci        if (ret_value) {
4545db71995Sopenharmony_ci            break;
4555db71995Sopenharmony_ci        }
4565db71995Sopenharmony_ci    }
4575db71995Sopenharmony_ci    return ret_value;
4585db71995Sopenharmony_ci}
4595db71995Sopenharmony_ci
4605db71995Sopenharmony_ci// Get the layer name(s) from the env_name environment variable. If layer is found in
4615db71995Sopenharmony_ci// search_list then add it to layer_list.  But only add it to layer_list if type_flags matches.
4625db71995Sopenharmony_ciVkResult loader_add_environment_layers(struct loader_instance *inst, const enum layer_type_flags type_flags,
4635db71995Sopenharmony_ci                                       const struct loader_envvar_all_filters *filters,
4645db71995Sopenharmony_ci                                       struct loader_pointer_layer_list *target_list,
4655db71995Sopenharmony_ci                                       struct loader_pointer_layer_list *expanded_target_list,
4665db71995Sopenharmony_ci                                       const struct loader_layer_list *source_list) {
4675db71995Sopenharmony_ci    VkResult res = VK_SUCCESS;
4685db71995Sopenharmony_ci    char *layer_env = loader_getenv(ENABLED_LAYERS_ENV, inst);
4695db71995Sopenharmony_ci
4705db71995Sopenharmony_ci    // If the layer environment variable is present (i.e. VK_INSTANCE_LAYERS), we will always add it to the layer list.
4715db71995Sopenharmony_ci    if (layer_env != NULL) {
4725db71995Sopenharmony_ci        size_t layer_env_len = strlen(layer_env) + 1;
4735db71995Sopenharmony_ci        char *name = loader_stack_alloc(layer_env_len);
4745db71995Sopenharmony_ci        if (name != NULL) {
4755db71995Sopenharmony_ci            loader_strncpy(name, layer_env_len, layer_env, layer_env_len);
4765db71995Sopenharmony_ci
4775db71995Sopenharmony_ci            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "env var \'%s\' defined and adding layers \"%s\"",
4785db71995Sopenharmony_ci                       ENABLED_LAYERS_ENV, name);
4795db71995Sopenharmony_ci
4805db71995Sopenharmony_ci            // First look for the old-fashion layers forced on with VK_INSTANCE_LAYERS
4815db71995Sopenharmony_ci            while (name && *name) {
4825db71995Sopenharmony_ci                char *next = loader_get_next_path(name);
4835db71995Sopenharmony_ci
4845db71995Sopenharmony_ci                if (strlen(name) > 0) {
4855db71995Sopenharmony_ci                    bool found = false;
4865db71995Sopenharmony_ci                    for (uint32_t i = 0; i < source_list->count; i++) {
4875db71995Sopenharmony_ci                        struct loader_layer_properties *source_prop = &source_list->list[i];
4885db71995Sopenharmony_ci
4895db71995Sopenharmony_ci                        if (0 == strcmp(name, source_prop->info.layerName)) {
4905db71995Sopenharmony_ci                            found = true;
4915db71995Sopenharmony_ci                            // Only add it if it doesn't already appear in the layer list
4925db71995Sopenharmony_ci                            if (!loader_find_layer_name_in_list(source_prop->info.layerName, target_list)) {
4935db71995Sopenharmony_ci                                if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
4945db71995Sopenharmony_ci                                    res = loader_add_layer_properties_to_list(inst, target_list, source_prop);
4955db71995Sopenharmony_ci                                    if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
4965db71995Sopenharmony_ci                                    res = loader_add_layer_properties_to_list(inst, expanded_target_list, source_prop);
4975db71995Sopenharmony_ci                                    if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
4985db71995Sopenharmony_ci                                } else {
4995db71995Sopenharmony_ci                                    res = loader_add_meta_layer(inst, filters, source_prop, target_list, expanded_target_list,
5005db71995Sopenharmony_ci                                                                source_list, NULL);
5015db71995Sopenharmony_ci                                    if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
5025db71995Sopenharmony_ci                                }
5035db71995Sopenharmony_ci                                break;
5045db71995Sopenharmony_ci                            }
5055db71995Sopenharmony_ci                        }
5065db71995Sopenharmony_ci                    }
5075db71995Sopenharmony_ci                    if (!found) {
5085db71995Sopenharmony_ci                        loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0,
5095db71995Sopenharmony_ci                                   "Layer \"%s\" was not found but was requested by env var VK_INSTANCE_LAYERS!", name);
5105db71995Sopenharmony_ci                    }
5115db71995Sopenharmony_ci                }
5125db71995Sopenharmony_ci                name = next;
5135db71995Sopenharmony_ci            }
5145db71995Sopenharmony_ci        }
5155db71995Sopenharmony_ci    }
5165db71995Sopenharmony_ci
5175db71995Sopenharmony_ci    // Loop through all the layers and check the enable/disable filters
5185db71995Sopenharmony_ci    for (uint32_t i = 0; i < source_list->count; i++) {
5195db71995Sopenharmony_ci        struct loader_layer_properties *source_prop = &source_list->list[i];
5205db71995Sopenharmony_ci
5215db71995Sopenharmony_ci        // If it doesn't match the type, or the name isn't what we're looking for, just continue
5225db71995Sopenharmony_ci        if ((source_prop->type_flags & type_flags) != type_flags) {
5235db71995Sopenharmony_ci            continue;
5245db71995Sopenharmony_ci        }
5255db71995Sopenharmony_ci
5265db71995Sopenharmony_ci        // We found a layer we're interested in, but has it been disabled...
5275db71995Sopenharmony_ci        bool adding = true;
5285db71995Sopenharmony_ci        bool is_implicit = (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER));
5295db71995Sopenharmony_ci        bool disabled_by_type =
5305db71995Sopenharmony_ci            (is_implicit) ? (filters->disable_filter.disable_all_implicit) : (filters->disable_filter.disable_all_explicit);
5315db71995Sopenharmony_ci        if ((filters->disable_filter.disable_all || disabled_by_type ||
5325db71995Sopenharmony_ci             check_name_matches_filter_environment_var(source_prop->info.layerName, &filters->disable_filter.additional_filters)) &&
5335db71995Sopenharmony_ci            !check_name_matches_filter_environment_var(source_prop->info.layerName, &filters->allow_filter)) {
5345db71995Sopenharmony_ci            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
5355db71995Sopenharmony_ci                       "Layer \"%s\" ignored because it has been disabled by env var \'%s\'", source_prop->info.layerName,
5365db71995Sopenharmony_ci                       VK_LAYERS_DISABLE_ENV_VAR);
5375db71995Sopenharmony_ci            adding = false;
5385db71995Sopenharmony_ci        }
5395db71995Sopenharmony_ci
5405db71995Sopenharmony_ci        // If we are supposed to filter through all layers, we need to compare the layer name against the filter.
5415db71995Sopenharmony_ci        // This can override the disable above, so we want to do it second.
5425db71995Sopenharmony_ci        // Also make sure the layer isn't already in the output_list, skip adding it if it is.
5435db71995Sopenharmony_ci        if (check_name_matches_filter_environment_var(source_prop->info.layerName, &filters->enable_filter) &&
5445db71995Sopenharmony_ci            !loader_find_layer_name_in_list(source_prop->info.layerName, target_list)) {
5455db71995Sopenharmony_ci            adding = true;
5465db71995Sopenharmony_ci            // Only way is_substring is true is if there are enable variables.  If that's the case, and we're past the
5475db71995Sopenharmony_ci            // above, we should indicate that it was forced on in this way.
5485db71995Sopenharmony_ci            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
5495db71995Sopenharmony_ci                       "Layer \"%s\" forced enabled due to env var \'%s\'", source_prop->info.layerName, VK_LAYERS_ENABLE_ENV_VAR);
5505db71995Sopenharmony_ci        } else {
5515db71995Sopenharmony_ci            adding = false;
5525db71995Sopenharmony_ci        }
5535db71995Sopenharmony_ci
5545db71995Sopenharmony_ci        if (!adding) {
5555db71995Sopenharmony_ci            continue;
5565db71995Sopenharmony_ci        }
5575db71995Sopenharmony_ci
5585db71995Sopenharmony_ci        // If not a meta-layer, simply add it.
5595db71995Sopenharmony_ci        if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
5605db71995Sopenharmony_ci            res = loader_add_layer_properties_to_list(inst, target_list, source_prop);
5615db71995Sopenharmony_ci            if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
5625db71995Sopenharmony_ci            res = loader_add_layer_properties_to_list(inst, expanded_target_list, source_prop);
5635db71995Sopenharmony_ci            if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
5645db71995Sopenharmony_ci        } else {
5655db71995Sopenharmony_ci            res = loader_add_meta_layer(inst, filters, source_prop, target_list, expanded_target_list, source_list, NULL);
5665db71995Sopenharmony_ci            if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
5675db71995Sopenharmony_ci        }
5685db71995Sopenharmony_ci    }
5695db71995Sopenharmony_ci
5705db71995Sopenharmony_ciout:
5715db71995Sopenharmony_ci
5725db71995Sopenharmony_ci    if (layer_env != NULL) {
5735db71995Sopenharmony_ci        loader_free_getenv(layer_env, inst);
5745db71995Sopenharmony_ci    }
5755db71995Sopenharmony_ci
5765db71995Sopenharmony_ci    return res;
5775db71995Sopenharmony_ci}
578