Skip to content

Commit e4748cc

Browse files
authored
Fix address slot overruns causing AMDSupport panics (#102)
1 parent 161537e commit e4748cc

File tree

3 files changed

+65
-21
lines changed

3 files changed

+65
-21
lines changed

Changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
Lilu Changelog
22
==============
3+
#### v1.7.2
4+
- Fixed AMDSupport lockups & panics in macOS 26
5+
36
#### v1.7.1
47
- Allow loading on macOS 26 without `-lilubetaall`, thanks @AlfCraft07
58

Lilu/Headers/kern_mach.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,13 @@ class MachInfo {
182182
*/
183183
kern_return_t initFromMemory();
184184

185+
/**
186+
* Resolve for empty space between segments for medium jumps
187+
*
188+
* @return KERN_SUCCESS if found
189+
*/
190+
kern_return_t getAddressSlots(mach_header_64 *hdr, segment_command_64 *segment);
191+
185192
public:
186193

187194
/**

Lilu/Sources/kern_mach.cpp

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -593,14 +593,14 @@ void MachInfo::findSectionBounds(void *ptr, size_t sourceSize, vm_address_t &vms
593593
if (!strncmp(sect->sectname, sectionName, sizeof(sect->sectname))) {
594594
auto sptr = static_cast<uint8_t *>(ptr) + sect->offset;
595595
if (sptr + sect->size > endaddr) {
596-
SYSLOG("mach", "found section %s size %u in segment %llu is invalid", sectionName, sno, (uint64_t)vmsegment);
596+
SYSLOG("mach", "found section %s size %u in segment %u is invalid", sectionName, sect->size, sno);
597597
return;
598598
}
599599
vmsegment = scmd->vmaddr;
600600
vmsection = sect->addr;
601601
sectionptr = sptr;
602602
sectionSize = static_cast<size_t>(sect->size);
603-
DBGLOG("mach", "found section %s size %u in segment %llu", sectionName, sno, (uint64_t)vmsegment);
603+
DBGLOG("mach", "found section %s size %u in segment %u", sectionName, sect->size, sno);
604604
return;
605605
}
606606

@@ -622,14 +622,14 @@ void MachInfo::findSectionBounds(void *ptr, size_t sourceSize, vm_address_t &vms
622622
if (!strncmp(sect->sectname, sectionName, sizeof(sect->sectname))) {
623623
auto sptr = static_cast<uint8_t *>(ptr) + sect->offset;
624624
if (sptr + sect->size > endaddr) {
625-
SYSLOG("mach", "found section %s size %u in segment %llu is invalid", sectionName, sno, (uint64_t)vmsegment);
625+
SYSLOG("mach", "found section %s size %llu in segment %u is invalid", sectionName, sect->size, sno);
626626
return;
627627
}
628628
vmsegment = (vm_address_t)scmd->vmaddr;
629629
vmsection = (vm_address_t)sect->addr;
630630
sectionptr = sptr;
631631
sectionSize = static_cast<size_t>(sect->size);
632-
DBGLOG("mach", "found section %s size %u in segment %llu", sectionName, sno, (uint64_t)vmsegment);
632+
DBGLOG("mach", "found section %s size %llu in segment %u", sectionName, sect->size, sno);
633633
return;
634634
}
635635

@@ -802,6 +802,47 @@ uint8_t *MachInfo::findImage(const char *identifier, uint32_t &imageSize, mach_v
802802
return nullptr;
803803
}
804804

805+
kern_return_t MachInfo::getAddressSlots(mach_header_64 *hdr, segment_command_64 *segment) {
806+
auto section = reinterpret_cast<section_64 *>(segment + 1);
807+
mach_vm_address_t last_slot_start = 0;
808+
mach_vm_address_t last_slot_end = 0;
809+
size_t idx = 0;
810+
811+
if (segment->nsects == 0) {
812+
return KERN_FAILURE;
813+
}
814+
815+
// First space is between the mach load commands and first section (usually __text)
816+
if (section->addr < reinterpret_cast<mach_vm_address_t>(hdr) + sizeof(*hdr) + hdr->sizeofcmds) {
817+
SYSLOG("mach", "Invalid section address for address slots");
818+
return KERN_FAILURE;
819+
}
820+
821+
address_slots = reinterpret_cast<mach_vm_address_t>(hdr) + sizeof(*hdr) + hdr->sizeofcmds;
822+
address_slots_end = section->addr;
823+
824+
// Find last section
825+
for (idx = 0; idx < segment->nsects - 1; section++, idx++) {}
826+
827+
// Second potential space is between the last section and the end of the segment
828+
last_slot_start = section->addr + section->size;
829+
last_slot_end = segment->vmaddr + segment->vmsize;
830+
831+
DBGLOG("mach", "Potential slots: " PRIKADDR " - " PRIKADDR " : " PRIKADDR " - " PRIKADDR,
832+
CASTKADDR(address_slots), CASTKADDR(address_slots_end),
833+
CASTKADDR(last_slot_start), CASTKADDR(last_slot_end));
834+
835+
if (last_slot_start > segment->vmaddr &&
836+
(last_slot_end - last_slot_start) > (address_slots_end - address_slots)) {
837+
address_slots = last_slot_start;
838+
address_slots_end = last_slot_end;
839+
}
840+
841+
DBGLOG("mach", "activating slots for %s in " PRIKADDR " - " PRIKADDR, objectId, CASTKADDR(address_slots), CASTKADDR(address_slots_end));
842+
843+
return KERN_SUCCESS;
844+
}
845+
805846
kern_return_t MachInfo::kcGetRunningAddresses(mach_vm_address_t slide) {
806847
#if defined (__i386__)
807848
// KC is not supported on 32-bit.
@@ -856,6 +897,12 @@ kern_return_t MachInfo::kcGetRunningAddresses(mach_vm_address_t slide) {
856897
auto segCmd = reinterpret_cast<segment_command_64 *>(loadCmd);
857898
DBGLOG("mach", "%s has segment is %s from " PRIKADDR " to " PRIKADDR, objectId, segCmd->segname,
858899
CASTKADDR(segCmd->vmaddr), CASTKADDR(segCmd->vmaddr + segCmd->vmsize));
900+
901+
// Try to find space for address slots in __TEXT segment
902+
if (!strncmp(segCmd->segname, "__TEXT", sizeof(segCmd->segname)) && (slide || isKernel)) {
903+
(void) getAddressSlots(inner, segCmd);
904+
}
905+
859906
if (!sym_buf && !strncmp(segCmd->segname, "__LINKEDIT", sizeof(segCmd->segname))) {
860907
sym_buf = reinterpret_cast<uint8_t *>(segCmd->vmaddr);
861908
sym_fileoff = segCmd->fileoff;
@@ -891,15 +938,6 @@ kern_return_t MachInfo::kcGetRunningAddresses(mach_vm_address_t slide) {
891938
prelink_slid = true;
892939
running_mh = inner;
893940
memory_size = (size_t)(last_addr - reinterpret_cast<mach_vm_address_t>(inner));
894-
if (slide != 0 || isKernel) {
895-
address_slots = reinterpret_cast<mach_vm_address_t>(inner + 1) + inner->sizeofcmds;
896-
address_slots_end = (address_slots + (PAGE_SIZE - 1)) & ~PAGE_SIZE;
897-
while (*reinterpret_cast<uint32_t *>(address_slots_end) == 0) {
898-
address_slots_end += PAGE_SIZE;
899-
}
900-
901-
DBGLOG("mach", "activating slots for %s in " PRIKADDR " - " PRIKADDR, objectId, CASTKADDR(address_slots), CASTKADDR(address_slots_end));
902-
}
903941
return KERN_SUCCESS;
904942

905943
#else
@@ -960,6 +998,10 @@ kern_return_t MachInfo::getRunningAddresses(mach_vm_address_t slide, size_t size
960998
if (!strncmp(segCmd->segname, "__TEXT", sizeof(segCmd->segname))) {
961999
running_text_addr = segCmd->vmaddr;
9621000
running_mh = mh;
1001+
1002+
#if defined(__x86_64__)
1003+
(void) getAddressSlots(mh, segCmd);
1004+
#endif
9631005
break;
9641006
}
9651007
#if defined(__i386__)
@@ -1000,14 +1042,6 @@ kern_return_t MachInfo::getRunningAddresses(mach_vm_address_t slide, size_t size
10001042
kaslr_slide_set = true;
10011043

10021044
DBGLOG("mach", "aslr/load slide is 0x%llx", kaslr_slide);
1003-
1004-
#if defined(__x86_64__)
1005-
address_slots = reinterpret_cast<mach_vm_address_t>(running_mh + 1) + running_mh->sizeofcmds;
1006-
address_slots_end = (address_slots + (PAGE_SIZE - 1)) & ~PAGE_SIZE;
1007-
while (*reinterpret_cast<uint32_t *>(address_slots_end) == 0) {
1008-
address_slots_end += PAGE_SIZE;
1009-
}
1010-
#endif
10111045
} else {
10121046
SYSLOG("mach", "couldn't find the running addresses");
10131047
return KERN_FAILURE;

0 commit comments

Comments
 (0)