2016-04-22 12 views
-1

Ich schreibe eine C-Bibliothek, die Wrapper-Funktionen für strcpy, strcat, gets usw. bereitstellt, um Pufferüberlaufangriffen vorzubeugen. Im Grunde genommen behalte ich die Größe aller Puffer im Auge und verhindere, dass über den zugewiesenen Speicher geschrieben wird. Ich bin in der Lage, dynamisch zugewiesene Puffer zu verfolgen, indem ich Wrapper für malloc, calloc und realloc schreibe. Aber ich konnte nicht die Größe des Puffers im Stapel bekommen.Pufferüberlaufschutz für stackbasierte Puffer

char s[10]; 
char *s1 = "stackoverflow"; 
strcpy(s,s1); 

Der Aufruf von ‚strcpy‘ in dem obigen Code würde meine Wrapper-Funktion aufrufen, die

char *strcpy(char* s1, const char* s2) 

wie

aussieht Da die Funktion die Quelle als char * nimmt, ich bin nicht in der Lage, die Größe wissen des Quell-Arrays, das sich im Stack befindet. Ich habe versucht, den Stack-basierten Puffer neu zuzuordnen und mein Programm ist abgestürzt. Ist die Neuzuordnung des Puffers eine praktikable Lösung dafür? Jede Hilfe wird geschätzt.

+0

Sie können auch nicht die Größe von Globalen oder die Größe von Arrays innerhalb einer Struktur ermitteln. Beispiel: 'struct person {char name [28]; int age} '- 'malloc' kann wissen, dass es 32 Bytes zugewiesen hat, aber 'strcpy' kann diese 32 Bytes für den Namen nicht verwenden. – MSalters

+0

Sie können das nicht tun. Die einzige Möglichkeit, Pufferüberläufe zu verhindern, besteht nicht darin, 'strcpy'-ähnliche Funktionen zu verwenden, sondern diese durch äquivalente Funktionen zu ersetzen, bei denen Sie explizit die Größe des Zielpuffers übergeben. Z.B. 'secure_strcpy (s, s1, buffersize);' –

+0

Denken Sie darüber nach - wenn es so einfach wäre, hätte es jemand schon getan. –

Antwort

1

Hier s ist die automatische Speicherung und realloc gemeint ist die dynamische zugewiesenen Speicher neu zuzuordnen durch malloc oder andere allocatin Funktionen aufrufen. Sie können also nicht realloc auf s anrufen, es würde Ergebnisse UB aufrufen, also ist Crash keine Überraschung.

Selbst wenn Sie einen Weg finden, um die Größe der automatischen Variablen zu erhalten, können Sie die Größe nicht ändern, das einzige, was Sie tun können, ist einen ganz neuen Puffer zu machen und dann den alten Puffer in den neuen zu kopieren. In diesem Fall benötigen Sie eine Markierung, um zwischen dynamischem Speicher und automatischem Speicher zu unterscheiden.

2

Da die Funktion die Quelle als char * nimmt, kann ich die Größe des Quell-Arrays, das sich im Stapel befindet, nicht ermitteln.

char * ist ein generischer Zeiger, Sie können Ihre Quelle in einen anderen Typ umwandeln.

Ein Beispiel einer Verbindung wörtlichen und ein struct mit:

struct secure { 
    char *s; 
    size_t sz; 
}; 

#define SECURE(xs, xsz) (char *)&((struct secure){.s = xs, .sz = xsz}) 

char *strcpy(char *s1, const char *s2) 
{ 
    struct secure *sec = (struct secure *)s1; 

    if (sec->sz < strlen(s2)) { 
     printf("%s\n", "stackoverflow"); 
    } else { 
     yourimplementation(sec->s, s2); 
    } 
    return sec->s; 
} 

int main(void) 
{ 
    char s[10]; 
    char *s1 = "stackoverflow"; 

    strcpy(SECURE(s, sizeof s - 1), s1); 
    return 0; 
} 

Sie vermeiden auf diese Weise SECURE im Aufruf mit:

struct secure { 
    char *s; 
    size_t sz; 
}; 

#define SECURE(ps, psz) (char *)&((struct secure){.s = ps, .sz = psz}) 
#define strcpy(s1, s2) strcpy(SECURE(s1, sizeof s1 - 1), s2) 

char *(strcpy)(char *s1, const char *s2) /*() to distinguish from macro */ 
{ 
    struct secure *sec = (struct secure *)s1; 

    if (sec->sz < strlen(s2)) { 
     printf("%s\n", "stackoverflow"); 
    } else { 
     yourimplementation(sec->s, s2); 
    } 
    return sec->s; 
} 

int main(void) 
{ 
    char s[10]; 
    char *s1 = "stackoverflow"; 

    strcpy(s, s1); 
    return 0; 
} 

Aber dies wird mit dynamischen Speicher nicht (sizeof Zeiger ist nicht das, was Sie wollen)

0

Sie können nicht die Puffergröße von nur char * Zeiger kennen. Aus diesem Grund implementieren viele Bibliotheken ihre eigenen String-Objekte. Beispiele: GString in glib, PHP hat sein internes String-Objekt, pascal verwendet ein String-Objekt.

0

Sie befassen sich auf eine interessante und automatisierte Weise mit einem gemeinsamen Problem.

Der GCC selbst hat einen Stapelschutz, der das Programm abstürzt, wenn jemand in unerlaubte Bereiche geschrieben hat, ob absichtlich oder nicht. Es platziert bestimmte Variablen auf dem Stack mit definierten Werten und wenn diese Werte sich ändern, kann die Stapelkorruption erkannt werden.

Wenn char Zeiger in Funktionen behandelt wird, gibt es keine Möglichkeit zu wissen, wie viel Speicher der Bereich zeigte. Du könntest deine eigene "char" -Klasse/struct entwerfen, die das für dich handhabt, indem du deinen char-Zeiger und seine Größe zusammenhältst.

struct char_helper { 
    int size; 
    char data[]; 
} 

char buffer[10+sizeof(struct char_helper)]: 
struct char_helper *mychar = (struct char_helper*)buffer; 
mychar.size = 76; 
your_strcpy(mychar, "hallo", 6); 

Ihre Funktion your_strcpy kann jetzt die Größe überprüfen. Technisch habe ich eine Ganzzahl für die Größe vorangestellt. Eine weitere und flexiblere Art und Weise wäre, nur strcpy sagen, welche Größe der Puffer hat es soll kopieren ...

Das ist, was strncpy, snprintf, strnlen tun. Sie haben eine kleine Eigenart mit dem Beenden von 0 Charakteren.