87 return ExecutableValidationResult::Malformed;
91 MemoryCopy(&header, pBuffer,
sizeof(header));
92 if (header.ident[0] != 0x7f || header.ident[1] !=
'E' || header.ident[2] !=
'L' ||
93 header.ident[3] !=
'F') {
94 return ExecutableValidationResult::Malformed;
97 const uint8_t expectedClass = BITS_32 ? ElfClass32 : ElfClass64;
98 const uint8_t expectedData =
99 TargetInfo::isLittleEndian() ? ElfDataLittleEndian : ElfDataBigEndian;
100 if (header.ident[4] != expectedClass || header.ident[5] != expectedData ||
101 !isExpectedMachine(header.machine)) {
102 return ExecutableValidationResult::WrongArchitecture;
105 if (header.ident[6] != ElfCurrentVersion || header.version != ElfCurrentVersion) {
106 return ExecutableValidationResult::Malformed;
108 if (header.type != ET_EXEC && header.type != ET_DYN) {
109 return ExecutableValidationResult::UnsupportedType;
114 return ExecutableValidationResult::Malformed;
117 const size_t programHeaderSize =
static_cast<size_t>(header.phnum) *
sizeof(
ElfProgramHeader_t);
119 !rangeWithinFile(header.phoff, programHeaderSize, fileSize)) {
120 return ExecutableValidationResult::Malformed;
123 metadata.type = header.type;
124 metadata.entryPoint =
static_cast<uintptr_t
>(header.entry);
125 metadata.programHeaderOffset =
static_cast<size_t>(header.phoff);
126 metadata.programHeaderCount = header.phnum;
127 metadata.programHeaderSize = programHeaderSize;
128 return ExecutableValidationResult::Valid;
132 const uint8_t* pBuffer,
size_t length,
size_t fileSize,
ExecutableMetadata& metadata) {
133 if (!pBuffer || !metadata.programHeaderCount ||
134 metadata.programHeaderCount > (MaximumProgramHeaderTableSize /
sizeof(
ElfProgramHeader_t))) {
135 return ExecutableValidationResult::Malformed;
139 if (metadata.programHeaderSize != expectedSize || length < expectedSize ||
140 !rangeWithinFile(metadata.programHeaderOffset, expectedSize, fileSize)) {
141 return ExecutableValidationResult::Malformed;
144 metadata.loadStart = ~uintptr_t{0};
145 metadata.loadEnd = 0;
146 metadata.interpreterOffset = 0;
147 metadata.interpreterSize = 0;
148 metadata.hasInterpreter =
false;
150 const uintptr_t pageMask = TargetInfo::getPageOffsetMask();
151 bool hasLoadSegment =
false;
152 bool entryPointCovered =
false;
153 for (
size_t i = 0; i < metadata.programHeaderCount; ++i) {
155 MemoryCopy(&header, pBuffer + (i *
sizeof(header)),
sizeof(header));
157 if (header.type != PT_NULL && header.filesz &&
158 !rangeWithinFile(header.offset, header.filesz, fileSize)) {
159 return ExecutableValidationResult::Malformed;
162 if (header.type == PT_INTERP) {
163 if (metadata.hasInterpreter) {
164 return ExecutableValidationResult::MultipleInterpreters;
166 if (header.filesz < 2 || header.filesz > MaximumInterpreterSize ||
167 !rangeWithinFile(header.offset, header.filesz, fileSize)) {
168 return ExecutableValidationResult::Malformed;
171 metadata.hasInterpreter =
true;
172 metadata.interpreterOffset =
static_cast<size_t>(header.offset);
173 metadata.interpreterSize =
static_cast<size_t>(header.filesz);
176 if (header.type != PT_LOAD) {
179 if (!rangeWithinFile(header.offset, header.filesz, fileSize) || header.filesz > header.memsz) {
180 return ExecutableValidationResult::Malformed;
182 if (header.align > 1 &&
183 ((header.align & (header.align - 1)) ||
184 ((header.vaddr & (header.align - 1)) != (header.offset & (header.align - 1))))) {
185 return ExecutableValidationResult::Malformed;
187 if ((header.vaddr & pageMask) != (header.offset & pageMask)) {
188 return ExecutableValidationResult::Malformed;
194 uintptr_t pageStart = 0;
195 uintptr_t pageEnd = 0;
196 if (!loadPageRange(header.vaddr, header.memsz, pageStart, pageEnd)) {
197 return ExecutableValidationResult::Malformed;
200 for (
size_t j = 0; j < i; ++j) {
202 MemoryCopy(&previous, pBuffer + (j *
sizeof(previous)),
sizeof(previous));
203 if (previous.type != PT_LOAD || !previous.memsz) {
207 uintptr_t previousStart = 0;
208 uintptr_t previousEnd = 0;
209 if (!loadPageRange(previous.vaddr, previous.memsz, previousStart, previousEnd)) {
210 return ExecutableValidationResult::Malformed;
212 if (pageStart < previousEnd && previousStart < pageEnd) {
213 return ExecutableValidationResult::UnsupportedLayout;
217 hasLoadSegment =
true;
218 if (pageStart < metadata.loadStart) {
219 metadata.loadStart = pageStart;
221 if (pageEnd > metadata.loadEnd) {
222 metadata.loadEnd = pageEnd;
225 if ((header.flags & PF_X) && metadata.entryPoint >= header.vaddr &&
226 (metadata.entryPoint - header.vaddr) < header.memsz) {
227 entryPointCovered =
true;
231 if (!hasLoadSegment || !entryPointCovered) {
232 return ExecutableValidationResult::Malformed;
234 if (metadata.type == ET_DYN && metadata.loadStart != 0) {
235 return ExecutableValidationResult::UnsupportedLayout;
238 return ExecutableValidationResult::Valid;