2023-06-10 13:10:56 +03:00

418 lines
10 KiB
C

#include "ld.h"
#include "fcts.h"
#include "../../../Kernel/syscalls.h"
#include "../../../Kernel/ipc.h"
#include "elf.h"
#define Print(x) Print__(x)
#define PrintNL(x) PrintNL__(x)
#if (1)
#define PrintDbg(x) Print__(x)
#define PrintDbgNL(x) PrintNL__(x)
#define ltoaDbg(x, y, z) ltoa(x, y, z)
#else
#define PrintDbg(x)
#define PrintDbgNL(x)
#define ltoaDbg(x, y, z)
#endif
struct InterpreterIPCDataLibrary
{
char Name[64];
};
typedef struct
{
char Path[256];
void *MemoryImage;
struct InterpreterIPCDataLibrary Libraries[64];
} InterpreterIPCData;
struct LibsCollection
{
char ParentName[32];
char LibraryName[32];
uintptr_t ParentMemoryImage;
uintptr_t LibraryMemoryImage;
struct LibsCollection *Next;
char Valid;
};
static char ParentPath[256];
static char Lock = 0;
__attribute__((naked, used, no_stack_protector)) void ELF_LAZY_RESOLVE_STUB()
{
while (Lock == 1)
;
__asm__ __volatile__("mfence\n");
Lock = 1;
__asm__ __volatile__("pop %r11\n"
"pop %r10\n"
"push %rdi\n"
"push %rsi\n"
"push %rdx\n"
"push %rcx\n"
"push %r8\n"
"push %r9\n"
"mov %r11, %rdi\n" // Move the first argument to rdi (libs collection)
"mov %r10, %rsi\n" // Move the second argument to rsi (rel index)
"call ELF_LAZY_RESOLVE_MAIN\n"
"mov %rax, %r11\n" // Move the return value to r11
"pop %r9\n"
"pop %r8\n"
"pop %rcx\n"
"pop %rdx\n"
"pop %rsi\n"
"pop %rdi\n"
"jmp *%r11\n"); // Jump to the return value
}
void (*ELF_LAZY_RESOLVE_MAIN(struct LibsCollection *Info, long RelIndex))()
{
if (!Info)
goto FailEnd;
char DbgBuff[32];
char LibraryPathBuffer[256];
struct LibsCollection *CurLib = Info;
PrintDbgNL("_______");
/* The last entry is the null entry (Valid == false)
which determines the end of the list. */
while (CurLib->Valid)
{
KernelCTL(KCTL_GET_ABSOLUTE_PATH, CurLib->LibraryName,
LibraryPathBuffer, sizeof(LibraryPathBuffer), 0);
PrintDbg("-- ");
PrintDbg(LibraryPathBuffer);
PrintDbg(" ");
ltoaDbg(RelIndex, DbgBuff, 10);
PrintDbg(DbgBuff);
PrintDbgNL(" --");
uintptr_t lib_BaseAddress = __UINTPTR_MAX__;
uintptr_t app_BaseAddress = __UINTPTR_MAX__;
Elf64_Ehdr lib_Header;
Elf64_Ehdr app_Header;
void *KP_lib = syscall2(_FileOpen, LibraryPathBuffer, "r");
void *KP_app = syscall2(_FileOpen, ParentPath, "r");
if (!KP_lib)
{
PrintNL("Failed to open library");
goto RetryNextLib;
}
if (!KP_app)
{
PrintNL("Failed to open application");
goto RetryNextLib;
}
syscall3(_FileRead, KP_lib, &lib_Header, sizeof(Elf64_Ehdr));
syscall3(_FileRead, KP_app, &app_Header, sizeof(Elf64_Ehdr));
Elf64_Phdr ItrProgramHeader;
for (Elf64_Half i = 0; i < lib_Header.e_phnum; i++)
{
syscall3(_FileSeek, KP_lib,
lib_Header.e_phoff +
lib_Header.e_phentsize * i,
SEEK_SET);
syscall3(_FileRead, KP_lib, &ItrProgramHeader, sizeof(Elf64_Phdr));
lib_BaseAddress = MIN(lib_BaseAddress, ItrProgramHeader.p_vaddr);
}
for (Elf64_Half i = 0; i < app_Header.e_phnum; i++)
{
syscall3(_FileSeek, KP_app,
app_Header.e_phoff +
app_Header.e_phentsize * i,
SEEK_SET);
syscall3(_FileRead, KP_app, &ItrProgramHeader, sizeof(Elf64_Phdr));
app_BaseAddress = MIN(app_BaseAddress, ItrProgramHeader.p_vaddr);
}
struct Elf64_Dyn lib_JmpRel = ELFGetDynamicTag(LibraryPathBuffer, DT_JMPREL);
struct Elf64_Dyn lib_SymTab = ELFGetDynamicTag(LibraryPathBuffer, DT_SYMTAB);
struct Elf64_Dyn lib_StrTab = ELFGetDynamicTag(LibraryPathBuffer, DT_STRTAB);
struct Elf64_Dyn app_JmpRel = ELFGetDynamicTag(ParentPath, DT_JMPREL);
struct Elf64_Dyn app_SymTab = ELFGetDynamicTag(ParentPath, DT_SYMTAB);
struct Elf64_Dyn app_StrTab = ELFGetDynamicTag(ParentPath, DT_STRTAB);
if (!lib_JmpRel.d_tag == 0)
{
PrintNL("No DT_JMPREL");
// goto RetryNextLib;
}
else if (RelIndex >= lib_JmpRel.d_un.d_val /
sizeof(Elf64_Rela))
{
PrintNL("RelIndex is greater than the number of relocations");
goto RetryNextLib;
}
if (!lib_SymTab.d_tag == 0)
{
PrintNL("No DT_SYMTAB");
goto RetryNextLib;
}
if (!lib_StrTab.d_tag == 0)
{
PrintNL("No DT_STRTAB");
goto RetryNextLib;
}
if (!lib_SymTab.d_tag == 0 &&
!lib_StrTab.d_tag == 0)
goto RetryNextLib;
Elf64_Rela *_lib_JmpRel = (Elf64_Rela *)(CurLib->LibraryMemoryImage + (lib_JmpRel.d_un.d_ptr - lib_BaseAddress));
Elf64_Sym *_lib_SymTab = (Elf64_Sym *)(CurLib->LibraryMemoryImage + (lib_SymTab.d_un.d_ptr - lib_BaseAddress));
Elf64_Rela *_app_JmpRel = (Elf64_Rela *)(CurLib->ParentMemoryImage + (app_JmpRel.d_un.d_ptr - app_BaseAddress));
Elf64_Sym *_app_SymTab = (Elf64_Sym *)(CurLib->ParentMemoryImage + (app_SymTab.d_un.d_ptr - app_BaseAddress));
char *lib_DynStr = (char *)(CurLib->LibraryMemoryImage + (lib_StrTab.d_un.d_ptr - lib_BaseAddress));
char *app_DynStr = (char *)(CurLib->ParentMemoryImage + (app_StrTab.d_un.d_ptr - app_BaseAddress));
Elf64_Rela *Rel = _app_JmpRel + RelIndex;
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Rel->r_offset);
int RelType = ELF64_R_TYPE(Rel->r_info);
switch (RelType)
{
case R_X86_64_NONE:
{
PrintDbgNL("R_X86_64_NONE");
if (*GOTEntry == 0)
{
PrintDbgNL("GOTEntry is 0");
break;
}
Lock = 0;
return (void (*)()) * GOTEntry;
}
case R_X86_64_JUMP_SLOT:
{
PrintDbgNL("R_X86_64_JUMP_SLOT");
int SymIndex = ELF64_R_SYM(Rel->r_info);
Elf64_Sym *Sym = _app_SymTab + SymIndex;
if (Sym->st_name)
{
char *SymName = app_DynStr + Sym->st_name;
PrintDbg("SymName: ");
PrintDbgNL(SymName);
Elf64_Sym LibSym = ELFLookupSymbol(ParentPath, SymName);
PrintDbg("LibSym: 0x");
ltoaDbg((long)LibSym.st_size, DbgBuff, 16);
PrintDbgNL(DbgBuff);
if (LibSym.st_value)
{
*GOTEntry = (Elf64_Addr)(CurLib->LibraryMemoryImage + LibSym.st_value);
ltoa(*GOTEntry, DbgBuff, 16);
PrintDbg("*GOTEntry: 0x");
PrintDbgNL(DbgBuff);
Lock = 0;
return (void (*)()) * GOTEntry;
}
PrintDbgNL("Not found in lib");
}
break;
}
default:
{
ltoa(RelType, DbgBuff, 10);
Print("RelType not supported ");
PrintNL(DbgBuff);
break;
}
}
RetryNextLib:
PrintDbgNL("Retrying next lib");
CurLib = CurLib->Next;
}
FailEnd:
Lock = 0;
__asm__ __volatile__("mfence\n");
Print("Symbol index ");
ltoa(RelIndex, DbgBuff, 10);
Print(DbgBuff);
PrintNL(" not found");
int ExitCode = 0x51801;
syscall1(_Exit, ExitCode);
while (1) // Make sure we don't return
;
}
/* Preload */
int ld_main()
{
/* Prevent race condition. */
uintptr_t KCTL_ret = KernelCTL(KCTL_IS_CRITICAL, 0, 0, 0, 0);
do
{
syscall1(_Sleep, 250);
KCTL_ret = KernelCTL(KCTL_IS_CRITICAL, 0, 0, 0, 0);
} while (KCTL_ret == SYSCALL_ACCESS_DENIED);
if (KCTL_ret == false)
return -1;
/* Everything is ok, continue. */
return 0;
}
bool ELFAddLazyResolverToGOT(void *MemoryImage, struct LibsCollection *Libs)
{
struct Elf64_Dyn Dyn = ELFGetDynamicTag(ParentPath, DT_PLTGOT);
if (!Dyn.d_tag)
return false;
Elf64_Addr *GOT = (Elf64_Addr *)Dyn.d_un.d_ptr;
GOT[1] = (uintptr_t)Libs;
GOT[2] = (uintptr_t)ELF_LAZY_RESOLVE_STUB;
return true;
}
/* Actual load */
int ld_load(int argc, char *argv[], char *envp[])
{
PrintDbgNL("!");
uintptr_t PageSize = KernelCTL(KCTL_GET_PAGE_SIZE, 0, 0, 0, 0);
int PagesForIPCDataStruct = sizeof(InterpreterIPCData) / PageSize + 1;
int PagesForLibsCollectionStruct = sizeof(struct LibsCollection) / PageSize + 1;
InterpreterIPCData *IPCBuffer =
(InterpreterIPCData *)RequestPages(PagesForIPCDataStruct);
int IPC_ID = IPC(IPC_CREATE, IPC_TYPE_MessagePassing,
0, 0, "LOAD", sizeof(InterpreterIPCData));
while (true)
{
IPC(IPC_LISTEN, IPC_TYPE_MessagePassing, IPC_ID, 1, NULL, 0);
IPC(IPC_WAIT, IPC_TYPE_MessagePassing, IPC_ID, 0, NULL, 0);
int IPCResult = IPC(IPC_READ, IPC_TYPE_MessagePassing,
IPC_ID, 0, IPCBuffer, PageSize);
if (IPCResult == IPC_E_CODE_Success)
break;
}
struct LibsCollection *LibsForLazyResolver =
(struct LibsCollection *)RequestPages(PagesForLibsCollectionStruct);
for (short i = 0; i < 64; i++)
{
if (IPCBuffer->Libraries[i].Name[0] == '\0')
break;
uintptr_t lib_mm_image =
KernelCTL(KCTL_GET_ELF_LIB_MEMORY_IMAGE,
(uint64_t)IPCBuffer->Libraries[i].Name, 0, 0, 0);
if (lib_mm_image == 0)
{
enum SyscallsErrorCodes ret =
KernelCTL(KCTL_REGISTER_ELF_LIB,
(uint64_t)IPCBuffer->Libraries[i].Name,
(uint64_t)IPCBuffer->Libraries[i].Name, 0, 0);
if (ret != SYSCALL_OK)
{
PrintNL("Failed to register ELF lib");
return -0x11B;
}
lib_mm_image = KernelCTL(KCTL_GET_ELF_LIB_MEMORY_IMAGE,
(uint64_t)IPCBuffer->Libraries[i].Name, 0, 0, 0);
}
if (LibsForLazyResolver->Next == NULL)
{
LibsForLazyResolver->Valid = true;
LibsForLazyResolver->LibraryMemoryImage = (uintptr_t)lib_mm_image;
LibsForLazyResolver->ParentMemoryImage = (uintptr_t)IPCBuffer->MemoryImage;
for (short j = 0; j < sizeof(LibsForLazyResolver->LibraryName); j++)
LibsForLazyResolver->LibraryName[j] = IPCBuffer->Libraries[i].Name[j];
LibsForLazyResolver->Next =
(struct LibsCollection *)RequestPages(PagesForLibsCollectionStruct);
memset(LibsForLazyResolver->Next, 0, sizeof(struct LibsCollection));
continue;
}
struct LibsCollection *CurrentLib = LibsForLazyResolver;
while (CurrentLib->Next != NULL)
CurrentLib = CurrentLib->Next;
CurrentLib->Valid = true;
CurrentLib->LibraryMemoryImage = (uintptr_t)lib_mm_image;
CurrentLib->ParentMemoryImage = (uintptr_t)IPCBuffer->MemoryImage;
for (short j = 0; j < sizeof(LibsForLazyResolver->LibraryName); j++)
CurrentLib->LibraryName[j] = IPCBuffer->Libraries[i].Name[j];
CurrentLib->Next =
(struct LibsCollection *)RequestPages(PagesForLibsCollectionStruct);
memset(CurrentLib->Next, 0, sizeof(struct LibsCollection));
}
struct LibsCollection *CurrentLib = LibsForLazyResolver;
for (int i = 0; i < sizeof(ParentPath); i++)
ParentPath[i] = IPCBuffer->Path[i];
if (!ELFAddLazyResolverToGOT(IPCBuffer->MemoryImage,
LibsForLazyResolver))
{
PrintNL("Failed to add lazy resolver to GOT");
return -0x607;
}
void *KP = syscall2(_FileOpen, ParentPath, (long)"r");
if (KP == NULL)
{
PrintNL("Failed to open file");
syscall1(_Exit, -0xF17E);
}
Elf64_Ehdr ELFHeader;
syscall3(_FileRead, KP, &ELFHeader, sizeof(Elf64_Ehdr));
Elf64_Addr Entry = ELFHeader.e_entry;
syscall1(_FileClose, KP);
IPC(IPC_DELETE, IPC_TYPE_MessagePassing, IPC_ID, 0, NULL, 0);
FreePages((uintptr_t)IPCBuffer, PagesForIPCDataStruct);
PrintDbgNL("Calling entry point");
return ((int (*)(int, char *[], char *[]))Entry)(argc, argv, envp);
}