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