On Linux, the Vulkan loader will scan the files in the following Linux
directories:
+```
+ $XDG_CONFIG_HOME (or if not defined $HOME/.config)
+ $XDG_CONFIG_DIRS
+ $SYSCONFDIR (or if not defined /etc)
+ $EXTRASYSCONFDIR (or ir not defined /etc)
+ $XDG_DATA_HOME (or if not defined $HOME/.local/share)
+ $XDG_DATA_DIRS
+```
+
+The "XDG_..._HOME" default directories can be configured to be other directories
+at build time.
+
+
+To each of these paths will be added two suffixes.
+First, the suffix **/vulkan** is added so the loader will only look for
+information in a "vulkan" sub-folder.
+Second, a suffix for the type of layer being searched for is used.
+This second suffix will be **/explicit_layer.d** when searching for explicit
+layers, and **/implicit_layer.d** when searching for implicit layers.
+Duplicate resulting folders will be ignored.
+
+An example combined search path for explicit layers may look like this:
+
+```
/usr/local/etc/vulkan/explicit_layer.d
- /usr/local/etc/vulkan/implicit_layer.d
/usr/local/share/vulkan/explicit_layer.d
- /usr/local/share/vulkan/implicit_layer.d
/etc/vulkan/explicit_layer.d
- /etc/vulkan/implicit_layer.d
/usr/share/vulkan/explicit_layer.d
- /usr/share/vulkan/implicit_layer.d
$HOME/.local/share/vulkan/explicit_layer.d
- $HOME/.local/share/vulkan/implicit_layer.d
+```
-Of course, there are some things you have to know about the above folders:
- 1. The "/usr/local/*" directories can be configured to be other directories at
-build time.
- 2. $HOME is the current home directory of the application's user id; this path
-will be ignored for suid programs.
- 3. The "/usr/local/etc/vulkan/\*\_layer.d" and
-"/usr/local/share/vulkan/\*\_layer.d" directories are for layers that are
-installed from locally-built sources.
- 4. The "/usr/share/vulkan/\*\_layer.d" directories are for layers that are
-installed from Linux-distribution-provided packages.
-5. The locations in `$HOME` will only be searched if an application does not have
-root access. This is done to ensure that an application with root access does not
-run layers that did not need root access to install.
+<b>IMPORTANT NOTE!</b> Any path using $HOME is ignored for all suid programs for
+security reasons.
As on Windows, if VK\_LAYER\_PATH is defined, then the
loader will instead look at the paths defined by that variable instead of using
On macOS, the Vulkan loader will scan the files in the following directories:
- <bundle>/Contents/Resources/vulkan/explicit_layer.d
+```
+ <bundle>/Contents/Resources
+ $XDG_CONFIG_HOME (or if not defined $HOME/.config)
+ $XDG_CONFIG_DIRS
+ $SYSCONFDIR (or if not defined /etc)
+ $EXTRASYSCONFDIR (or ir not defined /etc)
+ $XDG_DATA_HOME (or if not defined $HOME/.local/share)
+ $XDG_DATA_DIRS
+```
+
+**bundle**; is the directory containing a bundled application.
+It is scanned first.
+
+The "XDG_..._HOME" default directories can be configured to be other directories
+at build time.
+
+To each of these paths will be added two suffixes.
+First, the suffix **/vulkan** is added so the loader will only look for
+information in a "vulkan" sub-folder.
+Second, a suffix for the type of layer being searched for is used.
+This second suffix will be **/explicit_layer.d** when searching for explicit
+layers, and **/implicit_layer.d** when searching for implicit layers.
+Duplicate resulting folders will be ignored.
+
+An example combined search path for implicit layers may look like this:
+
+```
<bundle>/Contents/Resources/vulkan/implicit_layer.d
- /etc/vulkan/explicit_layer.d
/etc/vulkan/implicit_layer.d
- /usr/local/share/vulkan/explicit_layer.d
/usr/local/share/vulkan/implicit_layer.d
- /usr/share/vulkan/explicit_layer.d
/usr/share/vulkan/implicit_layer.d
- $HOME/.local/share/vulkan/explicit_layer.d
$HOME/.local/share/vulkan/implicit_layer.d
+```
-1. <bundle> is the directory containing a bundled application. It is scanned first.
-2. The "/usr/local/\*" directories can be configured to be other directories at
-build time.
-3. $HOME is the current home directory of the application's user id; this path
-will be ignored for suid programs.
-4. The locations in `$HOME` will only be searched if an application does not have
-root access. This is done to ensure that an application with root access does not
-run layers that did not need root access to install.
+<b>IMPORTANT NOTE!</b> Any path using $HOME is ignored for all suid programs for
+security reasons.
As on Windows, if VK\_LAYER\_PATH is defined, then the
loader will instead look at the paths defined by that variable instead of using
In order to find installed ICDs, the Vulkan loader will scan the files
in the following Linux directories:
+```
+ $XDG_CONFIG_HOME (or if not defined $HOME/.config)
+ $XDG_CONFIG_DIRS
+ $SYSCONFDIR (or if not defined /etc)
+ $EXTRASYSCONFDIR (or ir not defined /etc)
+ $XDG_DATA_HOME (or if not defined $HOME/.local/share)
+ $XDG_DATA_DIRS
+```
+
+The "XDG_..._HOME" default directories can be configured to be other directories
+at build time.
+
+To each of these paths will be added a suffix to narrow down the search and
+prevent attempted loading of invalid content.
+First, the string "/vulkan" is appended so the loader will only look for
+information in a **/vulkan** sub-folder.
+Second, the string **/icd.d** is appended to indicate the loader is specifically
+looking for only ICDs.
+
+An example combined search path for ICDs may look like this:
+
```
/usr/local/etc/vulkan/icd.d
/usr/local/share/vulkan/icd.d
$HOME/.local/share/vulkan/icd.d
```
-The "/usr/local/*" directories can be configured to be other directories at
-build time.
-
-The typical usage of the directories is indicated in the table below.
-
-| Location | Details |
-|-------------------|------------------------|
-| $HOME/.local/share/vulkan/icd.d | $HOME is the current home directory of the application's user id; this path will be ignored for suid programs |
-| "/usr/local/etc/vulkan/icd.d" | Directory for locally built ICDs |
-| "/usr/local/share/vulkan/icd.d" | Directory for locally built ICDs |
-| "/etc/vulkan/icd.d" | Location of ICDs installed from non-Linux-distribution-provided packages |
-| "/usr/share/vulkan/icd.d" | Location of ICDs installed from Linux-distribution-provided packages |
+<b>IMPORTANT NOTE!</b> Any path using $HOME is ignored for all suid programs for
+security reasons.
The Vulkan loader will open each manifest file found to obtain the name or
pathname of an ICD shared library (".so") file.
in the following directories:
```
- <bundle>/Contents/Resources/vulkan/icd.d
- /etc/vulkan/icd.d
- /usr/local/share/vulkan/icd.d
- /usr/share/vulkan/icd.d
- $HOME/.local/share/vulkan/icd.d
+ <bundle>/Contents/Resources
+ $XDG_CONFIG_HOME (or if not defined $HOME/.config)
+ $XDG_CONFIG_DIRS
+ $SYSCONFDIR (or if not defined /etc)
+ $EXTRASYSCONFDIR (or ir not defined /etc)
+ $XDG_DATA_HOME (or if not defined $HOME/.local/share)
+ $XDG_DATA_DIRS
```
-The "/usr/local/*" directories can be configured to be other directories at
-build time.
+The "XDG_..._HOME" default directories can be configured to be other directories
+at build time.
The typical usage of the directories is indicated in the table below.
size_t rel_size = 0;
bool use_first_found_manifest = false;
#ifndef _WIN32
- bool xdgconfig_alloc = true;
- bool xdgdata_alloc = true;
+ bool xdg_config_home_secenv_alloc = true;
+ bool xdg_config_dirs_secenv_alloc = true;
+ bool xdg_data_home_secenv_alloc = true;
+ bool xdg_data_dirs_secenv_alloc = true;
#endif
#ifndef _WIN32
// Determine how much space is needed to generate the full search path
// for the current manifest files.
- char *xdgconfdirs = loader_secure_getenv("XDG_CONFIG_DIRS", inst);
- char *xdgdatadirs = loader_secure_getenv("XDG_DATA_DIRS", inst);
- char *xdgdatahome = loader_secure_getenv("XDG_DATA_HOME", inst);
- char *home = NULL;
- char *home_root = NULL;
-
- if (xdgconfdirs == NULL) {
- xdgconfig_alloc = false;
+ char *xdg_config_home = loader_secure_getenv("XDG_CONFIG_HOME", inst);
+ if (NULL == xdg_config_home) {
+ xdg_config_home_secenv_alloc = false;
}
- if (xdgdatadirs == NULL) {
- xdgdata_alloc = false;
+
+ char *xdg_config_dirs = loader_secure_getenv("XDG_CONFIG_DIRS", inst);
+ if (NULL == xdg_config_dirs) {
+ xdg_config_dirs_secenv_alloc = false;
}
#if !defined(__Fuchsia__) && !defined(__QNXNTO__)
- if (xdgconfdirs == NULL || xdgconfdirs[0] == '\0') {
- xdgconfdirs = FALLBACK_CONFIG_DIRS;
+ if (NULL == xdg_config_dirs || '\0' == xdg_config_dirs[0]) {
+ xdg_config_dirs = FALLBACK_CONFIG_DIRS;
+ }
+#endif
+
+ char *xdg_data_home = loader_secure_getenv("XDG_DATA_HOME", inst);
+ if (NULL == xdg_data_home) {
+ xdg_data_home_secenv_alloc = false;
+ }
+
+ char *xdg_data_dirs = loader_secure_getenv("XDG_DATA_DIRS", inst);
+ if (NULL == xdg_data_dirs) {
+ xdg_data_dirs_secenv_alloc = false;
}
- if (xdgdatadirs == NULL || xdgdatadirs[0] == '\0') {
- xdgdatadirs = FALLBACK_DATA_DIRS;
+#if !defined(__Fuchsia__) && !defined(__QNXNTO__)
+ if (NULL == xdg_data_dirs || '\0' == xdg_data_dirs[0]) {
+ xdg_data_dirs = FALLBACK_DATA_DIRS;
}
#endif
+ char *home = NULL;
+ char *default_data_home = NULL;
+ char *default_config_home = NULL;
+
// Only use HOME if XDG_DATA_HOME is not present on the system
- if (NULL == xdgdatahome) {
- home = loader_secure_getenv("HOME", inst);
- if (home != NULL) {
- home_root = loader_instance_heap_alloc(inst, strlen(home) + 14, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
- if (home_root == NULL) {
+ home = loader_secure_getenv("HOME", inst);
+ if (home != NULL) {
+ if (NULL == xdg_config_home || '\0' == xdg_config_home[0]) {
+ const char config_suffix[] = "/.config";
+ default_config_home =
+ loader_instance_heap_alloc(inst, strlen(home) + strlen(config_suffix) + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+ if (default_config_home == NULL) {
+ vk_result = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ strcpy(default_config_home, home);
+ strcat(default_config_home, config_suffix);
+ }
+ if (NULL == xdg_data_home || '\0' == xdg_data_home[0]) {
+ const char data_suffix[] = "/.local/share";
+ default_data_home =
+ loader_instance_heap_alloc(inst, strlen(home) + strlen(data_suffix) + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+ if (default_data_home == NULL) {
vk_result = VK_ERROR_OUT_OF_HOST_MEMORY;
goto out;
}
- strcpy(home_root, home);
- strcat(home_root, "/.local/share");
+ strcpy(default_data_home, home);
+ strcat(default_data_home, data_suffix);
}
}
-#endif
+#endif // !_WIN32
if (path_override != NULL) {
override_path = path_override;
search_path_size += MAXPATHLEN;
#endif
#ifndef _WIN32
- search_path_size += DetermineDataFilePathSize(xdgconfdirs, rel_size);
- search_path_size += DetermineDataFilePathSize(xdgdatadirs, rel_size);
+ // Only add the home folders if not ICD filenames or superuser
+ if (is_directory_list && !IsHighIntegrity()) {
+ if (NULL != default_config_home) {
+ search_path_size += DetermineDataFilePathSize(default_config_home, rel_size);
+ } else {
+ search_path_size += DetermineDataFilePathSize(xdg_config_home, rel_size);
+ }
+ }
+ search_path_size += DetermineDataFilePathSize(xdg_config_dirs, rel_size);
search_path_size += DetermineDataFilePathSize(SYSCONFDIR, rel_size);
#if defined(EXTRASYSCONFDIR)
search_path_size += DetermineDataFilePathSize(EXTRASYSCONFDIR, rel_size);
#endif
- if (is_directory_list) {
- if (!IsHighIntegrity()) {
- search_path_size += DetermineDataFilePathSize(xdgdatahome, rel_size);
- search_path_size += DetermineDataFilePathSize(home_root, rel_size);
+ // Only add the home folders if not ICD filenames or superuser
+ if (is_directory_list && !IsHighIntegrity()) {
+ if (NULL != default_data_home) {
+ search_path_size += DetermineDataFilePathSize(default_data_home, rel_size);
+ } else {
+ search_path_size += DetermineDataFilePathSize(xdg_data_home, rel_size);
}
}
-#endif
+ search_path_size += DetermineDataFilePathSize(xdg_data_dirs, rel_size);
+#endif // !_WIN32
}
}
CFRelease(ref);
}
}
-#endif
- CopyDataFilePath(xdgconfdirs, relative_location, rel_size, &cur_path_ptr);
+#endif // __APPLE__
+ // Only add the home folders if not ICD filenames or superuser
+ if (is_directory_list && !IsHighIntegrity()) {
+ if (NULL != default_config_home) {
+ CopyDataFilePath(default_config_home, relative_location, rel_size, &cur_path_ptr);
+ } else {
+ CopyDataFilePath(xdg_config_home, relative_location, rel_size, &cur_path_ptr);
+ }
+ }
+ CopyDataFilePath(xdg_config_dirs, relative_location, rel_size, &cur_path_ptr);
CopyDataFilePath(SYSCONFDIR, relative_location, rel_size, &cur_path_ptr);
#if defined(EXTRASYSCONFDIR)
CopyDataFilePath(EXTRASYSCONFDIR, relative_location, rel_size, &cur_path_ptr);
#endif
- CopyDataFilePath(xdgdatadirs, relative_location, rel_size, &cur_path_ptr);
- if (is_directory_list) {
- CopyDataFilePath(xdgdatahome, relative_location, rel_size, &cur_path_ptr);
- CopyDataFilePath(home_root, relative_location, rel_size, &cur_path_ptr);
+
+ // Only add the home folders if not ICD filenames or superuser
+ if (is_directory_list && !IsHighIntegrity()) {
+ if (NULL != default_data_home) {
+ CopyDataFilePath(default_data_home, relative_location, rel_size, &cur_path_ptr);
+ } else {
+ CopyDataFilePath(xdg_data_home, relative_location, rel_size, &cur_path_ptr);
+ }
}
+ CopyDataFilePath(xdg_data_dirs, relative_location, rel_size, &cur_path_ptr);
}
// Remove the last path separator
assert(cur_path_ptr - search_path < (ptrdiff_t)search_path_size);
*cur_path_ptr = '\0';
-#endif
+#endif // !_WIN32
}
// Remove duplicate paths, or it would result in duplicate extensions, duplicate devices, etc.
loader_free_getenv(override_env, inst);
}
#ifndef _WIN32
- if (xdgconfig_alloc) {
- loader_free_getenv(xdgconfdirs, inst);
+ if (xdg_config_home_secenv_alloc) {
+ loader_free_getenv(xdg_config_home, inst);
+ }
+ if (xdg_config_dirs_secenv_alloc) {
+ loader_free_getenv(xdg_config_dirs, inst);
}
- if (xdgdata_alloc) {
- loader_free_getenv(xdgdatadirs, inst);
+ if (xdg_data_home_secenv_alloc) {
+ loader_free_getenv(xdg_data_home, inst);
}
- if (NULL != xdgdatahome) {
- loader_free_getenv(xdgdatahome, inst);
+ if (xdg_data_dirs_secenv_alloc) {
+ loader_free_getenv(xdg_data_dirs, inst);
+ }
+ if (NULL != xdg_data_home) {
+ loader_free_getenv(xdg_data_home, inst);
}
if (NULL != home) {
loader_free_getenv(home, inst);
}
- if (NULL != home_root) {
- loader_instance_heap_free(inst, home_root);
+ if (NULL != default_data_home) {
+ loader_instance_heap_free(inst, default_data_home);
+ }
+ if (NULL != default_config_home) {
+ loader_instance_heap_free(inst, default_config_home);
}
#endif
inline void PlatformShim::redirect_category(fs::path const& new_path, ManifestCategory category) {
std::vector<std::string> xdg_paths;
- std::string xdg_data_dirs_var = get_env_var("XDG_DATA_DIRS");
- if (xdg_data_dirs_var.size() == 0) {
- xdg_data_dirs_var = FALLBACK_CONFIG_DIRS;
+ std::string home = get_env_var("HOME");
+ if (home.size() != 0) {
+ std::string xdg_config_home_path = fs::path(home).c_str();
+ xdg_config_home_path += "/.config";
+ xdg_paths.push_back(xdg_config_home_path);
}
- auto data_dirs_paths = parse_env_var_list(xdg_data_dirs_var);
- xdg_paths.insert(xdg_paths.begin(), data_dirs_paths.begin(), data_dirs_paths.end());
std::string xdg_config_dirs_var = get_env_var("XDG_CONFIG_DIRS");
if (xdg_config_dirs_var.size() == 0) {
- xdg_config_dirs_var = FALLBACK_DATA_DIRS;
+ xdg_config_dirs_var = FALLBACK_CONFIG_DIRS;
}
auto config_dirs_paths = parse_env_var_list(xdg_config_dirs_var);
- xdg_paths.insert(xdg_paths.begin(), config_dirs_paths.begin(), config_dirs_paths.end());
+ xdg_paths.insert(xdg_paths.end(), config_dirs_paths.begin(), config_dirs_paths.end());
- add(fs::path(SYSCONFDIR) / "vulkan" / category_path_name(category), new_path);
+ xdg_paths.push_back(fs::path(SYSCONFDIR).c_str());
#if defined(EXTRASYSCONFDIR)
// EXTRASYSCONFDIR default is /etc, if SYSCONFDIR wasn't defined, it will have /etc put
// as its default. Don't want to double add it
if (!string_eq(SYSCONFDIR, EXTRASYSCONFDIR)) {
- add(fs::path(EXTRASYSCONFDIR) / "vulkan" / category_path_name(category), new_path);
+ xdg_paths.push_back(fs::path(EXTRASYSCONFDIR).c_str());
}
#endif
+ if (home.size() != 0) {
+ std::string xdg_data_home_path = fs::path(home).c_str();
+ xdg_data_home_path += "/.local/share";
+ xdg_paths.push_back(xdg_data_home_path);
+ }
- for (auto& path : xdg_paths) {
- add(fs::path(path) / "vulkan" / category_path_name(category), new_path);
+ std::string xdg_data_dirs_var = get_env_var("XDG_DATA_DIRS");
+ if (xdg_data_dirs_var.size() == 0) {
+ xdg_data_dirs_var = FALLBACK_DATA_DIRS;
}
+ auto data_dirs_paths = parse_env_var_list(xdg_data_dirs_var);
+ xdg_paths.insert(xdg_paths.end(), data_dirs_paths.begin(), data_dirs_paths.end());
- std::string home = get_env_var("HOME");
- if (home.size() != 0) {
- add(fs::path(home) / ".local/share/vulkan" / category_path_name(category), new_path);
+ for (auto& path : xdg_paths) {
+ add(fs::path(path) / "vulkan" / category_path_name(category), new_path);
}
}
# Set vars to include some "challenging" paths and run the test.
output=$(VK_LOADER_DEBUG=all \
- XDG_CONFIG_DIRS=":/tmp/goober:::::/tmp/goober2/:/tmp/goober3/with spaces:::" \
- XDG_DATA_DIRS="::::/tmp/goober4:::::/tmp/goober5:/tmp/goober6/with spaces::::/tmp/goober7:" \
+ XDG_CONFIG_DIRS=":/tmp/goober:::::/tmp/goober2/::::" \
+ XDG_DATA_DIRS="::::/tmp/goober3:/tmp/goober4/with spaces:::" \
VK_LAYER_PATH=${vk_layer_path} \
GTEST_FILTER=CreateInstance.LayerPresent \
./vk_loader_validation_tests 2>&1)
# Here is a path we expect to find. The loader constructs these from the XDG* env vars.
- right_path="/tmp/goober/vulkan/icd.d:/tmp/goober2/vulkan/icd.d:/tmp/goober3/with spaces/vulkan/icd.d"
+ right_path="$HOME/.config/vulkan/icd.d:/tmp/goober/vulkan/icd.d:/tmp/goober2/vulkan/icd.d"
# There are other paths that come from SYSCONFIG settings established at build time.
# So we can't really guess at what those are here.
right_path+=".*"
# Also expect to find these, since we added them.
- right_path+="/tmp/goober4/vulkan/icd.d:/tmp/goober5/vulkan/icd.d:/tmp/goober6/with spaces/vulkan/icd.d:/tmp/goober7/vulkan/icd.d"
- echo "$output" | grep -q "$right_path"
+ right_path+="$HOME/.local/share/vulkan/icd.d:/tmp/goober3/vulkan/icd.d:/tmp/goober4/with spaces/vulkan/icd.d"
+
+ # Find just the line we're interested in
+ manifest_path_output=`grep "Searching the following paths for manifest files.*icd.d" <<< $output`
+ echo "$manifest_path_output" | grep -q "$right_path"
ec=$?
if [ $ec -eq 1 ]
then
fi
# Change the string to implicit layers.
right_path=${right_path//icd.d/implicit_layer.d}
- echo "$output" | grep -q "$right_path"
+ manifest_path_output=`grep "Searching the following paths for manifest files.*implicit_layer.d" <<< $output`
+ echo "$manifest_path_output" | grep -q "$right_path"
ec=$?
if [ $ec -eq 1 ]
then
# The loader cleans up this path to remove the empty paths, so we need to clean up the right path, too
right_path="${vk_layer_path//:::::/:}"
right_path="${right_path//::::/:}"
- echo "$output" | grep -q "$right_path"
+ echo "$manifest_path_output" | grep -q "$right_path"
ec=$?
if [ $ec -eq 1 ]
then