Coverage Report

Created: 2023-06-29 07:49

/src/vulkan-loader/loader/loader_environment.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *
3
 * Copyright (c) 2014-2023 The Khronos Group Inc.
4
 * Copyright (c) 2014-2023 Valve Corporation
5
 * Copyright (c) 2014-2023 LunarG, Inc.
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 *
19
 * Author: Jon Ashburn <jon@lunarg.com>
20
 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
21
 * Author: Chia-I Wu <olvaffe@gmail.com>
22
 * Author: Chia-I Wu <olv@lunarg.com>
23
 * Author: Mark Lobodzinski <mark@LunarG.com>
24
 * Author: Lenny Komow <lenny@lunarg.com>
25
 * Author: Charles Giessen <charles@lunarg.com>
26
 *
27
 */
28
29
#include "loader_environment.h"
30
31
#include "allocation.h"
32
#include "loader.h"
33
#include "log.h"
34
35
#include <ctype.h>
36
37
// Environment variables
38
#if COMMON_UNIX_PLATFORMS
39
40
0
bool is_high_integrity() { return geteuid() != getuid() || getegid() != getgid(); }
41
42
2
char *loader_getenv(const char *name, const struct loader_instance *inst) {
43
2
    if (NULL == name) return NULL;
44
    // No allocation of memory necessary for Linux, but we should at least touch
45
    // the inst pointer to get rid of compiler warnings.
46
2
    (void)inst;
47
2
    return getenv(name);
48
2
}
49
50
0
char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
51
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
52
    // Apple does not appear to have a secure getenv implementation.
53
    // The main difference between secure getenv and getenv is that secure getenv
54
    // returns NULL if the process is being run with elevated privileges by a normal user.
55
    // The idea is to prevent the reading of malicious environment variables by a process
56
    // that can do damage.
57
    // This algorithm is derived from glibc code that sets an internal
58
    // variable (__libc_enable_secure) if the process is running under setuid or setgid.
59
    return is_high_integrity() ? NULL : loader_getenv(name, inst);
60
#elif defined(__Fuchsia__)
61
    return loader_getenv(name, inst);
62
#else
63
    // Linux
64
0
    char *out;
65
0
#if defined(HAVE_SECURE_GETENV) && !defined(LOADER_USE_UNSAFE_FILE_SEARCH)
66
0
    (void)inst;
67
0
    out = secure_getenv(name);
68
#elif defined(HAVE___SECURE_GETENV) && !defined(LOADER_USE_UNSAFE_FILE_SEARCH)
69
    (void)inst;
70
    out = __secure_getenv(name);
71
#else
72
    out = loader_getenv(name, inst);
73
#if !defined(LOADER_USE_UNSAFE_FILE_SEARCH)
74
    loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Loader is using non-secure environment variable lookup for %s", name);
75
#endif
76
#endif
77
0
    return out;
78
0
#endif
79
0
}
80
81
2
void loader_free_getenv(char *val, const struct loader_instance *inst) {
82
    // No freeing of memory necessary for Linux, but we should at least touch
83
    // the val and inst pointers to get rid of compiler warnings.
84
2
    (void)val;
85
2
    (void)inst;
86
2
}
87
88
#elif defined(WIN32)
89
90
bool is_high_integrity() {
91
    HANDLE process_token;
92
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_QUERY_SOURCE, &process_token)) {
93
        // Maximum possible size of SID_AND_ATTRIBUTES is maximum size of a SID + size of attributes DWORD.
94
        uint8_t mandatory_label_buffer[SECURITY_MAX_SID_SIZE + sizeof(DWORD)];
95
        DWORD buffer_size;
96
        if (GetTokenInformation(process_token, TokenIntegrityLevel, mandatory_label_buffer, sizeof(mandatory_label_buffer),
97
                                &buffer_size) != 0) {
98
            const TOKEN_MANDATORY_LABEL *mandatory_label = (const TOKEN_MANDATORY_LABEL *)mandatory_label_buffer;
99
            const DWORD sub_authority_count = *GetSidSubAuthorityCount(mandatory_label->Label.Sid);
100
            const DWORD integrity_level = *GetSidSubAuthority(mandatory_label->Label.Sid, sub_authority_count - 1);
101
102
            CloseHandle(process_token);
103
            return integrity_level >= SECURITY_MANDATORY_HIGH_RID;
104
        }
105
106
        CloseHandle(process_token);
107
    }
108
109
    return false;
110
}
111
112
char *loader_getenv(const char *name, const struct loader_instance *inst) {
113
    int name_utf16_size = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
114
    if (name_utf16_size <= 0) {
115
        return NULL;
116
    }
117
    wchar_t *name_utf16 = (wchar_t *)loader_stack_alloc(name_utf16_size * sizeof(wchar_t));
118
    if (MultiByteToWideChar(CP_UTF8, 0, name, -1, name_utf16, name_utf16_size) != name_utf16_size) {
119
        return NULL;
120
    }
121
122
    DWORD val_size = GetEnvironmentVariableW(name_utf16, NULL, 0);
123
    // val_size DOES include the null terminator, so for any set variable
124
    // will always be at least 1. If it's 0, the variable wasn't set.
125
    if (val_size == 0) {
126
        return NULL;
127
    }
128
129
    wchar_t *val = (wchar_t *)loader_stack_alloc(val_size * sizeof(wchar_t));
130
    if (GetEnvironmentVariableW(name_utf16, val, val_size) != val_size - 1) {
131
        return NULL;
132
    }
133
134
    int val_utf8_size = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0, NULL, NULL);
135
    if (val_utf8_size <= 0) {
136
        return NULL;
137
    }
138
    char *val_utf8 = (char *)loader_instance_heap_alloc(inst, val_utf8_size * sizeof(char), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
139
    if (val_utf8 == NULL) {
140
        return NULL;
141
    }
142
    if (WideCharToMultiByte(CP_UTF8, 0, val, -1, val_utf8, val_utf8_size, NULL, NULL) != val_utf8_size) {
143
        loader_instance_heap_free(inst, val_utf8);
144
        return NULL;
145
    }
146
    return val_utf8;
147
}
148
149
char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
150
    if (NULL == name) return NULL;
151
#if !defined(LOADER_USE_UNSAFE_FILE_SEARCH)
152
    if (is_high_integrity()) {
153
        loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
154
                   "Loader is running with elevated permissions. Environment variable %s will be ignored", name);
155
        return NULL;
156
    }
157
#endif
158
159
    return loader_getenv(name, inst);
160
}
161
162
void loader_free_getenv(char *val, const struct loader_instance *inst) { loader_instance_heap_free(inst, (void *)val); }
163
164
#else
165
166
#warning \
167
    "This platform does not support environment variables! If this is not intended, please implement the stubs functions loader_getenv and loader_free_getenv"
168
169
char *loader_getenv(const char *name, const struct loader_instance *inst) {
170
    // stub func
171
    (void)inst;
172
    (void)name;
173
    return NULL;
174
}
175
void loader_free_getenv(char *val, const struct loader_instance *inst) {
176
    // stub func
177
    (void)val;
178
    (void)inst;
179
}
180
181
#endif
182
183
// Determine the type of filter string based on the contents of it.
184
// This will properly check against:
185
//  - substrings "*string*"
186
//  - prefixes "string*"
187
//  - suffixes "*string"
188
//  - full string names "string"
189
// It will also return the correct start and finish to remove any star '*' characters for the actual string compare
190
void determine_filter_type(const char *filter_string, enum loader_filter_string_type *filter_type, const char **new_start,
191
0
                           size_t *new_length) {
192
0
    size_t filter_length = strlen(filter_string);
193
0
    bool star_begin = false;
194
0
    bool star_end = false;
195
0
    if ('~' == filter_string[0]) {
196
        // One of the special identifiers like: ~all~, ~implicit~, or ~explicit~
197
0
        *filter_type = FILTER_STRING_SPECIAL;
198
0
        *new_start = filter_string;
199
0
        *new_length = filter_length;
200
0
    } else {
201
0
        if ('*' == filter_string[0]) {
202
            // Only the * means everything
203
0
            if (filter_length == 1) {
204
0
                *filter_type = FILTER_STRING_SPECIAL;
205
0
                *new_start = filter_string;
206
0
                *new_length = filter_length;
207
0
            } else {
208
0
                star_begin = true;
209
0
            }
210
0
        }
211
0
        if ('*' == filter_string[filter_length - 1]) {
212
            // Not really valid, but just catch this case so if someone accidentally types "**" it will also mean everything
213
0
            if (filter_length == 2) {
214
0
                *filter_type = FILTER_STRING_SPECIAL;
215
0
                *new_start = filter_string;
216
0
                *new_length = filter_length;
217
0
            } else {
218
0
                star_end = true;
219
0
            }
220
0
        }
221
0
        if (star_begin && star_end) {
222
0
            *filter_type = FILTER_STRING_SUBSTRING;
223
0
            *new_start = &filter_string[1];
224
0
            *new_length = filter_length - 2;
225
0
        } else if (star_begin) {
226
0
            *new_start = &filter_string[1];
227
0
            *new_length = filter_length - 1;
228
0
            *filter_type = FILTER_STRING_SUFFIX;
229
0
        } else if (star_end) {
230
0
            *filter_type = FILTER_STRING_PREFIX;
231
0
            *new_start = filter_string;
232
0
            *new_length = filter_length - 1;
233
0
        } else {
234
0
            *filter_type = FILTER_STRING_FULLNAME;
235
0
            *new_start = filter_string;
236
0
            *new_length = filter_length;
237
0
        }
238
0
    }
239
0
}
240
241
// Parse the provided filter string provided by the envrionment variable into the appropriate filter
242
// struct variable.
243
VkResult parse_generic_filter_environment_var(const struct loader_instance *inst, const char *env_var_name,
244
0
                                              struct loader_envvar_filter *filter_struct) {
245
0
    VkResult result = VK_SUCCESS;
246
0
    memset(filter_struct, 0, sizeof(struct loader_envvar_filter));
247
0
    char *parsing_string = NULL;
248
0
    char *env_var_value = loader_secure_getenv(env_var_name, inst);
249
0
    if (NULL == env_var_value) {
250
0
        return result;
251
0
    }
252
0
    const size_t env_var_len = strlen(env_var_value);
253
0
    if (env_var_len == 0) {
254
0
        goto out;
255
0
    }
256
    // Allocate a separate string since scan_for_next_comma modifies the original string
257
0
    parsing_string = loader_instance_heap_calloc(inst, env_var_len + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
258
0
    if (NULL == parsing_string) {
259
0
        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
260
0
                   "parse_generic_filter_environment_var: Failed to allocate space for parsing env var \'%s\'", env_var_name);
261
0
        result = VK_ERROR_OUT_OF_HOST_MEMORY;
262
0
        goto out;
263
0
    }
264
265
0
    for (uint32_t iii = 0; iii < env_var_len; ++iii) {
266
0
        parsing_string[iii] = (char)tolower(env_var_value[iii]);
267
0
    }
268
0
    parsing_string[env_var_len] = '\0';
269
270
0
    char *context = NULL;
271
0
    char *token = thread_safe_strtok(parsing_string, ",", &context);
272
0
    while (NULL != token) {
273
0
        enum loader_filter_string_type cur_filter_type;
274
0
        const char *actual_start;
275
0
        size_t actual_len;
276
0
        determine_filter_type(token, &cur_filter_type, &actual_start, &actual_len);
277
0
        if (actual_len > VK_MAX_EXTENSION_NAME_SIZE) {
278
0
            strncpy(filter_struct->filters[filter_struct->count].value, actual_start, VK_MAX_EXTENSION_NAME_SIZE);
279
0
        } else {
280
0
            strncpy(filter_struct->filters[filter_struct->count].value, actual_start, actual_len);
281
0
        }
282
0
        filter_struct->filters[filter_struct->count].length = actual_len;
283
0
        filter_struct->filters[filter_struct->count++].type = cur_filter_type;
284
0
        if (filter_struct->count >= MAX_ADDITIONAL_FILTERS) {
285
0
            break;
286
0
        }
287
0
        token = thread_safe_strtok(NULL, ",", &context);
288
0
    }
289
290
0
out:
291
292
0
    loader_instance_heap_free(inst, parsing_string);
293
0
    loader_free_getenv(env_var_value, inst);
294
0
    return result;
295
0
}
296
297
// Parse the disable layer string.  The layer disable has some special behavior because we allow it to disable
298
// all layers (either with "~all~", "*", or "**"), all implicit layers (with "~implicit~"), and all explicit layers
299
// (with "~explicit~"), in addition to the other layer filtering behavior.
300
VkResult parse_layers_disable_filter_environment_var(const struct loader_instance *inst,
301
0
                                                     struct loader_envvar_disable_layers_filter *disable_struct) {
302
0
    VkResult result = VK_SUCCESS;
303
0
    memset(disable_struct, 0, sizeof(struct loader_envvar_disable_layers_filter));
304
0
    char *parsing_string = NULL;
305
0
    char *env_var_value = loader_secure_getenv(VK_LAYERS_DISABLE_ENV_VAR, inst);
306
0
    if (NULL == env_var_value) {
307
0
        goto out;
308
0
    }
309
0
    const size_t env_var_len = strlen(env_var_value);
310
0
    if (env_var_len == 0) {
311
0
        goto out;
312
0
    }
313
    // Allocate a separate string since scan_for_next_comma modifies the original string
314
0
    parsing_string = loader_instance_heap_calloc(inst, env_var_len + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
315
0
    if (NULL == parsing_string) {
316
0
        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
317
0
                   "parse_layers_disable_filter_environment_var: Failed to allocate space for parsing env var "
318
0
                   "\'VK_LAYERS_DISABLE_ENV_VAR\'");
319
0
        result = VK_ERROR_OUT_OF_HOST_MEMORY;
320
0
        goto out;
321
0
    }
322
323
0
    for (uint32_t iii = 0; iii < env_var_len; ++iii) {
324
0
        parsing_string[iii] = (char)tolower(env_var_value[iii]);
325
0
    }
326
0
    parsing_string[env_var_len] = '\0';
327
328
0
    char *context = NULL;
329
0
    char *token = thread_safe_strtok(parsing_string, ",", &context);
330
0
    while (NULL != token) {
331
0
        uint32_t cur_count = disable_struct->additional_filters.count;
332
0
        enum loader_filter_string_type cur_filter_type;
333
0
        const char *actual_start;
334
0
        size_t actual_len;
335
0
        determine_filter_type(token, &cur_filter_type, &actual_start, &actual_len);
336
0
        if (cur_filter_type == FILTER_STRING_SPECIAL) {
337
0
            if (!strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_1, token) || !strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_2, token) ||
338
0
                !strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_3, token)) {
339
0
                disable_struct->disable_all = true;
340
0
            } else if (!strcmp(VK_LOADER_DISABLE_IMPLICIT_LAYERS_VAR, token)) {
341
0
                disable_struct->disable_all_implicit = true;
342
0
            } else if (!strcmp(VK_LOADER_DISABLE_EXPLICIT_LAYERS_VAR, token)) {
343
0
                disable_struct->disable_all_explicit = true;
344
0
            }
345
0
        } else {
346
0
            if (actual_len > VK_MAX_EXTENSION_NAME_SIZE) {
347
0
                strncpy(disable_struct->additional_filters.filters[cur_count].value, actual_start, VK_MAX_EXTENSION_NAME_SIZE);
348
0
            } else {
349
0
                strncpy(disable_struct->additional_filters.filters[cur_count].value, actual_start, actual_len);
350
0
            }
351
0
            disable_struct->additional_filters.filters[cur_count].length = actual_len;
352
0
            disable_struct->additional_filters.filters[cur_count].type = cur_filter_type;
353
0
            disable_struct->additional_filters.count++;
354
0
            if (disable_struct->additional_filters.count >= MAX_ADDITIONAL_FILTERS) {
355
0
                break;
356
0
            }
357
0
        }
358
0
        token = thread_safe_strtok(NULL, ",", &context);
359
0
    }
360
0
out:
361
0
    loader_instance_heap_free(inst, parsing_string);
362
0
    loader_free_getenv(env_var_value, inst);
363
0
    return result;
364
0
}
365
366
// Check to see if the provided layer name matches any of the filter strings.
367
// This will properly check against:
368
//  - substrings "*string*"
369
//  - prefixes "string*"
370
//  - suffixes "*string"
371
//  - full string names "string"
372
0
bool check_name_matches_filter_environment_var(const char *name, const struct loader_envvar_filter *filter_struct) {
373
0
    bool ret_value = false;
374
0
    const size_t name_len = strlen(name);
375
0
    char lower_name[VK_MAX_EXTENSION_NAME_SIZE];
376
0
    for (uint32_t iii = 0; iii < name_len; ++iii) {
377
0
        lower_name[iii] = (char)tolower(name[iii]);
378
0
    }
379
0
    lower_name[name_len] = '\0';
380
0
    for (uint32_t filt = 0; filt < filter_struct->count; ++filt) {
381
        // Check if the filter name is longer (this is with all special characters removed), and if it is
382
        // continue since it can't match.
383
0
        if (filter_struct->filters[filt].length > name_len) {
384
0
            continue;
385
0
        }
386
0
        switch (filter_struct->filters[filt].type) {
387
0
            case FILTER_STRING_SPECIAL:
388
0
                if (!strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_1, filter_struct->filters[filt].value) ||
389
0
                    !strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_2, filter_struct->filters[filt].value) ||
390
0
                    !strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_3, filter_struct->filters[filt].value)) {
391
0
                    ret_value = true;
392
0
                }
393
0
                break;
394
395
0
            case FILTER_STRING_SUBSTRING:
396
0
                if (NULL != strstr(lower_name, filter_struct->filters[filt].value)) {
397
0
                    ret_value = true;
398
0
                }
399
0
                break;
400
401
0
            case FILTER_STRING_SUFFIX:
402
0
                if (0 == strncmp(lower_name + name_len - filter_struct->filters[filt].length, filter_struct->filters[filt].value,
403
0
                                 filter_struct->filters[filt].length)) {
404
0
                    ret_value = true;
405
0
                }
406
0
                break;
407
408
0
            case FILTER_STRING_PREFIX:
409
0
                if (0 == strncmp(lower_name, filter_struct->filters[filt].value, filter_struct->filters[filt].length)) {
410
0
                    ret_value = true;
411
0
                }
412
0
                break;
413
414
0
            case FILTER_STRING_FULLNAME:
415
0
                if (0 == strncmp(lower_name, filter_struct->filters[filt].value, name_len)) {
416
0
                    ret_value = true;
417
0
                }
418
0
                break;
419
0
        }
420
0
        if (ret_value) {
421
0
            break;
422
0
        }
423
0
    }
424
0
    return ret_value;
425
0
}
426
427
// Get the layer name(s) from the env_name environment variable. If layer is found in
428
// search_list then add it to layer_list.  But only add it to layer_list if type_flags matches.
429
VkResult loader_add_environment_layers(struct loader_instance *inst, const enum layer_type_flags type_flags,
430
                                       const struct loader_envvar_filter *enable_filter,
431
                                       const struct loader_envvar_disable_layers_filter *disable_filter,
432
                                       struct loader_pointer_layer_list *target_list,
433
                                       struct loader_pointer_layer_list *expanded_target_list,
434
0
                                       const struct loader_layer_list *source_list) {
435
0
    VkResult res = VK_SUCCESS;
436
0
    char *layer_env = loader_getenv(ENABLED_LAYERS_ENV, inst);
437
438
    // If the layer environment variable is present (i.e. VK_INSTANCE_LAYERS), we will always add it to the layer list.
439
0
    if (layer_env != NULL) {
440
0
        size_t layer_env_len = strlen(layer_env) + 1;
441
0
        char *name = loader_stack_alloc(layer_env_len);
442
0
        if (name != NULL) {
443
0
            strncpy(name, layer_env, layer_env_len);
444
445
0
            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "env var \'%s\' defined and adding layers \"%s\"",
446
0
                       ENABLED_LAYERS_ENV, name);
447
448
            // First look for the old-fashion layers forced on with VK_INSTANCE_LAYERS
449
0
            while (name && *name) {
450
0
                char *next = loader_get_next_path(name);
451
452
0
                if (strlen(name) > 0) {
453
0
                    bool found = false;
454
0
                    for (uint32_t i = 0; i < source_list->count; i++) {
455
0
                        struct loader_layer_properties *source_prop = &source_list->list[i];
456
457
0
                        if (0 == strcmp(name, source_prop->info.layerName)) {
458
0
                            found = true;
459
                            // Only add it if it doesn't already appear in the layer list
460
0
                            if (!loader_find_layer_name_in_list(source_prop->info.layerName, target_list)) {
461
0
                                if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
462
0
                                    res = loader_add_layer_properties_to_list(inst, target_list, source_prop);
463
0
                                    if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
464
0
                                    res = loader_add_layer_properties_to_list(inst, expanded_target_list, source_prop);
465
0
                                    if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
466
0
                                } else {
467
0
                                    res = loader_add_meta_layer(inst, enable_filter, disable_filter, source_prop, target_list,
468
0
                                                                expanded_target_list, source_list, NULL);
469
0
                                    if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
470
0
                                }
471
0
                                break;
472
0
                            }
473
0
                        }
474
0
                    }
475
0
                    if (!found) {
476
0
                        loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0,
477
0
                                   "Layer \"%s\" was not found but was requested by env var VK_INSTANCE_LAYERS!", name);
478
0
                    }
479
0
                }
480
0
                name = next;
481
0
            }
482
0
        }
483
0
    }
484
485
    // Loop through all the layers and check the enable/disable filters
486
0
    for (uint32_t i = 0; i < source_list->count; i++) {
487
0
        struct loader_layer_properties *source_prop = &source_list->list[i];
488
489
        // If it doesn't match the type, or the name isn't what we're looking for, just continue
490
0
        if ((source_prop->type_flags & type_flags) != type_flags) {
491
0
            continue;
492
0
        }
493
494
        // We found a layer we're interested in, but has it been disabled...
495
0
        bool adding = true;
496
0
        bool is_implicit = (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER));
497
0
        bool disabled_by_type = (is_implicit) ? (NULL != disable_filter && disable_filter->disable_all_implicit)
498
0
                                              : (NULL != disable_filter && disable_filter->disable_all_explicit);
499
0
        if (NULL != disable_filter &&
500
0
            (disable_filter->disable_all || disabled_by_type ||
501
0
             check_name_matches_filter_environment_var(source_prop->info.layerName, &disable_filter->additional_filters))) {
502
0
            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
503
0
                       "Layer \"%s\" ignored because it has been disabled by env var \'%s\'", source_prop->info.layerName,
504
0
                       VK_LAYERS_DISABLE_ENV_VAR);
505
0
            adding = false;
506
0
        }
507
508
        // If we are supposed to filter through all layers, we need to compare the layer name against the filter.
509
        // This can override the disable above, so we want to do it second.
510
        // Also make sure the layer isn't already in the output_list, skip adding it if it is.
511
0
        if (check_name_matches_filter_environment_var(source_prop->info.layerName, enable_filter) &&
512
0
            !loader_find_layer_name_in_list(source_prop->info.layerName, target_list)) {
513
0
            adding = true;
514
            // Only way is_substring is true is if there are enable variables.  If that's the case, and we're past the
515
            // above, we should indicate that it was forced on in this way.
516
0
            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
517
0
                       "Layer \"%s\" forced enabled due to env var \'%s\'", source_prop->info.layerName, VK_LAYERS_ENABLE_ENV_VAR);
518
0
        } else {
519
0
            adding = false;
520
0
        }
521
522
0
        if (!adding) {
523
0
            continue;
524
0
        }
525
526
        // If not a meta-layer, simply add it.
527
0
        if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
528
0
            res = loader_add_layer_properties_to_list(inst, target_list, source_prop);
529
0
            if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
530
0
            res = loader_add_layer_properties_to_list(inst, expanded_target_list, source_prop);
531
0
            if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
532
0
        } else {
533
0
            res = loader_add_meta_layer(inst, enable_filter, disable_filter, source_prop, target_list, expanded_target_list,
534
0
                                        source_list, NULL);
535
0
            if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
536
0
        }
537
0
    }
538
539
0
out:
540
541
0
    if (layer_env != NULL) {
542
0
        loader_free_getenv(layer_env, inst);
543
0
    }
544
545
0
    return res;
546
0
}