loader: Null-terminated string checks
diff --git a/loader/loader.c b/loader/loader.c
index 1e213e1..df1c219 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -3234,29 +3234,45 @@
return res;
}
-VkResult loader_validate_layers(const uint32_t layer_count,
+VkResult loader_validate_layers(const struct loader_instance *inst,
+ const uint32_t layer_count,
const char *const *ppEnabledLayerNames,
const struct loader_layer_list *list) {
struct loader_layer_properties *prop;
for (uint32_t i = 0; i < layer_count; i++) {
+ VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, ppEnabledLayerNames[i]);
+ if (result != VK_STRING_ERROR_NONE) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "Loader: Device ppEnabledLayerNames contains string that is too long or is badly formed");
+ return VK_ERROR_LAYER_NOT_PRESENT;
+ }
+
prop = loader_get_layer_property(ppEnabledLayerNames[i], list);
if (!prop) {
return VK_ERROR_LAYER_NOT_PRESENT;
}
}
-
return VK_SUCCESS;
}
VkResult loader_validate_instance_extensions(
+ const struct loader_instance *inst,
const struct loader_extension_list *icd_exts,
const struct loader_layer_list *instance_layer,
const VkInstanceCreateInfo *pCreateInfo) {
+
VkExtensionProperties *extension_prop;
struct loader_layer_properties *layer_prop;
for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
+ VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
+ if (result != VK_STRING_ERROR_NONE) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "Loader: Instance ppEnabledExtensionNames contains string that is too long or is badly formed");
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
+ }
+
extension_prop = get_extension_property(
pCreateInfo->ppEnabledExtensionNames[i], icd_exts);
@@ -3304,6 +3320,14 @@
struct loader_layer_properties *layer_prop;
for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
+
+ VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
+ if (result != VK_STRING_ERROR_NONE) {
+ loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "Loader: Device ppEnabledExtensionNames contains string that is too long or is badly formed");
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
+ }
+
const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
extension_prop = get_extension_property(
extension_name, &phys_dev->device_extension_cache);
@@ -3720,7 +3744,8 @@
/* validate any app enabled layers are available */
if (pCreateInfo->enabledLayerCount > 0) {
- res = loader_validate_layers(pCreateInfo->enabledLayerCount,
+ res = loader_validate_layers(inst,
+ pCreateInfo->enabledLayerCount,
pCreateInfo->ppEnabledLayerNames,
&inst->device_layer_list);
if (res != VK_SUCCESS) {
@@ -3902,12 +3927,17 @@
/* get layer libraries if needed */
if (pLayerName && strlen(pLayerName) != 0) {
- loader_layer_scan(NULL, &instance_layers, NULL);
- for (uint32_t i = 0; i < instance_layers.count; i++) {
- struct loader_layer_properties *props = &instance_layers.list[i];
- if (strcmp(props->info.layerName, pLayerName) == 0) {
- global_ext_list = &props->instance_extension_list;
+ if (vk_string_validate(MaxLoaderStringLength, pLayerName) == VK_STRING_ERROR_NONE) {
+ loader_layer_scan(NULL, &instance_layers, NULL);
+ for (uint32_t i = 0; i < instance_layers.count; i++) {
+ struct loader_layer_properties *props = &instance_layers.list[i];
+ if (strcmp(props->info.layerName, pLayerName) == 0) {
+ global_ext_list = &props->instance_extension_list;
+ }
}
+ } else {
+ assert(VK_FALSE && "vkEnumerateInstanceExtensionProperties: pLayerName is too long or is badly formed");
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
}
} else {
/* Scan/discover all ICD libraries */
@@ -3981,6 +4011,7 @@
memcpy(&pProperties[i], &instance_layer_list.list[i].info,
sizeof(VkLayerProperties));
}
+
*pPropertyCount = copy_size;
loader_destroy_layer_list(NULL, &instance_layer_list);
@@ -4008,31 +4039,36 @@
/* get layer libraries if needed */
if (pLayerName && strlen(pLayerName) != 0) {
- for (uint32_t i = 0;
- i < phys_dev->this_instance->device_layer_list.count; i++) {
- struct loader_layer_properties *props =
- &phys_dev->this_instance->device_layer_list.list[i];
- if (strcmp(props->info.layerName, pLayerName) == 0) {
- dev_ext_list = &props->device_extension_list;
+ if (vk_string_validate(MaxLoaderStringLength, pLayerName) == VK_STRING_ERROR_NONE) {
+ for (uint32_t i = 0;
+ i < phys_dev->this_instance->device_layer_list.count; i++) {
+ struct loader_layer_properties *props =
+ &phys_dev->this_instance->device_layer_list.list[i];
+ if (strcmp(props->info.layerName, pLayerName) == 0) {
+ dev_ext_list = &props->device_extension_list;
+ }
}
- }
- count = (dev_ext_list == NULL) ? 0 : dev_ext_list->count;
- if (pProperties == NULL) {
- *pPropertyCount = count;
- return VK_SUCCESS;
- }
+ count = (dev_ext_list == NULL) ? 0: dev_ext_list->count;
+ if (pProperties == NULL) {
+ *pPropertyCount = count;
+ return VK_SUCCESS;
+ }
- copy_size = *pPropertyCount < count ? *pPropertyCount : count;
- for (uint32_t i = 0; i < copy_size; i++) {
- memcpy(&pProperties[i], &dev_ext_list->list[i].props,
- sizeof(VkExtensionProperties));
- }
- *pPropertyCount = copy_size;
+ copy_size = *pPropertyCount < count ? *pPropertyCount : count;
+ for (uint32_t i = 0; i < copy_size; i++) {
+ memcpy(&pProperties[i], &dev_ext_list->list[i].props,
+ sizeof(VkExtensionProperties));
+ }
+ *pPropertyCount = copy_size;
- if (copy_size < count) {
- return VK_INCOMPLETE;
+ if (copy_size < count) {
+ return VK_INCOMPLETE;
+ }
+ } else {
+ loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "vkEnumerateDeviceExtensionProperties: pLayerName is too long or is badly formed");
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
}
-
return VK_SUCCESS;
} else {
/* this case is during the call down the instance chain with pLayerName
@@ -4040,6 +4076,7 @@
struct loader_icd *icd = phys_dev->this_icd;
uint32_t icd_ext_count = *pPropertyCount;
VkResult res;
+
/* get device extensions */
res = icd->EnumerateDeviceExtensionProperties(
phys_dev->phys_dev, NULL, &icd_ext_count, pProperties);
@@ -4159,3 +4196,40 @@
return VK_SUCCESS;
}
+
+VkStringErrorFlags vk_string_validate(const int max_length, const char *utf8)
+{
+ VkStringErrorFlags result = VK_STRING_ERROR_NONE;
+ int num_char_bytes;
+ int i,j;
+
+ for (i = 0; i < max_length; i++)
+ {
+ if (utf8[i] == 0) {
+ break;
+ } else if ((utf8[i] > 0x20) && (utf8[i] < 0x7f)) {
+ num_char_bytes = 0;
+ } else if ((utf8[i] & UTF8_ONE_BYTE_MASK) == UTF8_ONE_BYTE_CODE) {
+ num_char_bytes = 1;
+ } else if ((utf8[i] & UTF8_TWO_BYTE_MASK) == UTF8_TWO_BYTE_CODE) {
+ num_char_bytes = 2;
+ } else if ((utf8[i] & UTF8_THREE_BYTE_MASK) == UTF8_THREE_BYTE_CODE) {
+ num_char_bytes = 3;
+ } else {
+ result = VK_STRING_ERROR_BAD_DATA;
+ }
+
+ // Validate the following num_char_bytes of data
+ for (j = 0; (j < num_char_bytes) && (i < max_length); j++) {
+ if (++i == max_length) {
+ result |= VK_STRING_ERROR_LENGTH;
+ break;
+ }
+ if ((utf8[i] & UTF8_DATA_BYTE_MASK) != UTF8_DATA_BYTE_CODE) {
+ result |= VK_STRING_ERROR_BAD_DATA;
+ }
+ }
+ }
+ return result;
+}
+
diff --git a/loader/loader.h b/loader/loader.h
index ac20d74..2c89460 100644
--- a/loader/loader.h
+++ b/loader/loader.h
@@ -72,6 +72,24 @@
0xc, // both instance and device layer, bitwise
};
+
+typedef enum VkStringErrorFlagBits {
+ VK_STRING_ERROR_NONE = 0x00000000,
+ VK_STRING_ERROR_LENGTH = 0x00000001,
+ VK_STRING_ERROR_BAD_DATA = 0x00000002,
+} VkStringErrorFlagBits;
+typedef VkFlags VkStringErrorFlags;
+
+static const int MaxLoaderStringLength = 256;
+static const char UTF8_ONE_BYTE_CODE = 0xC0;
+static const char UTF8_ONE_BYTE_MASK = 0xE0;
+static const char UTF8_TWO_BYTE_CODE = 0xE0;
+static const char UTF8_TWO_BYTE_MASK = 0xF0;
+static const char UTF8_THREE_BYTE_CODE = 0xF0;
+static const char UTF8_THREE_BYTE_MASK = 0xF8;
+static const char UTF8_DATA_BYTE_CODE = 0x80;
+static const char UTF8_DATA_BYTE_MASK = 0xC0;
+
// form of all dynamic lists/arrays
// only the list element should be changed
struct loader_generic_list {
@@ -370,11 +388,13 @@
bool compare_vk_extension_properties(const VkExtensionProperties *op1,
const VkExtensionProperties *op2);
-VkResult loader_validate_layers(const uint32_t layer_count,
+VkResult loader_validate_layers(const struct loader_instance *inst,
+ const uint32_t layer_count,
const char *const *ppEnabledLayerNames,
const struct loader_layer_list *list);
VkResult loader_validate_instance_extensions(
+ const struct loader_instance *inst,
const struct loader_extension_list *icd_exts,
const struct loader_layer_list *instance_layer,
const VkInstanceCreateInfo *pCreateInfo);
@@ -507,4 +527,7 @@
void *loader_tls_heap_alloc(size_t size);
void loader_tls_heap_free(void *pMemory);
+
+VkStringErrorFlags vk_string_validate(const int max_length, const char *char_array);
+
#endif /* LOADER_H */
diff --git a/loader/trampoline.c b/loader/trampoline.c
index 7cf6f55..98205b9 100644
--- a/loader/trampoline.c
+++ b/loader/trampoline.c
@@ -110,7 +110,8 @@
/* validate the app requested layers to be enabled */
if (pCreateInfo->enabledLayerCount > 0) {
- res = loader_validate_layers(pCreateInfo->enabledLayerCount,
+ res = loader_validate_layers(ptr_instance,
+ pCreateInfo->enabledLayerCount,
pCreateInfo->ppEnabledLayerNames,
&ptr_instance->instance_layer_list);
if (res != VK_SUCCESS) {
@@ -130,7 +131,7 @@
loader_get_icd_loader_instance_extensions(
ptr_instance, &ptr_instance->icd_libs, &ptr_instance->ext_list);
res = loader_validate_instance_extensions(
- &ptr_instance->ext_list, &ptr_instance->instance_layer_list,
+ ptr_instance, &ptr_instance->ext_list, &ptr_instance->instance_layer_list,
pCreateInfo);
if (res != VK_SUCCESS) {
loader_delete_layer_properties(ptr_instance,