mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-28 13:43:45 +03:00
Launching an arbitrary ELF executable from disk works! :^)
This is so cool! It's a bit messy now with two Task constructors, but eventually they should fold into a single constructor somehow.
This commit is contained in:
parent
befeabd8fe
commit
b824f15619
Notes:
sideshowbarker
2024-07-19 18:45:05 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/b824f156197
@ -25,6 +25,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Assertions.h"
|
||||
#include "OwnPtr.h"
|
||||
#include "StdLib.h"
|
||||
|
||||
|
@ -22,7 +22,9 @@ int puts(const char* str)
|
||||
|
||||
void ExecSpace::initializeBuiltins()
|
||||
{
|
||||
#ifndef SERENITY
|
||||
m_symbols.set("puts", { (char*)puts, 0 });
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SERENITY
|
||||
@ -86,8 +88,13 @@ char* ExecSpace::symbolPtr(const char* name)
|
||||
|
||||
char* ExecSpace::allocateArea(String&& name, unsigned size)
|
||||
{
|
||||
char* ptr = static_cast<char*>(kmalloc(size));
|
||||
ASSERT(ptr);
|
||||
char* ptr;
|
||||
if (hookableAlloc)
|
||||
ptr = static_cast<char*>(hookableAlloc(name, size));
|
||||
else
|
||||
ptr = static_cast<char*>(kmalloc(size));
|
||||
if (size)
|
||||
ASSERT(ptr);
|
||||
m_areas.append(make<Area>(move(name), ptr, size));
|
||||
return ptr;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/MappedFile.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
@ -37,6 +38,8 @@ public:
|
||||
ExecSpace();
|
||||
~ExecSpace();
|
||||
|
||||
Function<void*(const String&, size_t)> hookableAlloc;
|
||||
|
||||
#ifdef SERENITY
|
||||
bool loadELF(ByteBuffer&&);
|
||||
#else
|
||||
|
@ -161,20 +161,27 @@ bool MemoryManager::unmapRegionsForTask(Task& task)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MemoryManager::mapRegion(Task& task, Task::Region& region)
|
||||
{
|
||||
auto& zone = *region.zone;
|
||||
for (size_t i = 0; i < zone.m_pages.size(); ++i) {
|
||||
auto laddr = region.linearAddress.offset(i * PAGE_SIZE);
|
||||
auto pte = ensurePTE(laddr);
|
||||
pte.setPhysicalPageBase(zone.m_pages[i].get());
|
||||
pte.setPresent(true);
|
||||
pte.setWritable(true);
|
||||
pte.setUserAllowed(!task.isRing0());
|
||||
|
||||
//kprintf("MM: >> Mapped L%x => P%x <<\n", laddr, zone.m_pages[i].get());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MemoryManager::mapRegionsForTask(Task& task)
|
||||
{
|
||||
for (auto& region : task.m_regions) {
|
||||
auto& zone = *region->zone;
|
||||
for (size_t i = 0; i < zone.m_pages.size(); ++i) {
|
||||
auto laddr = region->linearAddress.offset(i * PAGE_SIZE);
|
||||
auto pte = ensurePTE(laddr);
|
||||
pte.setPhysicalPageBase(zone.m_pages[i].get());
|
||||
pte.setPresent(true);
|
||||
pte.setWritable(true);
|
||||
pte.setUserAllowed(!task.isRing0());
|
||||
|
||||
//kprintf("MM: >> Mapped L%x => P%x <<\n", laddr, zone.m_pages[i].get());
|
||||
}
|
||||
if (!mapRegion(task, *region))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <AK/RetainPtr.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include "Task.h"
|
||||
|
||||
class Task;
|
||||
|
||||
@ -49,6 +50,7 @@ public:
|
||||
// HACK: don't use this jeez :(
|
||||
byte* quickMapOnePage(PhysicalAddress);
|
||||
|
||||
bool mapRegion(Task&, Task::Region&);
|
||||
bool mapRegionsForTask(Task&);
|
||||
bool unmapRegionsForTask(Task&);
|
||||
|
||||
|
100
Kernel/Task.cpp
100
Kernel/Task.cpp
@ -7,6 +7,7 @@
|
||||
#include "system.h"
|
||||
#include <VirtualFileSystem/FileHandle.h>
|
||||
#include <VirtualFileSystem/VirtualFileSystem.h>
|
||||
#include <ELFLoader/ExecSpace.h>
|
||||
#include "MemoryManager.h"
|
||||
|
||||
Task* current;
|
||||
@ -103,6 +104,104 @@ Task::Region* Task::allocateRegion(size_t size, String&& name)
|
||||
return m_regions.last().ptr();
|
||||
}
|
||||
|
||||
Task* Task::create(const String& path, uid_t uid, gid_t gid)
|
||||
{
|
||||
auto parts = path.split('/');
|
||||
if (parts.isEmpty())
|
||||
return nullptr;
|
||||
|
||||
auto handle = VirtualFileSystem::the().open(path);
|
||||
if (!handle)
|
||||
return nullptr;
|
||||
|
||||
auto elfData = handle->readEntireFile();
|
||||
if (!elfData)
|
||||
return nullptr;
|
||||
|
||||
Task* t = new Task(parts.takeLast(), uid, gid);
|
||||
|
||||
ExecSpace space;
|
||||
space.hookableAlloc = [&] (const String& name, size_t size) {
|
||||
if (!size)
|
||||
return (void*)nullptr;
|
||||
size = ((size / 4096) + 1) * 4096;
|
||||
Region* region = t->allocateRegion(size, String(name));
|
||||
ASSERT(region);
|
||||
MemoryManager::the().mapRegion(*t, *region);
|
||||
return (void*)region->linearAddress.asPtr();
|
||||
};
|
||||
bool success = space.loadELF(move(elfData));
|
||||
if (!success) {
|
||||
delete t;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
t->m_tss.eip = (dword)space.symbolPtr("_start");
|
||||
|
||||
// Add this task to head of task list (meaning it's next to run too, ATM.)
|
||||
cli();
|
||||
s_tasks->prepend(t);
|
||||
system.nprocess++;
|
||||
kprintf("Task %u (%s) spawned @ %p\n", t->pid(), t->name().characters(), t->m_tss.eip);
|
||||
sti();
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
Task::Task(String&& name, uid_t uid, gid_t gid)
|
||||
: m_name(move(name))
|
||||
, m_pid(next_pid++)
|
||||
, m_uid(uid)
|
||||
, m_gid(gid)
|
||||
, m_state(Runnable)
|
||||
, m_ring(Ring3)
|
||||
{
|
||||
m_nextRegion = LinearAddress(0x600000);
|
||||
|
||||
memset(&m_tss, 0, sizeof(m_tss));
|
||||
memset(&m_ldtEntries, 0, sizeof(m_ldtEntries));
|
||||
|
||||
allocateLDT();
|
||||
|
||||
// Only IF is set when a task boots.
|
||||
m_tss.eflags = 0x0202;
|
||||
|
||||
WORD codeSegment = 0x1b;
|
||||
WORD dataSegment = 0x23;
|
||||
WORD stackSegment = dataSegment;
|
||||
|
||||
m_tss.ds = dataSegment;
|
||||
m_tss.es = dataSegment;
|
||||
m_tss.fs = dataSegment;
|
||||
m_tss.gs = dataSegment;
|
||||
m_tss.ss = stackSegment;
|
||||
m_tss.cs = codeSegment;
|
||||
|
||||
m_tss.cr3 = MemoryManager::the().pageDirectoryBase().get();
|
||||
|
||||
// NOTE: Each task gets 16KB of stack.
|
||||
static const DWORD defaultStackSize = 16384;
|
||||
|
||||
auto* region = allocateRegion(defaultStackSize, "stack");
|
||||
ASSERT(region);
|
||||
m_stackTop = region->linearAddress.offset(defaultStackSize).get() & 0xfffffff8;
|
||||
m_tss.esp = m_stackTop;
|
||||
|
||||
// Set up a separate stack for Ring0.
|
||||
// FIXME: Don't leak this stack.
|
||||
m_kernelStack = kmalloc(defaultStackSize);
|
||||
DWORD ring0StackTop = ((DWORD)m_kernelStack + defaultStackSize) & 0xffffff8;
|
||||
m_tss.ss0 = 0x10;
|
||||
m_tss.esp0 = ring0StackTop;
|
||||
|
||||
// HACK: Ring2 SS in the TSS is the current PID.
|
||||
m_tss.ss2 = m_pid;
|
||||
|
||||
m_farPtr.offset = 0x98765432;
|
||||
|
||||
ASSERT(m_pid);
|
||||
}
|
||||
|
||||
Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring)
|
||||
: m_name(n)
|
||||
, m_entry(e)
|
||||
@ -241,7 +340,6 @@ void Task::sys$exit(int status)
|
||||
kprintf("sys$exit: %s(%u) exit with status %d\n", name().characters(), pid(), status);
|
||||
|
||||
setState(Exiting);
|
||||
dumpRegions();
|
||||
|
||||
s_tasks->remove(this);
|
||||
|
||||
|
@ -16,6 +16,9 @@ class Zone;
|
||||
class Task : public InlineLinkedListNode<Task> {
|
||||
friend class InlineLinkedListNode<Task>;
|
||||
public:
|
||||
static Task* create(const String& path, uid_t, gid_t);
|
||||
Task(String&& name, uid_t, gid_t);
|
||||
|
||||
#ifdef TASK_SANITY_CHECKS
|
||||
static void checkSanity(const char* msg = nullptr);
|
||||
#else
|
||||
|
Binary file not shown.
@ -27,7 +27,7 @@
|
||||
#include "Console.h"
|
||||
|
||||
#define TEST_VFS
|
||||
#define TEST_ELF_LOADER
|
||||
//#define TEST_ELF_LOADER
|
||||
//#define TEST_CRASHY_USER_PROCESSES
|
||||
|
||||
static void motd_main() NORETURN;
|
||||
@ -167,6 +167,8 @@ static void init_stage2()
|
||||
}
|
||||
#endif
|
||||
|
||||
auto* idTask = Task::create("/bin/id", (uid_t)209, (gid_t)1985);
|
||||
|
||||
//new Task(motd_main, "motd", IPC::Handle::MotdTask, Task::Ring0);
|
||||
//new Task(syscall_test_main, "syscall_test", IPC::Handle::MotdTask, Task::Ring3);
|
||||
|
||||
|
@ -5,7 +5,9 @@ extern "C" int main(int, char**);
|
||||
extern "C" int _start()
|
||||
{
|
||||
// FIXME: Pass appropriate argc/argv.
|
||||
main(0, nullptr);
|
||||
int status = main(0, nullptr);
|
||||
|
||||
Syscall::invoke(Syscall::PosixExit, status);
|
||||
|
||||
// Birger's birthday <3
|
||||
return 20150614;
|
||||
|
Loading…
Reference in New Issue
Block a user