Domanda

So che è possibile traboccare il codice ordinario:

char string [9];

scanf ("%s", stringa).

Ma è possibile traboccare scanf ("%8s", stringa)? 8 è solo un esempio.

So che "%8s" funziona come un delimit, ma noto anche quando inserisco la stringa più lunga di 8 caratteri, il programma terminerà a causa di:

* Stack Smashing rilevato *: ./a.out terminato

======== BackTrace: =========

...

Ovviamente c'è una bandiera che rileva Stack Smashing accesa da GCC per impostazione predefinita. Dal momento che si tratta di uno stack, la mia ipotesi è che è ancora possibile traboccare ed eseguire un codice arbitrario.

Contrariamente al normale overflow che si muove il chiamante di scanf ("%s"), se scanf ("%8s") può traboccare, traboccerà la funzione di scanf in modo che quando scanf provi a restituire, si ottiene il controllo.

Ma Scanf è un SYSCall che richiede un cambio di modalità (passare dalla modalità utente in modalità kernel) e internamente chiamerà cose come leggere su stdin ecc. Quindi non sono sicuro che possiamo traboccare in modalità kernel o qualcosa del genere.

I commenti sono benvenuti !!

Aggiornamento >>

Char String [9] è assunto nell'esempio sopra. Char String [8] nel seguire il codice reale.

La domanda riguarda davvero la storia apparentemente contrastante tra Safe Scanf ("%8S") e l'aborto GCC a causa dello stack di Stack.

Codice semplificato:

void foo(pass some pointer) {
char input[8];
int input_number = 0;

while (1) { // looping console
   printf some info;
   scanf("%8s", input);

   input_number = atoi(input);

   if ((strlen(input) == 1) && (strncmp(input, "q", 1) == 0)) {
       input_number = -1;
   }
   switch (input_number) {
       case -1: to quit the console if input = 'q';
       default: to print info that pointer refers to;
       ...
   } 

}

}

Nota:

  1. Foo è chiamato da qualcun altro.
  2. Sebbene String sia 8 byte in codice reale con "%8s", non credo che questo porti allo schianto.
È stato utile?

Soluzione

Vedere http://www.opengroup.org/onlinepubs/009695399/functions/scanf.html:

Ogni direttiva è composta da una delle seguenti ... un intero decimale diverso da zero opzionale che specifica la larghezza massima del campo.

S
Abbina una sequenza di byte che non sono caratteri di spazio bianco. L'applicazione deve garantire che l'argomento corrispondente sia un puntatore al byte iniziale di una matrice di carbone, char firmato o char non firmato abbastanza grande da accettare la sequenza e un codice di carattere null terminato, che deve essere aggiunto automaticamente.

Quindi non traboccerà un buffer di stringa a 9 byte.

Altri suggerimenti

Non mai uso scanf (o fscanf per questo motivo) se vuoi che il tuo contributo sia robusto.

Dovresti usare fgets (o una variante "protetta dallo overflow buffer") quindi usa sscanf su quello.

Il problema principale con scanf e fscanf è che il tuo puntatore del file può finire in una posizione indeterminata se la linea non è del formato previsto (cioè, se il scanf non riesce). Con il fgets/sscanf Metodo, è molto più facile garantire che tu sia su un limite di linea, senza dover usare ftell e fseek Per muoversi intorno al file.

Per quanto riguarda la tua domanda specifica sul fatto che il buffer traboccherà, lo standard C ha questo da dire:

... L'argomento corrispondente deve essere un puntatore all'elemento iniziale di un array di caratteri abbastanza grande da accettare la sequenza e un carattere null terminale, che verrà aggiunto automaticamente.

Quindi, per a "%8s" Formato, hai bisogno di un array da 9 caratteri.

Sospetto che tu abbia qualche altro problema nel tuo codice. Con un programma di test:

#include <stdio.h>
int main(int argc, char* argv[]) {
    char x1;
    char a[9];
    char x2;
    x1 = x2 = ' ';
    scanf ("%s",a);
    printf ("[%c] [%s] [%c]\n",x1,a,x2);
    return 0;
}

Ottengo:

pax> ./qq.exe
dfjdhadgha...lghjdfgjhd
[s] [dfjdhadgha...lghjdfgjhd] [ ]
  6 [main] qq 4744 _cygtls::handle_exceptions: Error while dumping state
  (probably corrupted stack)
  Segmentation fault (core dumped)

Quando cambio lo stesso programma in uso "%8s", Ottengo (esattamente per lo stesso input):

pax> ./qq.exe
dfjdhadgha...lghjdfgjhd
[ ] [dfjdhadg] [ ]

Se la stringa viene assegnata per meno di 8 charter, sovrascriverà sicuramente il buffer anche scanf non aggiungerà un terminator null. Ma fintanto che hai abbastanza spazio nella stringa per il tuo valore non dovresti ottenere un sovraccarico.

Come ha sottolineato ysth, l'array dovrebbe essere in grado di contenere la stringa e Il carattere null terminale, quindi utilizzando un array a 8 byte (specialmente se viene assegnato sullo stack, come è nel codice) è molto probabile che lo rovini.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top