Ist es möglich, Code im Heap-Bereich auszuführen?

8

Ich würde gerne wissen, ob ich ein Code-Stück ausführen kann, das sich im Heap-Bereich befindet.

Sen.
quelle
1
Wenn Sie Fragen zum Verzweigen zu einem Code in einer bestimmten Programmiersprache haben, wenden Sie sich an Stack Overflow .
Gilles 'SO - hör auf böse zu sein'

Antworten:

5

Könnte sein. Wenn der Heap ausführbar ist, können Sie zu diesem Code verzweigen. Einige Unix-Varianten machen den Heap-Speicher jedoch nicht ausführbar , um das Ausnutzen einiger Sicherheitslücken wie Pufferüberläufe zu erschweren (selbst wenn Sie Code in ein Programm einfügen können, können Sie möglicherweise nicht dorthin verzweigen). (Eine Beschreibung der Unix-Varianten und ihrer Konfiguration finden Sie im verlinkten Artikel.) Einige Prozessorarchitekturen verfügen außerdem über separate Caches für Code und Daten , sodass Sie möglicherweise eine Anweisung zum Leeren des Cache ausgeben müssen. Alles in allem ist dies nicht etwas, was Sie von Hand tun möchten.

Es gibt eine Standard-Unix-API zum Laden und Ausführen von Code, die alles tut, um den geladenen Code ausführbar zu machen: dlopen . Der Code muss aus einer Datei geladen werden.

Just-in-Time-Compiler versuchen normalerweise, schnellere Schnittstellen als dlopen zu finden. Sie müssen die stark plattformabhängigen Methoden zur Sicherstellung der Ausführbarkeit von Code verwalten.

EDIT: Danke an Bruce Ediger , der mich daran erinnert hat, dass der Cache geleert werden muss.

Gilles 'SO - hör auf böse zu sein'
quelle
4

Auf einigen Hardwarekomponenten (wie den HP-PA-CPUs von HP) ist dies weitaus schwieriger, und auf anderen (wie der DEC Alpha-CPU) müssen Sie zuerst einen Befehls-Cache leeren, aber im Allgemeinen können Sie Code auf dem Heap ausführen. Das Folgende ist ein einigermaßen anständiges C-Sprachprogramm, das Code "auf dem Heap" ausführt.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>

/* $Id: cpup4.c,v 1.2 1999/02/25 05:12:53 bediger Exp bediger $ */

typedef int (*fxptr)(
                int, int, int (*)(const char *, ...),
                void *,
                void *(*)(void *, const void *, size_t),
                void *(*)(size_t),
                void (*)(void *),
                size_t
);

char *signal_string(int sig);
void  signal_handler(int sig);
int   main(int ac, char **av);
int copyup(
                int i,
                int j,
                int (*xptr)(const char *, ...),
                void *yptr,
                void *(*bptr)(void *, const void *, size_t),
                void *(*mptr)(size_t),
                void (*ffptr)(void *),
                size_t  size
);
void f2(void);

/* return a string for the most common signals this program
 * will generate.  Probably could replace this with strerror()
 */
char *
signal_string(sig)
                int sig;
{
                char *bpr = "Don't know what signal";

                switch (sig)
                {
                case SIGILL:
                                bpr = "Illegal instruction";
                                break;
                case SIGSEGV:
                                bpr = "Segmentation violation";
                                break;
                case SIGBUS:
                                bpr = "Bus error";
                                break;
                }

                return bpr;
}

/* Use of fprintf() seems sketchy.  I think that signal_handler() doesn't
 * need special compiler treatment like generating Position Independent
 * Code.  It stays in one place, and the kernel knows that place.
 */
void
signal_handler(int sig)
{
                (void)fprintf(
                                stderr,
                                "%s: sig = 0x%x\n",
                                signal_string(sig),
                                sig
                );

                exit(99);
}

int
main(int ac, char **av)
{
                int i, j;

                /* check to see if cmd line has a number on it */
                if (ac < 2) {
                                printf("not enough arguments\n");
                                exit(99);
                }
                /* install 3 different signal handlers - avoid core dumps */
                if (-1 == (i = (long)signal(SIGSEGV, signal_handler)))
                {
                                perror("Installing SIGSEGV signal failed");
                                exit(33);
                }
                if (-1 == (i = (long)signal(SIGILL, signal_handler)))
                {
                                perror("Installing SIGILL signal handler failed");
                                exit(33);
                }
                if (-1 == (i = (long)signal(SIGBUS, signal_handler)))
                {
                                perror("Installing SIGBUS signal handler failed");
                                exit(33);
                }

                setbuf(stdout, NULL);

                /*
                 * print out addresses of original functions so there is something to
                 * reference during recursive function copying and calling 
                 */
                printf(
           "main = %p, copyup %p, memcpy %p, malloc %p, printf %p, free %p, size %ld\n",
           main, copyup, memcpy, malloc, printf, free, (size_t)f2 - (size_t)copyup);

                if ((i = atoi(*(av + 1))) < 1) {
                                printf(" i = %d, i must be > 1\n", i);
                                exit(99);
                }

                printf(" going for %d recursions\n", i);

                j = copyup(1, i, printf, copyup, memcpy, malloc, free, (size_t)f2 - (size_t)copyup);

                printf("copyup at %p returned %d\n", copyup, j);


                return 1;
}

int
copyup(
                int i, int j,
                int   (*xptr)(const char *, ...),
                void *yptr,
                void *(*bptr)(void *, const void*, size_t),
                void *(*mptr)(size_t),
                void  (*ffptr)(void *),
                size_t   size
)
{
                fxptr fptr;
                int k;

                if (i == j)
                {
                                (*xptr)("function at %p got to %d'th copy\n", yptr, i);
                                return i;
                } else
                                (*xptr)("function at %p, i = %d, j = %d\n", yptr, i, j);

                if (!(fptr = (fxptr)(*mptr)(size)))
                {
                                (*xptr)("ran out of memory allocating new function\n");
                                return -1;
                }

                (*bptr)(fptr, yptr, size);

                k = (*fptr)(i + 1, j, xptr, (void *)fptr, bptr, mptr, ffptr, size);

                (*xptr)("function at %p got %d back from function at %p\n",
                                yptr, k, fptr);

                (*ffptr)(fptr);

                return (k + 1);
}

void f2(void) {return;}
Bruce Ediger
quelle
1
Ich habe dies versucht, aber ich verstehe nicht, warum ich einen Segmentierungsfehler für alle Werte außer 1 bekomme.
Sen
Ein Argument von 1 führt nur die Funktion aus - obwohl die Funktion eine Kopie von sich selbst auf dem Heap erstellt, führt sie die Heap-Kopie nicht aus. Ich weiß nicht, warum Sie eine Segmentierungsverletzung erhalten. Können Sie weitere Details zu Compiler, CPU, Betriebssystem usw. usw. angeben?
Bruce Ediger