| /* |
| * |
| * Copyright (c) 2014-2021 The Khronos Group Inc. |
| * Copyright (c) 2014-2021 Valve Corporation |
| * Copyright (c) 2014-2021 LunarG, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * Author: Jon Ashburn <jon@lunarg.com> |
| * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> |
| * Author: Chia-I Wu <olvaffe@gmail.com> |
| * Author: Chia-I Wu <olv@lunarg.com> |
| * Author: Mark Lobodzinski <mark@LunarG.com> |
| * Author: Lenny Komow <lenny@lunarg.com> |
| * Author: Charles Giessen <charles@lunarg.com> |
| * |
| */ |
| |
| #include "get_environment.h" |
| |
| #include "log.h" |
| |
| // Environment variables |
| #if defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__QNXNTO__) || defined(__FreeBSD__) |
| |
| bool is_high_integrity() { return geteuid() != getuid() || getegid() != getgid(); } |
| |
| char *loader_getenv(const char *name, const struct loader_instance *inst) { |
| // No allocation of memory necessary for Linux, but we should at least touch |
| // the inst pointer to get rid of compiler warnings. |
| (void)inst; |
| return getenv(name); |
| } |
| |
| char *loader_secure_getenv(const char *name, const struct loader_instance *inst) { |
| #if defined(__APPLE__) || defined(__FreeBSD__) |
| // Apple does not appear to have a secure getenv implementation. |
| // The main difference between secure getenv and getenv is that secure getenv |
| // returns NULL if the process is being run with elevated privileges by a normal user. |
| // The idea is to prevent the reading of malicious environment variables by a process |
| // that can do damage. |
| // This algorithm is derived from glibc code that sets an internal |
| // variable (__libc_enable_secure) if the process is running under setuid or setgid. |
| return is_high_integrity() ? NULL : loader_getenv(name, inst); |
| #elif defined(__Fuchsia__) |
| return loader_getenv(name, inst); |
| #else |
| // Linux |
| char *out; |
| #if defined(HAVE_SECURE_GETENV) && !defined(USE_UNSAFE_FILE_SEARCH) |
| (void)inst; |
| out = secure_getenv(name); |
| #elif defined(HAVE___SECURE_GETENV) && !defined(USE_UNSAFE_FILE_SEARCH) |
| (void)inst; |
| out = __secure_getenv(name); |
| #else |
| out = loader_getenv(name, inst); |
| #if !defined(USE_UNSAFE_FILE_SEARCH) |
| loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Loader is using non-secure environment variable lookup for %s", name); |
| #endif |
| #endif |
| return out; |
| #endif |
| } |
| |
| void loader_free_getenv(char *val, const struct loader_instance *inst) { |
| // No freeing of memory necessary for Linux, but we should at least touch |
| // the val and inst pointers to get rid of compiler warnings. |
| (void)val; |
| (void)inst; |
| } |
| |
| #elif defined(WIN32) |
| |
| bool is_high_integrity() { |
| HANDLE process_token; |
| if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_QUERY_SOURCE, &process_token)) { |
| // Maximum possible size of SID_AND_ATTRIBUTES is maximum size of a SID + size of attributes DWORD. |
| uint8_t mandatory_label_buffer[SECURITY_MAX_SID_SIZE + sizeof(DWORD)]; |
| DWORD buffer_size; |
| if (GetTokenInformation(process_token, TokenIntegrityLevel, mandatory_label_buffer, sizeof(mandatory_label_buffer), |
| &buffer_size) != 0) { |
| const TOKEN_MANDATORY_LABEL *mandatory_label = (const TOKEN_MANDATORY_LABEL *)mandatory_label_buffer; |
| const DWORD sub_authority_count = *GetSidSubAuthorityCount(mandatory_label->Label.Sid); |
| const DWORD integrity_level = *GetSidSubAuthority(mandatory_label->Label.Sid, sub_authority_count - 1); |
| |
| CloseHandle(process_token); |
| return integrity_level > SECURITY_MANDATORY_MEDIUM_RID; |
| } |
| |
| CloseHandle(process_token); |
| } |
| |
| return false; |
| } |
| |
| char *loader_getenv(const char *name, const struct loader_instance *inst) { |
| char *retVal; |
| DWORD valSize; |
| |
| valSize = GetEnvironmentVariableA(name, NULL, 0); |
| |
| // valSize DOES include the null terminator, so for any set variable |
| // will always be at least 1. If it's 0, the variable wasn't set. |
| if (valSize == 0) return NULL; |
| |
| // Allocate the space necessary for the registry entry |
| if (NULL != inst && NULL != inst->alloc_callbacks.pfnAllocation) { |
| retVal = (char *)inst->alloc_callbacks.pfnAllocation(inst->alloc_callbacks.pUserData, valSize, sizeof(char *), |
| VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); |
| } else { |
| retVal = (char *)malloc(valSize); |
| } |
| |
| if (NULL != retVal) { |
| GetEnvironmentVariableA(name, retVal, valSize); |
| } |
| |
| return retVal; |
| } |
| |
| char *loader_secure_getenv(const char *name, const struct loader_instance *inst) { |
| #if !defined(USE_UNSAFE_FILE_SEARCH) |
| if (is_high_integrity()) { |
| loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, |
| "Loader is running with elevated permissions. Environment variable %s will be ignored", name); |
| return NULL; |
| } |
| #endif |
| |
| return loader_getenv(name, inst); |
| } |
| |
| void loader_free_getenv(char *val, const struct loader_instance *inst) { |
| if (NULL != inst && NULL != inst->alloc_callbacks.pfnFree) { |
| inst->alloc_callbacks.pfnFree(inst->alloc_callbacks.pUserData, val); |
| } else { |
| free((void *)val); |
| } |
| } |
| |
| #else |
| |
| char *loader_getenv(const char *name, const struct loader_instance *inst) { |
| // stub func |
| (void)inst; |
| (void)name; |
| return NULL; |
| } |
| void loader_free_getenv(char *val, const struct loader_instance *inst) { |
| // stub func |
| (void)val; |
| (void)inst; |
| } |
| |
| #endif |