Memcpy() in sicherer Programmierung?

Lesezeit: 7 Minuten

Bin neulich drüber gestolpert ein Artikel das behauptet, Microsoft verbietet die memcpy() Funktion in seinen sicheren Programmierläden. Ich verstehe die der Funktion innewohnenden Schwachstellen, aber ist es notwendig, ihre Verwendung vollständig zu verbieten?

Sollten Programme, die ich schreibe, vermieden werden memcpy() vollständig oder nur um sicherzustellen, dass es sicher verwendet wird? Welche Alternativen gibt es, die eine ähnliche, aber sicherere Funktionalität bieten?

Benutzer-Avatar
Thomas L Holday

Microsoft bietet Alternativen zu memcpy und wmemcpy, die ihre Parameter validieren.

memcpy_s sagt: „Hmm, bevor ich von dieser Adresse lese, lass mich selbst überprüfen, dass es kein Nullzeiger ist; und bevor ich an diese Adresse schreibe, werde ich diesen Test noch einmal durchführen. Ich werde auch die Anzahl der Bytes I vergleichen aufgefordert wurden, auf die angegebene Größe des Ziels zu kopieren; wenn und nur wenn der Anruf alle diese Tests besteht, soll ich die Kopie durchführen.”

memcpy sagt: “Füllen Sie das Ziel in ein Register, stopfen Sie die Quelle in ein Register, stopfen Sie die Zählung in ein Register, führen Sie MOVSB ​​oder MOVSW aus.” (Beispiel zu Geocities, nicht mehr lange von dieser Welt: http://www.geocities.com/siliconvalley/park/3230/x86asm/asml1013.html)

Edit: Für ein Beispiel in freier Wildbahn Dein Wunsch ist mir Befehl Ansatz für memcpy, betrachten Sie OpenSolaris, wo memcpy ist (für einige Konfigurationen) in Bezug auf bcopy definiertund bkopieren (für einige Konfigurationen) ist …

void
     33 bcopy(from, to, count)
     34 #ifdef vax
     35     unsigned char *from, *to;
     36     int count;
     37 {
     38 
     39     asm("   movc3   12(ap),*4(ap),*8(ap)");
     40 }
     41 #else
     42 #ifdef u3b      /* movblkb only works with register args */
     43     unsigned char *from, *to;
     44     int count;
     45 {
     46     asm("   movblkb %r6, %r8, %r7");
     47 }
     48 #else
     49     unsigned char *from, *to;
     50     int count;
     51 {
     52     while ((count--) > 0)
     53         *to++ = *from++;
     54 }
     55 #endif

Bearbeiten: Danke, Millie Smith! Hier ist, was auf der Geocities-Seite war, die ich oben verlinkt habe:

MOVS

Die Anweisung movs wird verwendet, um den Quellstring in das Ziel zu kopieren (ja, kopieren, nicht verschieben). Diese Anweisung hat zwei Varianten: movsb und movsw. Das movsb (“String-Byte verschieben”) verschiebt jeweils ein Byte, während movsw jeweils zwei Bytes verschiebt.

Da wir mehrere Bytes gleichzeitig verschieben möchten, werden diese movs-Anweisungen in Stapeln mit dem Präfix rep ausgeführt. Die Anzahl der Bewegungen wird durch das CX-Register angegeben. Siehe das Beispiel unten:

:
lds   si, [src]
les   di, [dest]
cld
mov   cx, 100
rep   movsb
:

Dieses Beispiel kopiert 100 Bytes von src nach dest. Wenn Sie movsb durch movsw ersetzen, kopieren Sie stattdessen 200 Bytes. Wenn Sie das Rep-Präfix entfernen, hat das CX-Register keine Auswirkung. Sie verschieben ein Byte (wenn es sich um movsb handelt, oder um 2 Bytes, wenn es sich um movsw handelt).

  • Vergessen wir nicht, dass jede gute Memcpy-Implementierung die Speicherausrichtung berücksichtigt.

    – TrayMan

    15. Mai 2009 um 18:45 Uhr

  • Ich denke, movsb, movsw ist nicht mehr der schnellste Weg, um memcpy zu machen. ich denken (nicht getestet) Der schnellste Weg besteht darin, die Speicherausrichtung zu berücksichtigen (wie erwähnt) und SSE-Anweisungen zum Kopieren von Daten zu verwenden. Ich glaube, das ist die Art und Weise, wie OS X gcc es macht.

    – mmx

    15. Mai 2009 um 19:46 Uhr

  • Mir gefiel Ihre Erklärung in Bezug auf x86 asm :).

    – Soumya

    16. Mai 2009 um 15:12 Uhr

  • @Mehrdad, meine Recherche zu memcpy in glibc endet in Sackgassen mit der Quelle, die __vm_copy aufruft. vm_copy ist nicht Teil von glibc und ich kann die Quelle für vm_copy nicht finden. Hast du zufällig einen Link?

    – Thomas L Holday

    16. Mai 2009 um 16:38 Uhr

  • Leider ist memcpy_s nicht viel besser. Überläufe des Zielpuffers sind nur ein mögliches Problem. Das Überlaufen des Quellpuffers (seltener) kann ebenfalls Sicherheitslücken verursachen, ebenso wie das Kopieren von Blöcken, die sich überschneiden.

    – Adrian McCarthy

    25. März 2011 um 20:54 Uhr

Mach dir keine Sorgen. Microsofts Alternativen sind nicht viel besser. Der Hauptwert besteht darin, dass diese dazu führen, dass Ihr Code nicht mehr auf Linux portiert werden kann. Microsoft macht viel mehr Geld mit dem Betriebssystem, das sie an Ihre Kunden verkaufen, als mit der Kopie von Visual C++, die Sie gekauft haben.

  • Sie Sie können immer noch memcpy verwenden

    – Dustin Getz

    15. Oktober 2009 um 12:22 Uhr

  • In der Tat. Die Frage war “soll ich memcpy vermeiden” und meine Antwort ist “Nein, nicht stören”

    – MSalter

    15. Oktober 2009 um 12:25 Uhr

Eine Kettensäge ist, wenn sie richtig verwendet wird, sicher. Dasselbe gilt für memcpy(). Aber in beiden Fällen kann ein Nagel fliegen und Sie verletzen, wenn Sie ihn treffen.

Kurz gesagt, memcpy() ist für Low-Level-Computing erforderlich und wird nicht verschwinden, aber für High-Level-Programmierung brauchen Sie es nicht. In Python gibt es kein memcpy().

  • Denken Sie daran, dass dies Python nicht unbedingt besser macht. Ich liebe Python, aber manchmal möchte ich einfach nur eine Struktur oder einen Zeiger setzen. Gleiches gilt in die andere Richtung.

    – Matt Tischler

    26. August 2010 um 7:32 Uhr


  • Wenn ich die Wahl habe, mache ich das lieber in C: *struct1 = struct2; statt memcpy(struct1,&struct2, sizeof(struct1));

    – 0x6adb015

    16. August 2012 um 13:31 Uhr

  • Python ist bei einem Vergleich zwischen memcpy() und memcpy_s() völlig off-topic

    – März

    17. Dezember 2013 um 23:33 Uhr

  • @ 0x6adb015 Ja, das ist offensichtlich ein Kinderspiel. memcpy ist sehr nützlich, wenn es um Daten geht, die nicht ausgerichtet werden müssen (z. B. generische Puffereingabe in eine Bibliotheksfunktion) und von denen vernünftigerweise nicht erwartet werden kann, dass sie ausgerichtet werden (verschiedene Ausrichtungsanforderungen je nach Backend-Implementierung usw.). Dann ist die nur Eine sichere, konforme und portable Möglichkeit, an solchen Daten zu arbeiten, besteht darin, sie in eine bekanntermaßen ausgerichtete Variable (z. B. stapelzugeordnet) + Endianness-Handhabung zu speichern. x86 verbirgt das Problem, indem nicht ausgerichtete Speicherzugriffe in der Hardware behoben werden, aber es gibt dort viel UB-Potenzial.

    – Thomas

    17. Juli 2014 um 4:35 Uhr


Der Artikel selbst beschreibt eine sicherere Alternative: memcpy_s, bei der Sie die maximale Länge des Ziels angeben müssen. Wenn diese Zahl unabhängig von der Menge der zu kopierenden Bytes bereitgestellt wird, wirkt sie als Barriere, um einen Pufferüberlauf zu verhindern. Natürlich können Sie das missbrauchen, indem Sie beiden die gleiche Nummer geben.

Macht mich das Verbot von memcpy() in meinem Code zu einem besseren Programmierer und meine Anwendung sicherer oder nur inkompatibler? Ich bin mir nicht sicher, ob MS wirklich etwas ändern oder nur neuen C-Code mit anderen Compilern inkompatibel machen will. Übrigens. MS macht diesen Trick bei vielen Funktionen und es ist ziemlich nervig. strcpy -> strcpy_s -> StringCchCopy.

  • Sie haben es nicht verboten; Sie haben eine Warnung eingeführt, die potenziell unsicher ist. Wenn sie ihrerseits die Warnung beachtet und intern verboten haben, ist das vielleicht eine gute Sache für die Plattform? Dies ist kein Compiler-Portabilitätsproblem, sondern ein Bibliotheks-Portabilitätsproblem. Wenn du wählen um eine nicht standardmäßige Bibliotheksfunktion zu verwenden, dann Sie wählen Portabilität zu brechen.

    Benutzer172783

    15. Oktober 2009 um 11:54 Uhr

Benutzer-Avatar
Anton Kasennikow

Ich denke, dass C dem Programmierer die Option überlassen sollte, sich selbst in den Fuß zu schießen. Die manuelle Speicherverwaltung ist sicher, wenn sie richtig durchgeführt wird.

  • Sie haben es nicht verboten; Sie haben eine Warnung eingeführt, die potenziell unsicher ist. Wenn sie ihrerseits die Warnung beachtet und intern verboten haben, ist das vielleicht eine gute Sache für die Plattform? Dies ist kein Compiler-Portabilitätsproblem, sondern ein Bibliotheks-Portabilitätsproblem. Wenn du wählen um eine nicht standardmäßige Bibliotheksfunktion zu verwenden, dann Sie wählen Portabilität zu brechen.

    Benutzer172783

    15. Oktober 2009 um 11:54 Uhr

Sie haben es selbst gesagt: „Microsoft verbietet die Funktion memcpy() in seiner Sichere Programmiershopsich verstehe die Schwachstellen, die der Funktion innewohnen,”

memcpy() und eine Fülle anderer Standardfunktionen sind dafür bekannt, Schwachstellen zu verursachen, also warum sollte ein sicherer Programmiershop ihre Verwendung zulassen, wenn eine (wenn auch inkrementelle) Verbesserung trivial ist?

Zweifellos in ihren Bemühungen, die Sicherheit ihrer eigenen Produkte zu verbessern, zeigten die Code-Reviews deutlich, dass diese Funktionen für einen erheblichen Teil der Schwachstellen, Pufferüberläufe usw. verantwortlich waren. Anstatt Wrapper nur für den internen Gebrauch zu erstellen, führten sie sie in die Standardbibliothek ein und eine Compiler-Warnung (kein Verbot) zum Nutzen aller hinzugefügt.

  • Da es das Problem nicht wirklich löst, ist der Parameter schlecht. Eine Funktion, die einen eingebauten Compiler verwendet, der die Zielgröße automatisch nachschlägt, wäre weitaus weniger fehleranfällig, zB) eine negative Zahl wird zu einem riesigen unsigned size_t. Rushing eine unausgegorene sogenannte Lösung, die andere Möglichkeiten für Programmierfehler und Reklamationen einführt security ist keine wirkliche Lösung. Es gibt andere Versuche dazu, zB) OpenBSD strlcpy und strlcat, die aus ähnlichen Gründen abgelehnt werden.

    – Rob11311

    28. Juni 2014 um 13:21 Uhr


1187430cookie-checkMemcpy() in sicherer Programmierung?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy