Frage

Betrachten wir einen Linux-Treiber, dass Anwendungen get_user_pages (oder get_page) Seiten vom rufenden Prozess abzubilden. Die physikalische Adresse der Seiten werden dann an ein Hardware-Gerät übergeben. Sowohl das Verfahren und die Vorrichtung auf den Seiten lesen und schreiben können, bis die Parteien entscheiden, die Kommunikation zu beenden. Insbesondere kann die Kommunikation mit den Seiten nach dem Systemaufruf weiterhin die get_user_pages kehrt aufruft. Der Systemaufruf in-Effekt ist eine gemeinsam genutzten Speicherzone zwischen dem Prozess und der Hardware-Geräteinstallation .

Ich bin besorgt über das, was passiert, wenn der Prozess Anrufe fork (es von einem anderen Thread sein könnte, und könnte entweder während des syscall vorkommt, dass Anrufe get_user_pages im Gang ist oder höher). Insbesondere dann, wenn die Eltern auf den gemeinsam genutzten Speicherbereich nach der Gabel schreibt, was weiß ich über die zugrunde liegenden physikalischen Adresse (vermutlich geändert aufgrund Copy-on-Write)? Ich möchte verstehen:

  1. , was die Kernbedürfnisse gegen einen potenziell misbehaving Prozess zu verteidigen, zu tun (ich will nicht ein Sicherheit Loch schaffen!);
  2. , welche Einschränkungen der Prozess Notwendigkeit zu gehorchen, so dass die Funktionalität unser Fahrer richtig funktioniert (das heißt die physikalischen Speicher bleiben an der gleichen Adresse in dem übergeordneten Prozess abgebildet).

    • Idealerweise würde ich den gemeinsamen Fall mag, wo das Kind Prozess unseren Fahrer gar nicht benutzen (es wahrscheinlich ruft exec fast sofort) an der Arbeit.
    • Idealerweise sollte der Eltern-Prozess keine besonderen Maßnahmen zu ergreifen, wenn die Zuweisung von Speicher, wie wir Code bestehenden haben, die einen Stapel zugewiesenen Puffer übergibt an den Fahrer.
    • Ich bin mir dessen bewusst madvise mit MADV_DONTFORK, und es wäre in Ordnung, der Speicher von dem Kind Prozess Raum verschwinden zu lassen, aber es ist nicht anwendbar auf einen Stapel zugewiesenen Puffer.
    • „Do not fork verwenden, während Sie eine Verbindung aktiv mit unserem Fahrer haben“ wäre ärgerlich, aber akzeptabel als letztes Mittel, wenn Punkt 1 erfüllt ist.

Ich bin bereit, in der Dokumentation oder Quellcode hingewiesen werden. Ich habe unter Linux Device insbesondere sah Treiber , aber nicht dieses Problem finden gerichtet. RTFS angewandt auch nur den relevanten Teil der Kernel-Quelle ist ein wenig überwältigend.

Die Kernel-Version nicht vollständig festgelegt, sondern ist jüngeren Datums (sagen wir mal =2.6.26). Wir Targeting nur Arm Plattformen (Single-Prozessor so weit, aber mehradrige ist gleich um die Ecke), wenn es darauf ankommt.

War es hilfreich?

Lösung

Ein fork() nicht mit get_user_pages() stören. get_user_pages() geben Ihnen einen struct page

Sie müßten es kmap(), bevor sie zugreifen zu können, und diese Zuordnung wird im Kernel-Raum durchgeführt, nicht User-Space.

EDIT:. get_user_pages() die Seitentabelle berühren, aber man sollte nicht darüber besorgt sein (es nur sicherstellen, dass die Seiten in User-Space abgebildet) und kehrt -EFAULT, wenn es irgendein Problem damit hatte

Wenn Sie fork () aufrufen, bis Copy-on-Write durchgeführt wird, wird das Kind in der Lage sein, diese Seite zu sehen. Sobald copy-on-write erfolgt (weil das Kind / der Fahrer / die Eltern auf der Seite durch die User-Space-Mapping geschrieben - nicht den Kernel kmap () muss der Fahrer), wird diese Seite nicht mehr geteilt werden. Wenn Sie noch eine kmap () auf der Seite (im Treibercode) halten, werden Sie nicht in der Lage sein zu wissen, ob Sie die übergeordnete Seite halten oder das Kind.

1) Es ist nicht eine Sicherheitslücke, denn wenn man execve (), all das verschwunden ist.

2) Wenn Sie fork () aufrufen Sie wollen beiden Verfahren identisch zu sein (es ist eine Gabel !!). Ich würde denken, dass Ihr Design sowohl die Eltern und das Kind ermöglichen sollte, den Treiber zugreifen. Execve () wird alles spülen.

Was einige Funktionen in User-Space Zugabe wie:

 f = open("/dev/your_thing")
 mapping = mmap(f, ...)

Wenn mmap () auf dem Gerät aufgerufen wird, eine Speicherzuordnung installieren, mit speziellen Fahnen: http://os1a.cs.columbia.edu/lxr /source/include/linux/mm.h#071

Sie haben einige interessante Dinge wie:

#define VM_SHARED       0x00000008
#define VM_LOCKED       0x00002000
#define VM_DONTCOPY     0x00020000      /* Do not copy this vma on fork */

VM_SHARED wird Copy on Write deaktivieren VM_LOCKED wird auf dieser Seite Swapping deaktivieren VM_DONTCOPY wird die Kernel anweisen, nicht die VMA-Region auf der Gabel zu kopieren, obwohl ich nicht glaube, es ist eine gute Idee,

Andere Tipps

Die kurze Antwort ist madvise(addr, len, MADV_DONTFORK) auf jedem User-Space-Puffer zu verwenden, um Sie zu Ihrem Fahrer geben. Dies teilt dem Kernel, dass die Zuordnung nicht von den Eltern auf das Kind kopiert werden sollte, und so gibt es keine Kuh.

Der Nachteil ist, dass das Kind keine Zuordnung zu dieser Adresse erbt, wenn Sie also das Kind dann starten wollen die Treiber verwenden, müssen sie, dass der Speicher neu zuzuordnen. Aber das ist ziemlich einfach, in User-Space zu tun.

Aktualisieren : a. Auf dem Stack Puffer problematisch ist, ich bin nicht sicher, können Sie es im Allgemeinen sicher machen

Sie können nicht markieren DONTFORK, weil Ihr Kind auf diesem Stack-Seite ausgeführt werden kann, wenn er sich gabelt, oder (noch schlimmer in einer Art und Weise), es könnte eine Funktion Rückkehr später tun und auf den nicht zugeordneten Stack-Seite. (Ich dies auch getestet haben, können Sie gerne markieren Sie Ihren Stapel DONTFORK, schlechte Dinge passieren, wenn Sie die Gabel).

Der andere Weg, eine Kuh zu vermeiden, ist eine gemeinsame Zuordnung zu erstellen, aber Sie können Ihr Stack geteilt aus offensichtlichen Gründen nicht kartieren.

Das bedeutet, dass Sie eine Kuh riskieren, wenn Sie die Gabel. Selbst wenn das Kind „nur“ execs es könnte immer noch den Stapel Seite berühren und eine Kuh verursachen, an die Eltern führen eine andere Seite bekommen, was schlecht ist.

Der eine Kleinigkeit zu Ihren Gunsten ist, dass Code unter Verwendung eines On-stack buffer muss nur Sorge um Code ruft sie gabeln, dh. Sie können nicht einen On-Stack-Puffer verwenden, nachdem die Funktion zurückgekehrt ist. Sie müssen nur Ihre Angerufenen prüfen, und wenn sie nie Du bist sicher Gabel, aber das noch nicht durchführbar sein kann, und ist zerbrechlich, wenn der Code jemals ändert.

Ich glaube, Sie wirklich alle Speicher haben wollen, die Ihren Fahrer gegeben wird von einem benutzerdefinierten allocator in User-Space zu kommen. Es sollte nicht so aufdringlich sein. Der Allocator kann entweder Ihr Gerät direkt mmap, wie die andere Antwort vorgeschlagen, oder einfach nur anonym mmap verwenden, madvise(DONTFORK) und wahrscheinlich mlock() zu vermeiden Swap-out.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top