Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit 04e3307

Browse files
committed
Next set of additional error checks for invalid Mach-O files for the
load commands that use the MachO::thread_command type but are not used in llvm libObject code but used in llvm tool code. This includes the LC_UNIXTHREAD and LC_THREAD load commands. A quick note about the philosophy of the error checking in libObject for Mach-O files, the idea behind the checking is that we never will return a Mach-O file out of libObject that contains unknown things in the load commands. To do this the 32-bit ARM and PPC general tread states needed to be defined as two test case binaries contained them. If other thread states for other CPUs need to be added we will do that as needed. Going forward the LC_MAIN load command is used to set the entry point in Mach-O executables these days instead of an LC_UNIXTHREAD as was done in the past. So today only in core files are LC_THREAD load commands and thread states usually found. Other thread states have not yet been defined in include/Support/MachO.h at this time. But that can be added as needed with their corresponding checking also added. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@284668 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 6224e33 commit 04e3307

9 files changed

+306
-0
lines changed

include/llvm/Support/MachO.h

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,6 +1710,181 @@ namespace llvm {
17101710
const uint32_t x86_EXCEPTION_STATE_COUNT =
17111711
sizeof(x86_exception_state_t) / sizeof(uint32_t);
17121712

1713+
struct arm_thread_state32_t {
1714+
uint32_t r[13];
1715+
uint32_t sp;
1716+
uint32_t lr;
1717+
uint32_t pc;
1718+
uint32_t cpsr;
1719+
};
1720+
1721+
inline void swapStruct(arm_thread_state32_t &x) {
1722+
for (int i = 0; i < 13; i++)
1723+
sys::swapByteOrder(x.r[i]);
1724+
sys::swapByteOrder(x.sp);
1725+
sys::swapByteOrder(x.lr);
1726+
sys::swapByteOrder(x.pc);
1727+
sys::swapByteOrder(x.cpsr);
1728+
}
1729+
1730+
struct arm_state_hdr_t {
1731+
uint32_t flavor;
1732+
uint32_t count;
1733+
};
1734+
1735+
struct arm_thread_state_t {
1736+
arm_state_hdr_t tsh;
1737+
union {
1738+
arm_thread_state32_t ts32;
1739+
} uts;
1740+
};
1741+
1742+
inline void swapStruct(arm_state_hdr_t &x) {
1743+
sys::swapByteOrder(x.flavor);
1744+
sys::swapByteOrder(x.count);
1745+
}
1746+
1747+
enum ARMThreadFlavors {
1748+
ARM_THREAD_STATE = 1,
1749+
ARM_VFP_STATE = 2,
1750+
ARM_EXCEPTION_STATE = 3,
1751+
ARM_DEBUG_STATE = 4,
1752+
ARN_THREAD_STATE_NONE = 5,
1753+
ARM_THREAD_STATE64 = 6,
1754+
ARM_EXCEPTION_STATE64 = 7
1755+
};
1756+
1757+
inline void swapStruct(arm_thread_state_t &x) {
1758+
swapStruct(x.tsh);
1759+
if (x.tsh.flavor == ARM_THREAD_STATE)
1760+
swapStruct(x.uts.ts32);
1761+
}
1762+
1763+
const uint32_t ARM_THREAD_STATE_COUNT =
1764+
sizeof(arm_thread_state32_t) / sizeof(uint32_t);
1765+
1766+
struct ppc_thread_state32_t {
1767+
uint32_t srr0;
1768+
uint32_t srr1;
1769+
uint32_t r0;
1770+
uint32_t r1;
1771+
uint32_t r2;
1772+
uint32_t r3;
1773+
uint32_t r4;
1774+
uint32_t r5;
1775+
uint32_t r6;
1776+
uint32_t r7;
1777+
uint32_t r8;
1778+
uint32_t r9;
1779+
uint32_t r10;
1780+
uint32_t r11;
1781+
uint32_t r12;
1782+
uint32_t r13;
1783+
uint32_t r14;
1784+
uint32_t r15;
1785+
uint32_t r16;
1786+
uint32_t r17;
1787+
uint32_t r18;
1788+
uint32_t r19;
1789+
uint32_t r20;
1790+
uint32_t r21;
1791+
uint32_t r22;
1792+
uint32_t r23;
1793+
uint32_t r24;
1794+
uint32_t r25;
1795+
uint32_t r26;
1796+
uint32_t r27;
1797+
uint32_t r28;
1798+
uint32_t r29;
1799+
uint32_t r30;
1800+
uint32_t r31;
1801+
uint32_t ct;
1802+
uint32_t xer;
1803+
uint32_t lr;
1804+
uint32_t ctr;
1805+
uint32_t mq;
1806+
uint32_t vrsave;
1807+
};
1808+
1809+
inline void swapStruct(ppc_thread_state32_t &x) {
1810+
sys::swapByteOrder(x.srr0);
1811+
sys::swapByteOrder(x.srr1);
1812+
sys::swapByteOrder(x.r0);
1813+
sys::swapByteOrder(x.r1);
1814+
sys::swapByteOrder(x.r2);
1815+
sys::swapByteOrder(x.r3);
1816+
sys::swapByteOrder(x.r4);
1817+
sys::swapByteOrder(x.r5);
1818+
sys::swapByteOrder(x.r6);
1819+
sys::swapByteOrder(x.r7);
1820+
sys::swapByteOrder(x.r8);
1821+
sys::swapByteOrder(x.r9);
1822+
sys::swapByteOrder(x.r10);
1823+
sys::swapByteOrder(x.r11);
1824+
sys::swapByteOrder(x.r12);
1825+
sys::swapByteOrder(x.r13);
1826+
sys::swapByteOrder(x.r14);
1827+
sys::swapByteOrder(x.r15);
1828+
sys::swapByteOrder(x.r16);
1829+
sys::swapByteOrder(x.r17);
1830+
sys::swapByteOrder(x.r18);
1831+
sys::swapByteOrder(x.r19);
1832+
sys::swapByteOrder(x.r20);
1833+
sys::swapByteOrder(x.r21);
1834+
sys::swapByteOrder(x.r22);
1835+
sys::swapByteOrder(x.r23);
1836+
sys::swapByteOrder(x.r24);
1837+
sys::swapByteOrder(x.r25);
1838+
sys::swapByteOrder(x.r26);
1839+
sys::swapByteOrder(x.r27);
1840+
sys::swapByteOrder(x.r28);
1841+
sys::swapByteOrder(x.r29);
1842+
sys::swapByteOrder(x.r30);
1843+
sys::swapByteOrder(x.r31);
1844+
sys::swapByteOrder(x.ct);
1845+
sys::swapByteOrder(x.xer);
1846+
sys::swapByteOrder(x.lr);
1847+
sys::swapByteOrder(x.ctr);
1848+
sys::swapByteOrder(x.mq);
1849+
sys::swapByteOrder(x.vrsave);
1850+
}
1851+
1852+
struct ppc_state_hdr_t {
1853+
uint32_t flavor;
1854+
uint32_t count;
1855+
};
1856+
1857+
struct ppc_thread_state_t {
1858+
ppc_state_hdr_t tsh;
1859+
union {
1860+
ppc_thread_state32_t ts32;
1861+
} uts;
1862+
};
1863+
1864+
inline void swapStruct(ppc_state_hdr_t &x) {
1865+
sys::swapByteOrder(x.flavor);
1866+
sys::swapByteOrder(x.count);
1867+
}
1868+
1869+
enum PPCThreadFlavors {
1870+
PPC_THREAD_STATE = 1,
1871+
PPC_FLOAT_STATE = 2,
1872+
PPC_EXCEPTION_STATE = 3,
1873+
PPC_VECTOR_STATE = 4,
1874+
PPC_THREAD_STATE64 = 5,
1875+
PPC_EXCEPTION_STATE64 = 6,
1876+
PPC_THREAD_STATE_NONE = 7
1877+
};
1878+
1879+
inline void swapStruct(ppc_thread_state_t &x) {
1880+
swapStruct(x.tsh);
1881+
if (x.tsh.flavor == PPC_THREAD_STATE)
1882+
swapStruct(x.uts.ts32);
1883+
}
1884+
1885+
const uint32_t PPC_THREAD_STATE_COUNT =
1886+
sizeof(ppc_thread_state32_t) / sizeof(uint32_t);
1887+
17131888
// Define a union of all load command structs
17141889
#define LOAD_COMMAND_STRUCT(LCStruct) LCStruct LCStruct##_data;
17151890

lib/Object/MachOObjectFile.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,107 @@ static Error checkSubCommand(const MachOObjectFile *Obj,
782782
return Error::success();
783783
}
784784

785+
static Error checkThreadCommand(const MachOObjectFile *Obj,
786+
const MachOObjectFile::LoadCommandInfo &Load,
787+
uint32_t LoadCommandIndex,
788+
const char *CmdName) {
789+
if (Load.C.cmdsize < sizeof(MachO::thread_command))
790+
return malformedError("load command " + Twine(LoadCommandIndex) +
791+
CmdName + " cmdsize too small");
792+
MachO::thread_command T =
793+
getStruct<MachO::thread_command>(Obj, Load.Ptr);
794+
const char *state = Load.Ptr + sizeof(MachO::thread_command);
795+
const char *end = Load.Ptr + T.cmdsize;
796+
uint32_t nflavor = 0;
797+
uint32_t cputype = getCPUType(Obj);
798+
while (state < end) {
799+
if(state + sizeof(uint32_t) > end)
800+
return malformedError("load command " + Twine(LoadCommandIndex) +
801+
"flavor in " + CmdName + " extends past end of "
802+
"command");
803+
uint32_t flavor;
804+
memcpy(&flavor, state, sizeof(uint32_t));
805+
if (Obj->isLittleEndian() != sys::IsLittleEndianHost)
806+
sys::swapByteOrder(flavor);
807+
state += sizeof(uint32_t);
808+
809+
if(state + sizeof(uint32_t) > end)
810+
return malformedError("load command " + Twine(LoadCommandIndex) +
811+
" count in " + CmdName + " extends past end of "
812+
"command");
813+
uint32_t count;
814+
memcpy(&count, state, sizeof(uint32_t));
815+
if (Obj->isLittleEndian() != sys::IsLittleEndianHost)
816+
sys::swapByteOrder(count);
817+
state += sizeof(uint32_t);
818+
819+
if (cputype == MachO::CPU_TYPE_X86_64) {
820+
if (flavor == MachO::x86_THREAD_STATE64) {
821+
if (count != MachO::x86_THREAD_STATE64_COUNT)
822+
return malformedError("load command " + Twine(LoadCommandIndex) +
823+
" count not x86_THREAD_STATE64_COUNT for "
824+
"flavor number " + Twine(nflavor) + " which is "
825+
"a x86_THREAD_STATE64 flavor in " + CmdName +
826+
" command");
827+
if (state + sizeof(MachO::x86_thread_state64_t) > end)
828+
return malformedError("load command " + Twine(LoadCommandIndex) +
829+
" x86_THREAD_STATE64 extends past end of "
830+
"command in " + CmdName + " command");
831+
state += sizeof(MachO::x86_thread_state64_t);
832+
} else {
833+
return malformedError("load command " + Twine(LoadCommandIndex) +
834+
" unknown flavor (" + Twine(flavor) + ") for "
835+
"flavor number " + Twine(nflavor) + " in " +
836+
CmdName + " command");
837+
}
838+
} else if (cputype == MachO::CPU_TYPE_ARM) {
839+
if (flavor == MachO::ARM_THREAD_STATE) {
840+
if (count != MachO::ARM_THREAD_STATE_COUNT)
841+
return malformedError("load command " + Twine(LoadCommandIndex) +
842+
" count not ARM_THREAD_STATE_COUNT for "
843+
"flavor number " + Twine(nflavor) + " which is "
844+
"a ARM_THREAD_STATE flavor in " + CmdName +
845+
" command");
846+
if (state + sizeof(MachO::arm_thread_state32_t) > end)
847+
return malformedError("load command " + Twine(LoadCommandIndex) +
848+
" ARM_THREAD_STATE extends past end of "
849+
"command in " + CmdName + " command");
850+
state += sizeof(MachO::arm_thread_state32_t);
851+
} else {
852+
return malformedError("load command " + Twine(LoadCommandIndex) +
853+
" unknown flavor (" + Twine(flavor) + ") for "
854+
"flavor number " + Twine(nflavor) + " in " +
855+
CmdName + " command");
856+
}
857+
} else if (cputype == MachO::CPU_TYPE_POWERPC) {
858+
if (flavor == MachO::PPC_THREAD_STATE) {
859+
if (count != MachO::PPC_THREAD_STATE_COUNT)
860+
return malformedError("load command " + Twine(LoadCommandIndex) +
861+
" count not PPC_THREAD_STATE_COUNT for "
862+
"flavor number " + Twine(nflavor) + " which is "
863+
"a PPC_THREAD_STATE flavor in " + CmdName +
864+
" command");
865+
if (state + sizeof(MachO::ppc_thread_state32_t) > end)
866+
return malformedError("load command " + Twine(LoadCommandIndex) +
867+
" PPC_THREAD_STATE extends past end of "
868+
"command in " + CmdName + " command");
869+
state += sizeof(MachO::ppc_thread_state32_t);
870+
} else {
871+
return malformedError("load command " + Twine(LoadCommandIndex) +
872+
" unknown flavor (" + Twine(flavor) + ") for "
873+
"flavor number " + Twine(nflavor) + " in " +
874+
CmdName + " command");
875+
}
876+
} else {
877+
return malformedError("unknown cputype (" + Twine(cputype) + ") load "
878+
"command " + Twine(LoadCommandIndex) + " for " +
879+
CmdName + " command can't be checked");
880+
}
881+
nflavor++;
882+
}
883+
return Error::success();
884+
}
885+
785886
Expected<std::unique_ptr<MachOObjectFile>>
786887
MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian,
787888
bool Is64Bits) {
@@ -839,6 +940,7 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
839940
const char *EntryPointLoadCmd = nullptr;
840941
const char *EncryptLoadCmd = nullptr;
841942
const char *RoutinesLoadCmd = nullptr;
943+
const char *UnixThreadLoadCmd = nullptr;
842944
for (unsigned I = 0; I < LoadCommandCount; ++I) {
843945
if (is64Bit()) {
844946
if (Load.C.cmdsize % 8 != 0) {
@@ -1094,6 +1196,17 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
10941196
return;
10951197
}
10961198
RoutinesLoadCmd = Load.Ptr;
1199+
} else if (Load.C.cmd == MachO::LC_UNIXTHREAD) {
1200+
if ((Err = checkThreadCommand(this, Load, I, "LC_UNIXTHREAD")))
1201+
return;
1202+
if (UnixThreadLoadCmd) {
1203+
Err = malformedError("more than one LC_UNIXTHREAD command");
1204+
return;
1205+
}
1206+
UnixThreadLoadCmd = Load.Ptr;
1207+
} else if (Load.C.cmd == MachO::LC_THREAD) {
1208+
if ((Err = checkThreadCommand(this, Load, I, "LC_THREAD")))
1209+
return;
10971210
}
10981211
if (I < LoadCommandCount - 1) {
10991212
if (auto LoadOrErr = getNextLoadCommandInfo(this, I, Load))
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

test/Object/macho-invalid.test

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,3 +376,21 @@ INVALID-ROUTINES64-MORE-THAN-ONE: macho-invalid-routines64-more-than-one': trunc
376376

377377
RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-codesign-bad-size 2>&1 | FileCheck -check-prefix INVALID-CODESIGN-BAD-SIZE %s
378378
INVALID-CODESIGN-BAD-SIZE: macho-invalid-codesign-bad-size': truncated or malformed object (LC_CODE_SIGNATURE command 0 has incorrect cmdsize)
379+
380+
RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-thread-count-pastend 2>&1 | FileCheck -check-prefix INVALID-THREAD-COUNT-PASTEND %s
381+
INVALID-THREAD-COUNT-PASTEND: macho-invalid-thread-count-pastend': truncated or malformed object (load command 0 count in LC_UNIXTHREAD extends past end of command)
382+
383+
RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-thread-count-wrong 2>&1 | FileCheck -check-prefix INVALID-THREAD-COUNT-WRONG %s
384+
INVALID-THREAD-COUNT-WRONG: macho-invalid-thread-count-wrong': truncated or malformed object (load command 0 count not x86_THREAD_STATE64_COUNT for flavor number 0 which is a x86_THREAD_STATE64 flavor in LC_THREAD command)
385+
386+
RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-thread-flavor-unknown 2>&1 | FileCheck -check-prefix INVALID-THREAD-FLAVOR-UNKNOWN %s
387+
INVALID-THREAD-FLAVOR-UNKNOWN: macho-invalid-thread-flavor-unknown': truncated or malformed object (load command 0 unknown flavor (507) for flavor number 0 in LC_THREAD command)
388+
389+
RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-thread-state-pastend 2>&1 | FileCheck -check-prefix INVALID-THREAD-PASTEND %s
390+
INVALID-THREAD-PASTEND: macho-invalid-thread-state-pastend': truncated or malformed object (load command 0 x86_THREAD_STATE64 extends past end of command in LC_THREAD command)
391+
392+
RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-thread-unknown-cputype 2>&1 | FileCheck -check-prefix INVALID-THREAD-UNKNOWN-CPUTYPE %s
393+
INVALID-THREAD-UNKNOWN-CPUTYPE: macho-invalid-thread-unknown-cputype': truncated or malformed object (unknown cputype (328) load command 0 for LC_THREAD command can't be checked)
394+
395+
RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-unixthread-more-than-one 2>&1 | FileCheck -check-prefix INVALID-UNIXTHREAD-MORE-THAN-ONE %s
396+
INVALID-UNIXTHREAD-MORE-THAN-ONE: macho-invalid-unixthread-more-than-one': truncated or malformed object (more than one LC_UNIXTHREAD command)

0 commit comments

Comments
 (0)