Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit eb271d2

Browse files
Make the ELF deploy code less picky
It no longer requires the sections and segments to be in such a strict order. This is necessary as modern GNU toolchains generate sections that aren't in strictly increasing address order.
1 parent bade188 commit eb271d2

File tree

1 file changed

+48
-17
lines changed

1 file changed

+48
-17
lines changed

engine/src/deploy_linux.cpp

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -708,8 +708,8 @@ Exec_stat MCDeployToELF(const MCDeployParameters& p_params, bool p_is_android)
708708
t_success = MCDeployThrow(kMCDeployErrorLinuxNoPayloadSection);
709709

710710
// Next check that there are no sections after the project section.
711-
// (This check implies there are no segments after the project section
712-
// since the section table is ordered by vaddr and segments can only
711+
// (This check implies there are no loadable segments after the project
712+
// section since the section table is ordered by vaddr and segments can only
713713
// contain stuff in sections).
714714
if (t_success)
715715
for(typename T::Shdr *t_section = t_project_section + 1; t_section < t_section_headers + t_header . e_shnum; t_section += 1)
@@ -802,15 +802,17 @@ Exec_stat MCDeployToELF(const MCDeployParameters& p_params, bool p_is_android)
802802
else
803803
t_payload_delta = 0;
804804

805-
// If the project section is not the last one, then work out the
806-
// subsequent section data size/offset.
807-
if (t_project_section - t_section_headers + 1 < t_header . e_shnum)
808-
{
809-
t_end_offset = (t_project_section + 1) -> sh_offset;
810-
t_end_size = (t_section_headers[t_header . e_shnum - 1] . sh_offset + t_section_headers[t_header . e_shnum - 1] . sh_size) - t_end_offset;
811-
}
812-
else
813-
t_end_offset = t_end_size = 0;
805+
// The sections of the file are not strictly ordered so the
806+
// remainder of the file requires examining the whole section table.
807+
t_end_offset = t_project_section->sh_offset + t_project_section->sh_size;
808+
809+
t_end_size = 0;
810+
for (size_t i = 0; i < t_header.e_shnum; i++)
811+
{
812+
uint32_t t_section_end = t_section_headers[i].sh_offset + t_section_headers[i].sh_size;
813+
if (t_section_end > t_end_offset + t_end_size)
814+
t_end_size = t_section_end - t_end_offset;
815+
}
814816

815817
//
816818

@@ -821,16 +823,45 @@ Exec_stat MCDeployToELF(const MCDeployParameters& p_params, bool p_is_android)
821823
t_project_section -> sh_addr += t_payload_delta;
822824
t_project_section -> sh_size = t_project_size;
823825

824-
t_project_segment -> p_filesz = t_payload_size + t_project_size;
825-
t_project_segment -> p_memsz = t_payload_size + t_project_size;
826+
t_project_segment -> p_filesz += t_payload_delta + t_project_delta;
827+
t_project_segment -> p_memsz += t_payload_delta + t_project_delta;
826828

827-
for(typename T::Shdr *t_section = t_project_section + 1; t_section < t_section_headers + t_header . e_shnum; t_section += 1)
829+
// Update the sections that follow the project/payload
830+
for (typename T::Shdr* t_section = t_project_section + 1; t_section < t_section_headers + t_header . e_shnum; t_section += 1)
831+
{
828832
if (t_section -> sh_offset >= t_end_offset)
829833
t_section -> sh_offset += t_project_delta + t_payload_delta;
834+
}
830835

831-
t_header . e_shoff += t_project_delta + t_payload_delta;
832-
833-
//
836+
// Adjust the section header table offset if it comes after the adjusted
837+
// sections.
838+
if (t_header.e_shoff >= t_end_offset)
839+
t_header.e_shoff += t_project_delta + t_payload_delta;
840+
841+
// Adjust the segment header table offset if it coems after the adjusted
842+
// sections.
843+
if (t_header.e_phoff >= t_end_offset)
844+
t_header.e_phoff += t_project_delta + t_payload_delta;
845+
846+
// Update the segments that follow the project/payload
847+
// Note that segments aren't necessarily in increasing order of file
848+
// offset.
849+
for (typename T::Phdr* t_segment = t_program_headers; t_segment < t_program_headers + t_header.e_phnum; t_segment += 1)
850+
{
851+
// Skip segments that precede the segment we adjusted
852+
if (t_segment == t_project_segment || t_segment->p_offset < t_end_offset)
853+
continue;
854+
855+
// If any of these segments is a LOAD segment, we've broken the file!
856+
if (t_segment->p_type == PT_LOAD)
857+
{
858+
t_success = MCDeployThrow(kMCDeployErrorLinuxBadSectionOrder);
859+
break;
860+
}
861+
862+
// Adjust the file offset for the segment contents
863+
t_segment->p_offset += t_payload_delta + t_project_delta;
864+
}
834865

835866
t_section_table_size = t_header . e_shnum * sizeof(typename T::Shdr);
836867
t_section_table_offset = t_header . e_shoff;

0 commit comments

Comments
 (0)