Kernel+Userland: Remove loadable kernel moduless

These interfaces are broken for about 9 months, maybe longer than that.
At this point, this is just a dead code nobody tests or tries to use, so
let's remove it instead of keeping a stale code just for the sake of
keeping it and hoping someone will fix it.

To better justify this, I read that OpenBSD removed loadable kernel
modules in 5.7 release (2014), mainly for the same reason we do -
nobody used it so they had no good reason to maintain it.
Still, OpenBSD had LKMs being effectively working, which is not the
current state in our project for a long time.
An arguably better approach to minimize the Kernel image size is to
allow dropping drivers and features while compiling a new image.
This commit is contained in:
Liav A 2021-09-11 15:57:41 +03:00 committed by Andreas Kling
parent b92871f7ef
commit 04ba31b8c5
Notes: sideshowbarker 2024-07-18 04:15:47 +09:00
19 changed files with 0 additions and 530 deletions

View file

@ -1,35 +0,0 @@
## Name
module\_load - load a kernel module
## Synopsis
```**c++
#include <serenity.h>
int module_load(const char* path, size_t path_length);
```
## Description
`module_load()` will load a kernel module from an ELF object file given its
path in the filesystem.
## Return value
If the module is successfully loaded, `module_load()` returns 0. Otherwise, it
returns -1 and sets `errno` to describe the error.
## Errors
* `EPERM`: The calling process does not have superuser permissions.
* `EFAULT`: `path` pointed to memory that was not accessible for the caller.
* `ENOEXEC`: The specified file could not be parsed as an ELF object.
* `EINVAL`: One or more symbols referred to by the module could not be resolved, or the module had no `.text` section, or didn't export a `module_init` function.
* `EEXIST`: A module with the same name was already loaded.
## See also
* [`module_unload`(2)](module_unload.md)
* [`modload`(8)](../man8/modload.md)
* [`kernel_modules`(7)](../man7/kernel_modules.md)

View file

@ -1,32 +0,0 @@
## Name
module\_unload - unload a kernel module
## Synopsis
```**c++
#include <serenity.h>
int module_unload(const char* name, size_t name_length);
```
## Description
`module_unload()` will unload a kernel module by name.
## Return value
If the module is successfully unloaded, `module_unload()` returns 0.
Otherwise, it returns -1 and sets `errno` to describe the error.
## Errors
* `EPERM`: The calling process does not have superuser permissions.
* `EFAULT`: `path` pointed to memory that was not accessible for the caller.
* `ENOENT`: There was no module loaded with the specified name.
## See also
* [`module_load`(2)](module_load.md)
* [`modunload`(8)](../man8/modunload.md)
* [`kernel_modules`(7)](../man7/kernel_modules.md)

View file

@ -1,65 +0,0 @@
## Name
Kernel Modules - runtime code loading for the kernel
## Description
Serenity's kernel supports loading modules at runtime. This functionality can
be used to implement optional features (e.g. drivers), and speed up your
development cycle.
## Module format
A kernel module is a regular ELF object file which must export several
symbols. Any symbols it refers to will be resolved when it is loaded.
### `module_name`
This should be a string like `const char module_name[]` containing the name of
the module. This is used to give the module a name in any informational
contexts, but also to ensure that the module is not loaded twice by accident,
and also used as a reference to unload the module later.
### `module_init`
This should be a function with the following signature: `void module_init()`.
It will be called when the module is loaded.
### `module_fini`
This is optional, but if defined it should be a function with the following
signature: `void module_fini()`. It will be called when the module is
unloaded.
## Example:
```c++
#include <Kernel/kstdio.h>
#include <Kernel/Process.h>
extern "C" const char module_name[] = "ExampleModule";
extern "C" void module_init()
{
kprintf("ExampleModule has booted!\n");
for (int i = 0; i < 3; ++i) {
kprintf("i is now %d\n", i);
}
kprintf("current pid: %d\n", current->process().sys$getpid());
kprintf("current process name: %s\n", current->process().name().characters());
}
extern "C" void module_fini()
{
kprintf("ExampleModule is being removed!\n");
}
```
## See also
* [`modload`(8)](../man8/modload.md)
* [`modunload`(8)](../man8/modunload.md)
* [`module_load`(2)](../man2/module_load.md)
* [`module_unload`(2)](../man2/module_unload.md)

View file

@ -1,25 +0,0 @@
## Name
modload - load a kernel module
## Synopsis
```**sh
$ modload <path>
```
## Description
Load a kernel module specified by *path*.
## Examples
```sh
$ modload /mod/TestModule.o
```
## See also
* [`modunload`(1)](modunload.md)
* [`module_load`(2)](../man2/module_load.md)
* [`kernel_modules`(7)](../man7/kernel_modules.md)

View file

@ -1,25 +0,0 @@
## Name
modunload - unload a kernel module
## Synopsis
```**sh
$ modunload <name>
```
## Description
Unload a kernel module specified by *name*.
## Examples
```sh
$ modunload TestModule
```
## See also
* [`modload`(8)](modload.md)
* [`module_unload`(2)](../man2/module_unload.md)
* [`kernel_modules`(7)](../man7/kernel_modules.md)

View file

@ -121,8 +121,6 @@ enum class NeedsBigProcessLock {
S(mkdir, NeedsBigProcessLock::Yes) \
S(mknod, NeedsBigProcessLock::Yes) \
S(mmap, NeedsBigProcessLock::Yes) \
S(module_load, NeedsBigProcessLock::Yes) \
S(module_unload, NeedsBigProcessLock::Yes) \
S(mount, NeedsBigProcessLock::Yes) \
S(mprotect, NeedsBigProcessLock::Yes) \
S(mremap, NeedsBigProcessLock::Yes) \

View file

@ -219,7 +219,6 @@ set(KERNEL_SOURCES
Syscalls/mkdir.cpp
Syscalls/mknod.cpp
Syscalls/mmap.cpp
Syscalls/module.cpp
Syscalls/mount.cpp
Syscalls/open.cpp
Syscalls/perf_event.cpp
@ -528,4 +527,3 @@ serenity_install_headers(Kernel)
serenity_install_sources(Kernel)
add_subdirectory(Prekernel)
add_subdirectory(Modules)

View file

@ -20,7 +20,6 @@
#include <Kernel/Interrupts/GenericInterruptHandler.h>
#include <Kernel/Interrupts/InterruptManagement.h>
#include <Kernel/KBufferBuilder.h>
#include <Kernel/Module.h>
#include <Kernel/Net/LocalSocket.h>
#include <Kernel/Net/NetworkAdapter.h>
#include <Kernel/Net/NetworkingManagement.h>
@ -682,33 +681,7 @@ private:
return KSuccess;
}
};
class ProcFSModules final : public ProcFSGlobalInformation {
public:
static NonnullRefPtr<ProcFSModules> must_create();
virtual mode_t required_mode() const override { return 0400; }
private:
ProcFSModules();
virtual KResult try_generate(KBufferBuilder& builder) override
{
extern HashMap<String, OwnPtr<Module>>* g_modules;
JsonArraySerializer array { builder };
for (auto& it : *g_modules) {
auto obj = array.add_object();
obj.add("name", it.value->name);
obj.add("module_init", it.value->module_init);
obj.add("module_fini", it.value->module_fini);
u32 size = 0;
for (auto& section : it.value->sections) {
size += section.capacity();
}
obj.add("size", size);
}
array.finish();
return KSuccess;
}
};
class ProcFSProfile final : public ProcFSGlobalInformation {
public:
static NonnullRefPtr<ProcFSProfile> must_create();
@ -791,10 +764,6 @@ UNMAP_AFTER_INIT NonnullRefPtr<ProcFSCommandLine> ProcFSCommandLine::must_create
{
return adopt_ref_if_nonnull(new (nothrow) ProcFSCommandLine).release_nonnull();
}
UNMAP_AFTER_INIT NonnullRefPtr<ProcFSModules> ProcFSModules::must_create()
{
return adopt_ref_if_nonnull(new (nothrow) ProcFSModules).release_nonnull();
}
UNMAP_AFTER_INIT NonnullRefPtr<ProcFSProfile> ProcFSProfile::must_create()
{
return adopt_ref_if_nonnull(new (nothrow) ProcFSProfile).release_nonnull();
@ -853,10 +822,6 @@ UNMAP_AFTER_INIT ProcFSCommandLine::ProcFSCommandLine()
: ProcFSGlobalInformation("cmdline"sv)
{
}
UNMAP_AFTER_INIT ProcFSModules::ProcFSModules()
: ProcFSGlobalInformation("modules"sv)
{
}
UNMAP_AFTER_INIT ProcFSProfile::ProcFSProfile()
: ProcFSGlobalInformation("profile"sv)
{
@ -896,7 +861,6 @@ UNMAP_AFTER_INIT NonnullRefPtr<ProcFSRootDirectory> ProcFSRootDirectory::must_cr
directory->m_components.append(ProcFSDevices::must_create());
directory->m_components.append(ProcFSUptime::must_create());
directory->m_components.append(ProcFSCommandLine::must_create());
directory->m_components.append(ProcFSModules::must_create());
directory->m_components.append(ProcFSProfile::must_create());
directory->m_components.append(ProcFSKernelBase::must_create());

View file

@ -1,26 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/String.h>
#include <AK/Vector.h>
#include <Kernel/KBuffer.h>
namespace Kernel {
typedef void* (*ModuleInitPtr)();
typedef void* (*ModuleFiniPtr)();
struct Module {
String name;
NonnullOwnPtrVector<KBuffer> sections;
ModuleInitPtr module_init { nullptr };
ModuleFiniPtr module_fini { nullptr };
};
}

View file

@ -1,8 +0,0 @@
set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)
function(serenity_kernel_module name sources)
add_library(${name} STATIC ${sources})
install(FILES $<TARGET_OBJECTS:${name}> DESTINATION mod)
endfunction()
serenity_kernel_module(TestModule TestModule.cpp)

View file

@ -1,24 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Format.h>
#include <Kernel/Modules/module_syms.h>
extern "C" const char module_name[] = "TestModule";
extern "C" void module_init()
{
dmesgln("TestModule has booted!");
for (int i = 0; i < 3; ++i) {
dmesgln("i is now {}", i);
}
}
extern "C" void module_fini()
{
dmesgln("TestModule is being removed!");
}

View file

@ -1,11 +0,0 @@
/*
* Copyright (c) 2020, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
extern "C" const char module_name[];
extern "C" void module_init();
extern "C" void module_fini();

View file

@ -25,7 +25,6 @@
#include <Kernel/Memory/AnonymousVMObject.h>
#include <Kernel/Memory/PageDirectory.h>
#include <Kernel/Memory/SharedInodeVMObject.h>
#include <Kernel/Module.h>
#include <Kernel/PerformanceEventBuffer.h>
#include <Kernel/PerformanceManager.h>
#include <Kernel/Process.h>
@ -45,7 +44,6 @@ static void create_signal_trampoline();
RecursiveSpinlock g_profiling_lock;
static Atomic<pid_t> next_pid;
static Singleton<SpinlockProtected<Process::List>> s_processes;
READONLY_AFTER_INIT HashMap<String, OwnPtr<Module>>* g_modules;
READONLY_AFTER_INIT Memory::Region* g_signal_trampoline_region;
static Singleton<MutexProtected<String>> s_hostname;
@ -72,8 +70,6 @@ ProcessID Process::allocate_pid()
UNMAP_AFTER_INIT void Process::initialize()
{
g_modules = new HashMap<String, OwnPtr<Module>>;
next_pid.store(0, AK::MemoryOrder::memory_order_release);
// Note: This is called before scheduling is initialized, and before APs are booted.

View file

@ -393,8 +393,6 @@ public:
KResultOr<FlatPtr> sys$getrandom(Userspace<void*>, size_t, unsigned int);
KResultOr<FlatPtr> sys$getkeymap(Userspace<const Syscall::SC_getkeymap_params*>);
KResultOr<FlatPtr> sys$setkeymap(Userspace<const Syscall::SC_setkeymap_params*>);
KResultOr<FlatPtr> sys$module_load(Userspace<const char*> path, size_t path_length);
KResultOr<FlatPtr> sys$module_unload(Userspace<const char*> name, size_t name_length);
KResultOr<FlatPtr> sys$profiling_enable(pid_t, u64);
KResultOr<FlatPtr> sys$profiling_disable(pid_t);
KResultOr<FlatPtr> sys$profiling_free_buffer(pid_t);

View file

@ -1,168 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/FileSystem/OpenFileDescription.h>
#include <Kernel/FileSystem/VirtualFileSystem.h>
#include <Kernel/KSyms.h>
#include <Kernel/Module.h>
#include <Kernel/Process.h>
#include <LibELF/Image.h>
namespace Kernel {
extern HashMap<String, OwnPtr<Module>>* g_modules;
KResultOr<FlatPtr> Process::sys$module_load(Userspace<const char*> user_path, size_t path_length)
{
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
if (!is_superuser())
return EPERM;
REQUIRE_NO_PROMISES;
auto path = TRY(get_syscall_path_argument(user_path, path_length));
auto description = TRY(VirtualFileSystem::the().open(path->view(), O_RDONLY, 0, current_directory()));
auto payload = TRY(description->read_entire_file());
auto storage = TRY(KBuffer::try_create_with_bytes(payload->bytes()));
auto elf_image = try_make<ELF::Image>(storage->data(), storage->size());
if (!elf_image)
return ENOMEM;
if (!elf_image->parse())
return ENOEXEC;
HashMap<String, u8*> section_storage_by_name;
auto module = try_make<Module>();
if (!module)
return ENOMEM;
KResult section_loading_result = KSuccess;
elf_image->for_each_section_of_type(SHT_PROGBITS, [&](const ELF::Image::Section& section) {
if (!section.size() || !section_loading_result.is_error())
return;
auto section_storage_or_error = KBuffer::try_create_with_bytes(ReadonlyBytes { section.raw_data(), section.size() }, Memory::Region::Access::ReadWriteExecute);
if (section_storage_or_error.is_error()) {
section_loading_result = section_storage_or_error.error();
return;
}
auto section_storage = section_storage_or_error.release_value();
section_storage_by_name.set(section.name(), section_storage->data());
module->sections.append(move(section_storage));
});
if (section_loading_result.is_error())
return section_loading_result;
bool missing_symbols = false;
elf_image->for_each_section_of_type(SHT_PROGBITS, [&](const ELF::Image::Section& section) {
if (!section.size())
return;
auto* section_storage = section_storage_by_name.get(section.name()).value_or(nullptr);
VERIFY(section_storage);
auto relocations = section.relocations();
VERIFY(relocations.has_value());
relocations->for_each_relocation([&](const ELF::Image::Relocation& relocation) {
auto& patch_ptr = *reinterpret_cast<ptrdiff_t*>(section_storage + relocation.offset());
switch (relocation.type()) {
case R_386_PC32: {
// PC-relative relocation
dbgln("PC-relative relocation: {}", relocation.symbol().name());
auto symbol_address = address_for_kernel_symbol(relocation.symbol().name());
if (symbol_address == 0)
missing_symbols = true;
dbgln(" Symbol address: {:p}", symbol_address);
ptrdiff_t relative_offset = (FlatPtr)symbol_address - ((FlatPtr)&patch_ptr + 4);
patch_ptr = relative_offset;
break;
}
case R_386_32: // Absolute relocation
dbgln("Absolute relocation: '{}' value={}, index={}", relocation.symbol().name(), relocation.symbol().value(), relocation.symbol_index());
if (relocation.symbol().bind() == STB_LOCAL) {
auto* section_storage_containing_symbol = section_storage_by_name.get(relocation.symbol().section().name()).value_or(nullptr);
VERIFY(section_storage_containing_symbol);
u32 symbol_address = (ptrdiff_t)(section_storage_containing_symbol + relocation.symbol().value());
if (symbol_address == 0)
missing_symbols = true;
dbgln(" Symbol address: {:p}", symbol_address);
patch_ptr += symbol_address;
} else if (relocation.symbol().bind() == STB_GLOBAL) {
u32 symbol_address = address_for_kernel_symbol(relocation.symbol().name());
if (symbol_address == 0)
missing_symbols = true;
dbgln(" Symbol address: {:p}", symbol_address);
patch_ptr += symbol_address;
} else {
VERIFY_NOT_REACHED();
}
break;
}
});
});
if (missing_symbols)
return EINVAL;
auto* text_base = section_storage_by_name.get(".text").value_or(nullptr);
if (!text_base) {
dbgln("No .text section found in module!");
return EINVAL;
}
elf_image->for_each_symbol([&](const ELF::Image::Symbol& symbol) {
dbgln(" - {} '{}' @ {:p}, size={}", symbol.type(), symbol.name(), symbol.value(), symbol.size());
if (symbol.name() == "module_init") {
module->module_init = (ModuleInitPtr)(text_base + symbol.value());
} else if (symbol.name() == "module_fini") {
module->module_fini = (ModuleFiniPtr)(text_base + symbol.value());
} else if (symbol.name() == "module_name") {
const u8* storage = section_storage_by_name.get(symbol.section().name()).value_or(nullptr);
if (storage)
module->name = String((const char*)(storage + symbol.value()));
}
});
if (!module->module_init)
return EINVAL;
if (g_modules->contains(module->name)) {
dbgln("a module with the name {} is already loaded; please unload it first", module->name);
return EEXIST;
}
module->module_init();
auto name = module->name;
g_modules->set(name, move(module));
return 0;
}
KResultOr<FlatPtr> Process::sys$module_unload(Userspace<const char*> user_name, size_t name_length)
{
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
if (!is_superuser())
return EPERM;
REQUIRE_NO_PROMISES;
auto module_name = TRY(try_copy_kstring_from_user(user_name, name_length));
auto it = g_modules->find(module_name->view());
if (it == g_modules->end())
return ENOENT;
if (it->value->module_fini)
it->value->module_fini();
g_modules->remove(it);
return 0;
}
}

View file

@ -18,18 +18,6 @@ int disown(pid_t pid)
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int module_load(const char* path, size_t path_length)
{
int rc = syscall(SC_module_load, path, path_length);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int module_unload(const char* name, size_t name_length)
{
int rc = syscall(SC_module_unload, name, name_length);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int profiling_enable(pid_t pid, uint64_t event_mask)
{
int rc = syscall(SC_profiling_enable, pid, event_mask);

View file

@ -16,9 +16,6 @@ __BEGIN_DECLS
int disown(pid_t);
int module_load(const char* path, size_t path_length);
int module_unload(const char* name, size_t name_length);
int profiling_enable(pid_t, uint64_t);
int profiling_disable(pid_t);
int profiling_free_buffer(pid_t);

View file

@ -1,25 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibCore/ArgsParser.h>
#include <serenity.h>
#include <string.h>
int main(int argc, char** argv)
{
const char* path = nullptr;
Core::ArgsParser args_parser;
args_parser.add_positional_argument(path, "Path to the module to load", "path");
args_parser.parse(argc, argv);
int rc = module_load(path, strlen(path));
if (rc < 0) {
perror("module_load");
return 1;
}
return 0;
}

View file

@ -1,25 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibCore/ArgsParser.h>
#include <serenity.h>
#include <string.h>
int main(int argc, char** argv)
{
const char* name = nullptr;
Core::ArgsParser args_parser;
args_parser.add_positional_argument(name, "Name of the module to unload", "name");
args_parser.parse(argc, argv);
int rc = module_unload(name, strlen(name));
if (rc < 0) {
perror("module_unload");
return 1;
}
return 0;
}