GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wie lade ich Linux-Kernel-Module aus C-Code?

insmod/rmmod verwenden die Funktionen init_module und delete_module um dies zu tun, die auch eine Manpage zur Verfügung haben. Beide deklarieren die Funktionen als extern anstatt einen Header einzufügen, aber die Manpage sagt, dass sie in <linux/module.h> sein sollten .


init_module / remove_module Minimales lauffähiges Beispiel

Getestet auf einer QEMU + Buildroot VM und einem Ubuntu 16.04-Host mit diesem einfachen Parameterdruckermodul .

Wir verwenden den init_module / finit_module und remove_module Linux-Systemaufrufe.

Der Linux-Kernel bietet zwei Systemaufrufe zum Einfügen von Modulen:

  • init_module
  • finit_module

und:

man init_module

Dokumente, die:

Der Systemaufruf finit_module() ist wie init_module(), liest aber das zu ladende Modul aus dem Dateideskriptor fd. Es ist nützlich, wenn die Authentizität eines Kernelmoduls anhand seiner Position im Dateisystem bestimmt werden kann; In Fällen, in denen dies möglich ist, kann der Mehraufwand für die Verwendung kryptografisch signierter Module zur Bestimmung der Authentizität eines Moduls vermieden werden. Das Argument param_values ​​ist wie bei init_module().

finit ist neuer und wurde erst in v3.8 hinzugefügt. Weitere Begründung:https://lwn.net/Articles/519010/

glibc scheint keinen C-Wrapper für sie bereitzustellen, also erstellen wir einfach unseren eigenen mit syscall .

insmod.c

#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

#define init_module(module_image, len, param_values) syscall(__NR_init_module, module_image, len, param_values)
#define finit_module(fd, param_values, flags) syscall(__NR_finit_module, fd, param_values, flags)

int main(int argc, char **argv) {
    const char *params;
    int fd, use_finit;
    size_t image_size;
    struct stat st;
    void *image;

    /* CLI handling. */
    if (argc < 2) {
        puts("Usage ./prog mymodule.ko [args="" [use_finit=0]");
        return EXIT_FAILURE;
    }
    if (argc < 3) {
        params = "";
    } else {
        params = argv[2];
    }
    if (argc < 4) {
        use_finit = 0;
    } else {
        use_finit = (argv[3][0] != '0');
    }

    /* Action. */
    fd = open(argv[1], O_RDONLY);
    if (use_finit) {
        puts("finit");
        if (finit_module(fd, params, 0) != 0) {
            perror("finit_module");
            return EXIT_FAILURE;
        }
        close(fd);
    } else {
        puts("init");
        fstat(fd, &st);
        image_size = st.st_size;
        image = malloc(image_size);
        read(fd, image, image_size);
        close(fd);
        if (init_module(image, image_size, params) != 0) {
            perror("init_module");
            return EXIT_FAILURE;
        }
        free(image);
    }
    return EXIT_SUCCESS;
}

GitHub-Upstream.

rmmod.c

#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

#define delete_module(name, flags) syscall(__NR_delete_module, name, flags)

int main(int argc, char **argv) {
    if (argc != 2) {
        puts("Usage ./prog mymodule");
        return EXIT_FAILURE;
    }
    if (delete_module(argv[1], O_NONBLOCK) != 0) {
        perror("delete_module");
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

GitHub-Upstream.

Busybox-Quelleninterpretation

Busybox stellt insmod bereit , und da es auf Minimalismus ausgelegt ist, können wir versuchen, daraus abzuleiten, wie es gemacht wird.

Bei Version 1.24.2 ist der Einstiegspunkt bei modutils/insmod.c Funktion insmod_main .

Die IF_FEATURE_2_4_MODULES ist eine optionale Unterstützung für ältere Linux-Kernel-2.4-Module, daher können wir sie vorerst einfach ignorieren.

Das leitet einfach zu modutils.c weiter Funktion bb_init_module .

bb_init_module versucht zwei Dinge:

  • mmap die Datei in den Speicher durch try_to_mmap_module .

    Dadurch wird immer image_size gesetzt auf die Größe von .ko Datei als Nebeneffekt.

  • wenn das fehlschlägt, malloc die Datei mit xmalloc_open_zipped_read_close in den Speicher .

    Diese Funktion entpackt optional zuerst die Datei, wenn es sich um eine ZIP-Datei handelt, und blockiert sie ansonsten einfach.

    Ich verstehe nicht, warum dieses Zipping-Geschäft gemacht wird, da wir uns nicht einmal darauf verlassen können, weil der try_to_mmap_module scheint die Dinge nicht zu entpacken.

Schließlich kommt der Aufruf:

init_module(image, image_size, options);

wobei image ist die ausführbare Datei, die in den Speicher gestellt wurde, und Optionen sind nur "" wenn wir insmod file.elf anrufen ohne weitere Argumente.

init_module wird oben bereitgestellt von:

#ifdef __UCLIBC__
extern int init_module(void *module, unsigned long len, const char *options);
extern int delete_module(const char *module, unsigned int flags);
#else
# include <sys/syscall.h>
# define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
#endif

ulibc ist eine eingebettete libc-Implementierung und scheint init_module bereitzustellen .

Wenn es nicht vorhanden ist, wird glibc angenommen, aber als man init_module sagt:

Der Systemaufruf init_module() wird von glibc nicht unterstützt. In Glibc-Headern wird keine Deklaration bereitgestellt, aber aufgrund einer Eigenart der Geschichte exportiert Glibc eine ABI für diesen Systemaufruf. Um diesen Systemaufruf zu verwenden, reicht es daher aus, die Schnittstelle manuell in Ihrem Code zu deklarieren; Alternativ können Sie den Systemaufruf mit syscall(2) aufrufen.

BusyBox befolgt diesen Rat klug und verwendet syscall , die glibc bereitstellt, und die eine C-API für Systemaufrufe bietet.


Linux
  1. So aktualisieren Sie den Kernel auf dem Linux-Desktop

  2. Linux – Wie führe ich einen Bootloader von Linux aus?

  3. So erstellen, kompilieren und laden Sie ladbare Linux-LKM-Kernel-Module

  4. So kompilieren und installieren Sie Software aus dem Quellcode unter Linux

  5. Wie kann ich einen Speicherblock aus dem Linux-Kernel reservieren?

So laden und entladen Sie Kernel-Module in Linux

So erhalten Sie Nachrichten sofort von der Befehlszeile in Linux

So erstellen Sie einen Linux-Kernel von Grund auf neu

So kompilieren Sie den Linux-Kernel aus der Quelle, um einen benutzerdefinierten Kernel zu erstellen

So installieren Sie Software aus dem Quellcode in Ihrem Linux-System

Wie lädt Linux das 'initrd'-Image?