feature: Adding kernel sizes validation in ocloc

This commit adds a validation layer in ocloc,
which is designed to check if the data read from
the binary file does not exceed the size of the section.

Related-To: NEO-8062
Signed-off-by: Daria Hinz <daria.hinz@intel.com>
This commit is contained in:
Daria Hinz
2023-06-29 10:58:05 +00:00
committed by Compute-Runtime-Automation
parent 048dbaffc0
commit a6fee8994d
4 changed files with 113 additions and 56 deletions

View File

@@ -35,13 +35,14 @@ T readUnaligned(const void *ptr) {
int BinaryDecoder::decode() {
parseTokens();
std::stringstream ptmFile;
auto devBinPtr = getDevBinary();
if (devBinPtr == nullptr) {
auto [ptr, size] = getDevBinary();
if (ptr == nullptr) {
argHelper->printf("Error! Device Binary section was not found.\n");
abortOclocExecution(1);
return -1;
}
return processBinary(devBinPtr, ptmFile);
return processBinary(ptr, size, ptmFile);
}
void BinaryDecoder::dumpField(const void *&binaryPtr, const PTField &field, std::ostream &ptmFile) {
@@ -82,13 +83,13 @@ bool isPatchtokensBinary(const ContainerT &data) {
return intcMagic == binaryMagic;
}
const void *BinaryDecoder::getDevBinary() {
std::pair<const void *, size_t> BinaryDecoder::getDevBinary() {
binary = argHelper->readBinaryFile(binaryFile);
const void *data = nullptr;
if (isPatchtokensBinary(binary)) {
return binary.data();
return {binary.data(), binary.size()};
}
std::pair<const void *, size_t> data(nullptr, 0u);
std::string decoderErrors;
std::string decoderWarnings;
auto input = ArrayRef<const uint8_t>(reinterpret_cast<const uint8_t *>(binary.data()), binary.size());
@@ -109,7 +110,7 @@ const void *BinaryDecoder::getDevBinary() {
break;
}
case NEO::Elf::SHT_OPENCL_DEV_BINARY: {
data = sectionData.begin();
data = {sectionData.begin(), sectionData.size()};
break;
}
default:
@@ -333,7 +334,7 @@ Examples:
argHelper->createStringForArgs(argHelper->productConfigHelper->getDeviceAcronyms()).c_str());
}
int BinaryDecoder::processBinary(const void *&ptr, std::ostream &ptmFile) {
int BinaryDecoder::processBinary(const void *&ptr, size_t sectionSize, std::ostream &ptmFile) {
ptmFile << "ProgramBinaryHeader:\n";
uint32_t numberOfKernels = 0, patchListSize = 0, device = 0;
for (const auto &v : programHeader.fields) {
@@ -356,79 +357,100 @@ int BinaryDecoder::processBinary(const void *&ptr, std::ostream &ptmFile) {
// Reading Kernels
for (uint32_t i = 0; i < numberOfKernels; ++i) {
ptmFile << "Kernel #" << i << '\n';
processKernel(ptr, ptmFile);
processKernel(ptr, sectionSize, ptmFile);
}
argHelper->saveOutput(pathToDump + "PTM.txt", ptmFile);
return 0;
}
void BinaryDecoder::processKernel(const void *&ptr, std::ostream &ptmFile) {
uint32_t kernelNameSize = 0, kernelPatchListSize = 0, kernelHeapSize = 0, kernelHeapUnpaddedSize = 0,
generalStateHeapSize = 0, dynamicStateHeapSize = 0, surfaceStateHeapSize = 0;
void BinaryDecoder::validateLoadedKernelData(KernelSizeData kernelLoadedData, size_t sectionSize) {
if (kernelLoadedData.size > sectionSize) {
argHelper->printf("Error! %s loaded from KernelBinaryHeader is invalid: %d.\n", kernelLoadedData.name.str().c_str(), kernelLoadedData.size);
abortOclocExecution(1);
}
}
void BinaryDecoder::processKernel(const void *&ptr, size_t sectionSize, std::ostream &ptmFile) {
KernelSizeData kernelPatchListSize{"PatchListSize", 0u},
kernelNameSize{"KernelNameSize", 0u},
kernelHeapSize{"KernelHeapSize", 0u},
kernelHeapUnpaddedSize{"KernelUnpaddedSize", 0u},
generalStateHeapSize{"GeneralStateHeapSize", 0u},
dynamicStateHeapSize{"DynamicStateHeapSize", 0u},
surfaceStateHeapSize{"SurfaceStateHeapSize", 0u};
ptmFile << "KernelBinaryHeader:\n";
for (const auto &v : kernelHeader.fields) {
if (v.name == "PatchListSize")
kernelPatchListSize = readUnaligned<uint32_t>(ptr);
else if (v.name == "KernelNameSize")
kernelNameSize = readUnaligned<uint32_t>(ptr);
else if (v.name == "KernelHeapSize")
kernelHeapSize = readUnaligned<uint32_t>(ptr);
else if (v.name == "KernelUnpaddedSize")
kernelHeapUnpaddedSize = readUnaligned<uint32_t>(ptr);
else if (v.name == "GeneralStateHeapSize")
generalStateHeapSize = readUnaligned<uint32_t>(ptr);
else if (v.name == "DynamicStateHeapSize")
dynamicStateHeapSize = readUnaligned<uint32_t>(ptr);
else if (v.name == "SurfaceStateHeapSize")
surfaceStateHeapSize = readUnaligned<uint32_t>(ptr);
if (v.name == kernelPatchListSize.name)
kernelPatchListSize.size = readUnaligned<uint32_t>(ptr);
else if (v.name == kernelNameSize.name)
kernelNameSize.size = readUnaligned<uint32_t>(ptr);
else if (v.name == kernelHeapSize.name)
kernelHeapSize.size = readUnaligned<uint32_t>(ptr);
else if (v.name == kernelHeapUnpaddedSize.name)
kernelHeapUnpaddedSize.size = readUnaligned<uint32_t>(ptr);
else if (v.name == generalStateHeapSize.name)
generalStateHeapSize.size = readUnaligned<uint32_t>(ptr);
else if (v.name == dynamicStateHeapSize.name)
dynamicStateHeapSize.size = readUnaligned<uint32_t>(ptr);
else if (v.name == surfaceStateHeapSize.name)
surfaceStateHeapSize.size = readUnaligned<uint32_t>(ptr);
dumpField(ptr, v, ptmFile);
}
if (kernelNameSize == 0) {
if (kernelNameSize.size == 0) {
argHelper->printf("Error! KernelNameSize was 0.\n");
abortOclocExecution(1);
}
validateLoadedKernelData(kernelNameSize, sectionSize);
validateLoadedKernelData(kernelPatchListSize, sectionSize);
validateLoadedKernelData(kernelHeapSize, sectionSize);
validateLoadedKernelData(kernelHeapUnpaddedSize, sectionSize);
validateLoadedKernelData(generalStateHeapSize, sectionSize);
validateLoadedKernelData(dynamicStateHeapSize, sectionSize);
validateLoadedKernelData(surfaceStateHeapSize, sectionSize);
ptmFile << "\tKernelName ";
std::string kernelName(static_cast<const char *>(ptr), 0, kernelNameSize);
std::string kernelName(static_cast<const char *>(ptr), 0, kernelNameSize.size);
ptmFile << kernelName << '\n';
ptr = ptrOffset(ptr, kernelNameSize);
ptr = ptrOffset(ptr, kernelNameSize.size);
std::string fileName = pathToDump + kernelName + "_KernelHeap";
argHelper->printf("Trying to disassemble %s.krn\n", kernelName.c_str());
std::string disassembledKernel;
if (iga->tryDisassembleGenISA(ptr, kernelHeapUnpaddedSize, disassembledKernel)) {
if (iga->tryDisassembleGenISA(ptr, kernelHeapUnpaddedSize.size, disassembledKernel)) {
argHelper->saveOutput(fileName + ".asm", disassembledKernel.data(), disassembledKernel.size());
} else {
if (ignoreIsaPadding) {
argHelper->saveOutput(fileName + ".dat", ptr, kernelHeapUnpaddedSize);
argHelper->saveOutput(fileName + ".dat", ptr, kernelHeapUnpaddedSize.size);
} else {
argHelper->saveOutput(fileName + ".dat", ptr, kernelHeapSize);
argHelper->saveOutput(fileName + ".dat", ptr, kernelHeapSize.size);
}
}
ptr = ptrOffset(ptr, kernelHeapSize);
ptr = ptrOffset(ptr, kernelHeapSize.size);
if (generalStateHeapSize != 0) {
if (generalStateHeapSize.size != 0) {
argHelper->printf("Warning! GeneralStateHeapSize wasn't 0.\n");
fileName = pathToDump + kernelName + "_GeneralStateHeap.bin";
argHelper->saveOutput(fileName, ptr, dynamicStateHeapSize);
ptr = ptrOffset(ptr, generalStateHeapSize);
argHelper->saveOutput(fileName, ptr, dynamicStateHeapSize.size);
ptr = ptrOffset(ptr, generalStateHeapSize.size);
}
fileName = pathToDump + kernelName + "_DynamicStateHeap.bin";
argHelper->saveOutput(fileName, ptr, dynamicStateHeapSize);
ptr = ptrOffset(ptr, dynamicStateHeapSize);
argHelper->saveOutput(fileName, ptr, dynamicStateHeapSize.size);
ptr = ptrOffset(ptr, dynamicStateHeapSize.size);
fileName = pathToDump + kernelName + "_SurfaceStateHeap.bin";
argHelper->saveOutput(fileName, ptr, surfaceStateHeapSize);
ptr = ptrOffset(ptr, surfaceStateHeapSize);
argHelper->saveOutput(fileName, ptr, surfaceStateHeapSize.size);
ptr = ptrOffset(ptr, surfaceStateHeapSize.size);
if (kernelPatchListSize == 0) {
if (kernelPatchListSize.size == 0) {
argHelper->printf("Warning! Kernel's patch list size was 0.\n");
}
readPatchTokens(ptr, kernelPatchListSize, ptmFile);
readPatchTokens(ptr, kernelPatchListSize.size, ptmFile);
}
void BinaryDecoder::readPatchTokens(const void *&patchListPtr, uint32_t patchListSize, std::ostream &ptmFile) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2022 Intel Corporation
* Copyright (C) 2018-2023 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -24,10 +24,16 @@ struct BinaryHeader {
std::vector<PTField> fields;
uint32_t size = 0U;
};
struct PatchToken : BinaryHeader {
std::string name;
};
struct KernelSizeData {
NEO::ConstStringRef name;
uint32_t size = 0u;
};
using PTMap = std::unordered_map<uint8_t, std::unique_ptr<PatchToken>>;
class BinaryDecoder {
@@ -58,12 +64,13 @@ class BinaryDecoder {
void dumpField(const void *&binaryPtr, const PTField &field, std::ostream &ptmFile);
uint8_t getSize(const std::string &typeStr);
MOCKABLE_VIRTUAL const void *getDevBinary();
MOCKABLE_VIRTUAL std::pair<const void *, size_t> getDevBinary();
std::vector<std::string> loadPatchList();
MOCKABLE_VIRTUAL void parseTokens();
int processBinary(const void *&ptr, std::ostream &ptmFile);
void processKernel(const void *&ptr, std::ostream &ptmFile);
int processBinary(const void *&ptr, size_t sectionSize, std::ostream &ptmFile);
void processKernel(const void *&ptr, size_t sectionSize, std::ostream &ptmFile);
void readPatchTokens(const void *&patchListPtr, uint32_t patchListSize, std::ostream &ptmFile);
uint32_t readStructFields(const std::vector<std::string> &patchList,
const size_t &structPos, std::vector<PTField> &fields);
void validateLoadedKernelData(KernelSizeData kernelDataSize, size_t sectionSize);
};