Der Systemaufruf-Rückgabewert ist wie immer rax
. Siehe What are the calling conventions for UNIX & Linux system calls on i386 and x86-64.
Beachten Sie, dass sys_brk
eine etwas andere Schnittstelle hat als die brk
/sbrk
POSIX-Funktionen; siehe C library/kernel differences section of the Linux brk(2)
man page. Spezifisch, Linux sys_brk
setzt das Programm brechen; Arg und Rückgabewert sind beide Zeiger. Siehe Assembly x86 brk() call use. Diese Antwort braucht Upvotes, weil es der einzig gute in dieser Frage ist.
Der andere interessante Teil Ihrer Frage ist:
ich in diesem Fall
Sie sehen, die Mechanik, wie der Wert in den RCX-Registern nicht ganz verstehen Die Anweisungen syscall
/sysret
ermöglichen es dem Kernel, die Ausführung des Benutzerbereichs fortzusetzen, aber immer noch schnell zu sein.
syscall
lädt oder speichert nicht, es ändert nur Register. Anstatt spezielle Register zu verwenden, um eine Rückkehradresse zu speichern, verwendet es einfach reguläre Ganzzahlregister.
Es ist kein Zufall, dass RCX=RIP
und R11=RFLAGS
nach dem Kernel wieder in Ihren User-Space-Code. Der einzige Weg für diese nicht ist der Fall ist, wenn ein ptrace
Systemaufruf die gespeicherte rcx
oder r11
Wert des Prozesses geändert, während es im Kernel war. (ptrace
ist der Systemaufruf, den gdb verwendet). In diesem Fall würde Linux iret
anstelle von sysret
verwenden, um zum Benutzerbereich zurückzukehren, weil der langsamere allgemeine Fall iret
das tun kann. (Vgl. What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code? für einige Durchgänge von Linux-Systemaufruf-Einstiegspunkten. Meistens die Einstiegspunkte von 32-Bit-Prozessen, jedoch nicht von syscall
in einem 64-Bit-Prozess.
)
Statt eine Absenderadresse auf den Kernel-Stack des Drückens (wie int 0x80
der Fall ist), syscall
:
- Sätze RCX = RIP, R11 = rflags (so ist es unmöglich, den Kernel Sieh dir auch die Originalwerte dieser Regs an, bevor du
syscall
ausgeführt hast).
Masken mit einer vorkonfigurierten Maske aus einem Config-Register (IA32_FMASK
MSR). Dadurch kann der Kernel Interrupts (IF) deaktivieren, bis er fertig ist swapgs
und rsp
setzen, um auf den Kernel-Stack zu zeigen. Selbst mit cli
als erster Anweisung am Einstiegspunkt würde ein Fenster der Schwachstelle entstehen. Sie erhalten auch cld
kostenlos durch Maskierung aus DF
so rep movs
/stos
gehen nach oben, auch wenn User-Space std
verwendet hatte.
Fun Tatsache: AMDs erste vorgeschlagene syscall
/swapgs
Design nicht RFLAGS Maske, sondern they changed it after feedback from kernel developers on the amd64 mailing list (in ~ 2000, ein paar Jahre vor dem ersten Silizium).
springt zum konfigurierten syscall
Einstiegspunkt (Einstellung CS: RIP = IA32_LSTAR
). Der alte CS
Wert ist nirgendwo gespeichert, denke ich.
Es tut nichts anderes, der Kernel muss swapgs
verwenden, um Zugriff auf einen Info-Block zu bekommen, wo er den Kernel-Stack-Zeiger gespeichert hat, weil rsp
immer noch seinen Wert aus User-Space hat.
So ist die Gestaltung von syscall
erfordert eine ABI-System-Call, das Register clobbers, und das ist, warum die Werte sind, was sie sind.
RCX und R11 werden von der Anweisung [SYSCALL] (http://www.felixcloutier.com/x86/SYSCALL.html) selbst geplagt. Von der Befehlssatzreferenz: _nach dem Speichern der Adresse der Anweisung, die SYSCALL in RCX folgt) _. _RFLAGS_ wird in _R11_ gespeichert –
@MichaelPetch Sehr interessant. Es bedeutet, um sagen zu können, "cl" registrieren zu müssen, muss ich es zuerst löschen, richtig? Ich meine zum Beispiel "xor cl, cl" und dann "mov cl, 7". –
Sie können sich nach dem SYSCALL nicht auf den Wert von _RCX_ oder _R11_ verlassen. Sie müssen also entweder eines der anderen Register anstelle von _RCX_ und _R11_ (und RAX) verwenden oder Sie müssen den Wert speichern (zum Beispiel Stapel) und ihn danach wiederherstellen. _RCX_ und _R11_ werden von Ihnen nicht gesetzt, Sie können sie einfach nicht verwenden und erwarten, dass sie vor und nach dem SYSCALL gleich sind. –