GNU/Linux >> Belajar Linux >  >> Linux

Bagaimana cara memuat modul kernel Linux dari kode C?

insmod/rmmod menggunakan fungsi init_module dan delete_module untuk melakukan ini, yang juga menyediakan halaman manual. Keduanya mendeklarasikan fungsi sebagai extern alih-alih menyertakan tajuk, tetapi halaman manual mengatakan mereka harus dalam <linux/module.h> .


init_module / remove_module contoh minimal yang dapat dijalankan

Diuji pada host QEMU + Buildroot VM dan Ubuntu 16.04 dengan modul printer parameter sederhana ini.

Kami menggunakan init_module / finit_module dan remove_module Panggilan sistem Linux.

Kernel Linux menawarkan dua panggilan sistem untuk penyisipan modul:

  • init_module
  • finit_module

dan:

man init_module

dokumen yang:

Panggilan sistem finit_module() seperti init_module(), tetapi membaca modul yang akan dimuat dari deskriptor file fd. Ini berguna ketika keaslian modul kernel dapat ditentukan dari lokasinya di sistem berkas; dalam kasus yang memungkinkan, penggunaan modul yang ditandatangani secara kriptografis untuk menentukan keaslian modul dapat dihindari. Argumen param_values ​​adalah untuk init_module().

finit lebih baru dan ditambahkan hanya di v3.8. Alasan lainnya:https://lwn.net/Articles/519010/

glibc sepertinya tidak menyediakan pembungkus C untuk mereka, jadi kami hanya membuatnya sendiri dengan 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.

Interpretasi sumber busybox

Busybox menyediakan insmod , dan karena dirancang untuk minimalis, kita dapat mencoba menyimpulkan cara melakukannya dari sana.

Pada versi 1.24.2, titik masuknya ada di modutils/insmod.c fungsi insmod_main .

IF_FEATURE_2_4_MODULES adalah dukungan opsional untuk modul kernel Linux 2.4 lama, jadi kita dapat mengabaikannya untuk saat ini.

Itu hanya meneruskan ke modutils.c fungsi bb_init_module .

bb_init_module mencoba dua hal:

  • mmap file ke memori melalui try_to_mmap_module .

    Ini selalu menyetel image_size dengan ukuran .ko file sebagai efek samping.

  • jika gagal, malloc file ke memori dengan xmalloc_open_zipped_read_close .

    Fungsi ini secara opsional membuka zip file terlebih dahulu jika itu adalah zip, dan hanya mallocs sebaliknya.

    Saya tidak mengerti mengapa bisnis zipping ini dilakukan, karena kami bahkan tidak dapat mengandalkannya karena try_to_mmap_module sepertinya tidak meng-unzip sesuatu.

Akhirnya datang panggilan:

init_module(image, image_size, options);

di mana image adalah executable yang dimasukkan ke dalam memori, dan pilihannya hanya "" jika kita memanggil insmod file.elf tanpa argumen lebih lanjut.

init_module disediakan di atas oleh:

#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 adalah implementasi libc tersemat, dan tampaknya menyediakan init_module .

Jika tidak ada, saya pikir glibc diasumsikan, tetapi sebagai man init_module mengatakan:

Panggilan sistem init_module() tidak didukung oleh glibc. Tidak ada deklarasi yang disediakan di header glibc, tetapi, melalui kekhasan sejarah, glibc mengekspor ABI untuk panggilan sistem ini. Oleh karena itu, untuk menggunakan panggilan sistem ini, cukup mendeklarasikan antarmuka secara manual dalam kode Anda; sebagai alternatif, Anda dapat menjalankan panggilan sistem menggunakan syscall(2).

BusyBox dengan bijak mengikuti saran itu dan menggunakan syscall , yang disediakan oleh glibc, dan yang menawarkan C API untuk panggilan sistem.


Linux
  1. Cara Menginstal Modul Perl Di Linux

  2. Cara Mengkompilasi dan Menginstal Perangkat Lunak dari Kode Sumber di Linux

  3. Bagaimana cara membuat linux bootable minimal (hanya dengan terminal) dari kode sumber kernel?

  1. Cara memutakhirkan Kernel di Desktop Linux

  2. Linux – Bagaimana Cara Menjalankan Bootloader Dari Linux?

  3. Cara Membuat, Mengkompilasi, Memuat Modul Kernel yang Dapat Dimuat LKM Linux

  1. Cara mengatur alamat IP dari C di linux

  2. Bagaimana cara membuat kode modul kernel Linux?

  3. Bagaimana cara menambahkan fungsi polling ke kode modul kernel?