Lesen / Schreiben von Dateien in einem Linux-Kernelmodul

98

Ich kenne alle Diskussionen darüber, warum man keine Dateien aus dem Kernel lesen / schreiben sollte, sondern wie man / proc oder netlink verwendet , um das zu tun. Ich möchte trotzdem lesen / schreiben. Ich habe auch Driving Me Nuts gelesen - Dinge, die Sie niemals im Kernel tun sollten .

Das Problem ist jedoch, dass 2.6.30 nicht exportiert wird sys_read(). Eher ist es eingewickelt SYSCALL_DEFINE3. Wenn ich es also in meinem Modul verwende, erhalte ich die folgenden Warnungen:

WARNING: "sys_read" [xxx.ko] undefined!
WARNING: "sys_open" [xxx.ko] undefined!

insmodDas Modul kann offensichtlich nicht geladen werden, da die Verknüpfung nicht korrekt erfolgt.

Fragen:

  • Wie lese / schreibe ich im Kernel nach 2.6.22 (wo sys_read()/ sys_open()werden nicht exportiert)?
  • Wie werden im Allgemeinen Systemaufrufe verwendet, die im SYSCALL_DEFINEn()Kernel in Makros eingeschlossen sind ?
Methos
quelle

Antworten:

121

Sie sollten sich bewusst sein, dass Sie Datei-E / A innerhalb des Linux-Kernels nach Möglichkeit vermeiden sollten. Die Hauptidee ist, "eine Ebene tiefer" zu gehen und Funktionen der VFS-Ebene anstelle des Syscall-Handlers direkt aufzurufen :

Beinhaltet:

#include <linux/fs.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h>

Öffnen einer Datei (ähnlich wie beim Öffnen):

struct file *file_open(const char *path, int flags, int rights) 
{
    struct file *filp = NULL;
    mm_segment_t oldfs;
    int err = 0;

    oldfs = get_fs();
    set_fs(get_ds());
    filp = filp_open(path, flags, rights);
    set_fs(oldfs);
    if (IS_ERR(filp)) {
        err = PTR_ERR(filp);
        return NULL;
    }
    return filp;
}

Schließen Sie eine Datei (ähnlich wie beim Schließen):

void file_close(struct file *file) 
{
    filp_close(file, NULL);
}

Lesen von Daten aus einer Datei (ähnlich wie bei pread):

int file_read(struct file *file, unsigned long long offset, unsigned char *data, unsigned int size) 
{
    mm_segment_t oldfs;
    int ret;

    oldfs = get_fs();
    set_fs(get_ds());

    ret = vfs_read(file, data, size, &offset);

    set_fs(oldfs);
    return ret;
}   

Schreiben von Daten in eine Datei (ähnlich wie bei pwrite):

int file_write(struct file *file, unsigned long long offset, unsigned char *data, unsigned int size) 
{
    mm_segment_t oldfs;
    int ret;

    oldfs = get_fs();
    set_fs(get_ds());

    ret = vfs_write(file, data, size, &offset);

    set_fs(oldfs);
    return ret;
}

Durch das Synchronisieren wird eine Datei geändert (ähnlich wie bei fsync):

int file_sync(struct file *file) 
{
    vfs_fsync(file, 0);
    return 0;
}

[Bearbeiten] Ursprünglich schlug ich die Verwendung von file_fsync vor, die in neueren Kernelversionen nicht mehr vorhanden ist. Vielen Dank an den armen Kerl, der die Änderung vorgeschlagen hat, dessen Änderung jedoch abgelehnt wurde. Die Bearbeitung wurde abgelehnt, bevor ich sie überprüfen konnte.

dmeister
quelle
2
Danke dir. Ich dachte daran, etwas Ähnliches zu tun, indem ich die Funktionen sys_read / sys_open replizierte. Aber das ist eine große Hilfe. Gibt es eine Möglichkeit, Systemaufrufe zu verwenden, die mit SYSCALL_DEFINE deklariert wurden?
Methos
5
Ich habe diesen Code in Kernel 2.6.30 (Ubuntu 9.04) ausprobiert und beim Lesen der Datei stürzt das System ab. Hat jemand das gleiche Problem erlebt?
Enrico Detoma
@Enrico Detoma? Oh wow. Gibt es eine Möglichkeit, mir das Modul zu geben, das Sie verwendet haben? Noch nie gesehen?
Meister
2
Das wirft sofort die Frage auf, "warum machst du diesen FS-Tanz, übrigens", die hier ganz gut beantwortet wird: linuxjournal.com/node/8110/print unter "Fixing the Address Space".
PypeBros
@dmeister, Objekt nicht gefunden für ur Link VFS-Level-Funktionen
sree
18

Seit der Version 4.14 von Linux - Kernel, vfs_readund vfs_writeFunktionen werden nicht mehr exportieren für den Einsatz in Modulen. Stattdessen werden Funktionen bereitgestellt, die ausschließlich für den Dateizugriff des Kernels vorgesehen sind:

# Read the file from the kernel space.
ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos);

# Write the file from the kernel space.
ssize_t kernel_write(struct file *file, const void *buf, size_t count,
            loff_t *pos);

Außerdem wird filp_openkeine User-Space-Zeichenfolge mehr akzeptiert, sodass sie direkt für den Kernelzugriff verwendet werden kann (ohne mit zu tanzen set_fs).

Tsyvarev
quelle