2009-05-26 11 views
5

Ho il seguente frammento di codice C e devono identificare l'errore e suggerire un modo di scriverlo in modo più sicuro:In che modo questo frammento C può essere scritto in modo più sicuro?

char somestring[] = "Send money!\n"; 
char *copy; 

copy = (char *) malloc(strlen(somestring)); 

strcpy(copy, somestring); 
printf(copy); 

Quindi l'errore è che strlen ignora la finale '\0' di una stringa e quindi non è verrà assegnata una quantità di memoria sufficiente per la copia, ma non sono sicuro di cosa stiano per scrivere in modo più sicuro?

Potrei semplicemente usare malloc(strlen(somestring)+1)) presumo ma sto pensando che ci deve essere un modo migliore di quello?


EDIT: OK, ho accettato una risposta, ho il sospetto che la soluzione strdup non ci si aspetterebbe da noi perché non è parte di ANSI C. Sembra essere un bel questione soggettiva così ho non sono sicuro che quello che ho accettato sia effettivamente il migliore Grazie comunque per tutte le risposte.

risposta

4
char somestring[] = "Send money!\n"; 
char *copy; 
size_t copysize; 

copysize = strlen(somestring)+1; 
copy = (char *) malloc(copysize); 
if (copy == NULL) 
    bail("Oh noes!\n"); 

strncpy(copy, somestring, copysize); 
printf("%s", copy); 

differenze osservato in precedenza:

  • Risultato di malloc() devono essere controllati!
  • Compute e store la dimensione della memoria!
  • Utilizzare strncpy() perché strcpy() è cattivo. In questo esempio inventato non farà male, ma non prendere l'abitudine di usarlo.

EDIT:

A quelli pensando dovrei usare strdup() ... che funziona solo se si prende il punto di vista molto più stretta della domanda. Questo non è solo stupido, è che si affaccia una risposta ancora migliore:

char somestring[] = "Send money!\n"; 
char *copy = somestring; 
printf(copy); 

Se avete intenzione di essere ottusi, almeno essere bravo a farlo.

+3

+1 per l'uso di strncpy. Questa è la fonte di così tante falle nella sicurezza, non è divertente. –

+8

L'utilizzo di strncpy() è in modo peggiore rispetto all'utilizzo non corretto di strcpy(). Se usi strncpy(), sei * NOT * output con terminazione null (questo esempio è OK, ma non in generale). Inoltre, se si utilizzano buffer di dimensioni eccessive e sizeof (buffer) per il terzo parametro per strncpy(), si ha un mini-disastro delle prestazioni a portata di mano; strncpy() azzera zeriosamente i dati copiati su tutta la lunghezza. * SÌ * alla conoscenza della lunghezza delle stringhe di origine e di destinazione; se lo fai correttamente, usare strcpy() è sicuro e più sicuro dell'uso cieco di strncpy(). (Se c'è qualche aiuto, strncat() è molto, molto peggio di strncpy(), non usarlo mai!) –

+1

Jonathan, strlcpy() è molto più sano di mente. Lo uso ogni volta che è disponibile, ea volte porto una versione quando non lo è. Il Drepper è troppo cattivo. – dwc

6
char somestring[] = "Send money!\n"; 
char *copy = strdup(something); 

if (copy == NULL) { 
    // error 
} 

o semplicemente mettere questa logica in una funzione separata xstrdup:

char * xstrdup(const char *src) 
{ 
    char *copy = strdup(src); 

    if (copy == NULL) { 
     abort(); 
    } 

    return copy; 
} 
+5

Va notato che strdup() è non una parte di ANSI C. –

+1

dovrebbe essere: if (copy == NULL) { – hiena

+2

Se strdup() non esiste per la libreria C, allora dovresti scriverlo. Ciò significa che hai un singolo punto in cui può verificarsi un errore invece di centinaia. –

-2

Il modo più sicuro sarebbe usare strncpy anziché strcpy. Quella funzione prende un terzo argomento: la lunghezza della stringa da copiare. Questa soluzione non si estende oltre ANSI C, quindi funzionerà in tutti gli ambienti (mentre altri metodi possono funzionare solo con sistemi conformi a POSIX).

char somestring[] = "Send money!\n"; 
char *copy; 

copy = (char *) malloc(strlen(somestring)); 

strncpy(copy, somestring, strlen(somestring)); 
printf(copy); 
+0

+1 per strncpy; più di ogni altra cosa, questo rende questo codice più sicuro. Almeno nel caso di fallimento malloc, si segfault; strcpy() consente falle di sicurezza folle che sono difficili da trovare. –

+1

-1 per errore una tantum e danneggiamento della memoria –

+0

@McWafflestix: no, in questo caso, strncpy() viene utilizzato in modo errato e il risultato è un pasticcio. Come sottolinea Aaron Digulla, la chiamata a strncpy() richiede la lunghezza 'strlen (somestring) +1'; come è scritto, la copia è garantita non terminata in modo nulla. Printf() è pericoloso in generale - usando una stringa casuale in quanto il formato per printf() è sbagliato (puts() è probabilmente la scelta più vicina a quella sensata qui). (Immagina "Invia il 20% di denaro extra!" Invece!) –

3
  1. strlen + 1, per il \ 0 terminatore
  2. malloc potrebbe non riuscire; controllare sempre il valore di ritorno malloc
0

Il modo migliore per scrivere in modo più sicuro, se si fosse veramente interessati a una cosa del genere, sarebbe di scriverlo in Ada.

somestring : constant string := "Send money!"; 
declare 
    copy : constant string := somestring; 
begin 
    put_line (somestring); 
end; 

Stesso risultato, quindi quali sono le differenze?

  • Il tutto viene eseguito nello stack (senza riferimenti). La deallocazione è automatica e sicura.
  • Tutto è automaticly gamma-controllati in modo non c'è alcuna possibilità di buffer-overflow exploit
  • entrambe le stringhe sono costanti, quindi non c'è alcuna possibilità di avvitamento e comandate.
  • Sarà probabilmente il modo più veloce di rispetto alla C, non solo per la mancanza di allocazione dinamica, ma perché non c'è quella scansione extra attraverso la stringa richiesta da strlen().

Si noti che in Ada "stringa" non è un particolare costrutto dinamico. È la matrice di caratteri incorporata. Tuttavia, gli array Ada possono essere dimensionati in base alla dichiarazione dall'array che si assegna loro.

3

Ick ... strdup() utilizzare come tutti gli altri detto e scrivere voi stessi se si deve. Dal momento che si ha il tempo di pensare a questo ora ... controllare il 25 Most Dangerous Programming Errors at Mitre, quindi prendere in considerazione il motivo per cui la frase printf(copy) dovrebbe mai appaiono nel codice. Proprio qui con malloc(strlen(str)) in termini di assoluta cattiveria per non parlare del mal di testa di rintracciare perché causa un sacco di dolore quando la copia è qualcosa come "%s%n" ...

7

Non posso commentare le risposte sopra, ma oltre a controllare il codice ritorno e utilizzando strncpy, non si dovrebbe mai fare:

printf(string) 

Ma utilizzare:

printf("%s", string); 

ref: http://en.wikipedia.org/wiki/Format_string_attack

+2

+1 per foro di sicurezza imprevisto nel codice più comune –

1

Vorrei commentare le soluzioni precedenti ma non ho abbastanza rep. Utilizzando strncpy qui è così sbagliato come utilizzare strcpy (Poiché non v'è assolutamente alcun rischio di overflow). C'è una funzione chiamata memcpy in < string.h> ed è pensato proprio per questo. Non è solo molto più veloce, ma anche la funzione corretto da utilizzare per copiare le stringhe di lunghezza nota in serie C.

Dalla risposta accettata:

char somestring[] = "Send money!\n"; 
char *copy; 
size_t copysize; 

copysize = strlen(somestring)+1; 
copy = (char *) malloc(copysize); 
if (copy == NULL) 
    bail("Oh noes!\n"); 

memcpy(copy, somestring, copysize); /* You don't use str* functions for this! */ 
printf("%s", copy); 
+0

-1 per l'utilizzo di malloc() in una copia di stringa quando si dispone di strdup(). Non reinventare la ruota quando si dispone di una funzione di libreria. –

+0

@Aaron Come accennato in precedenza, strdup() non è ANSI, non esisterà su tutti i sistemi. Il punto di questa risposta può essere applicato quando scrivi la tua versione di strdup(). – Trent

1

modi per rendere il codice più sicuro (e più corretto).

  1. Non eseguire una copia non necessaria. Dall'esempio, non è apparentemente richiesto che sia effettivamente necessario copiare somestring. Puoi farlo direttamente.
  2. Se si deve fare una copia di una stringa, scrivere una funzione per farlo (o utilizzare strdup se lo avete). Quindi devi solo farlo in un posto.
  3. Se possibile, inizializzare il puntatore sulla copia immediatamente quando lo si dichiara.
  4. Ricordarsi di allocare spazio per il terminatore null.
  5. Ricordarsi di verificare il valore restituito da malloc.
  6. Ricordarsi di liberare la memoria di malloc.
  7. Non chiamare printf con una stringa di formato non attendibile. Utilizzare printf("%s", copy) o puts(copy).
  8. Utilizzare un linguaggio orientato agli oggetti con una classe stringa o qualsiasi lingua con supporto stringa incorporato per evitare la maggior parte di questi problemi.
1

ad aggiungere di più per le vie di Adrian McCarthy per rendere il codice più sicuro,

Utilizzare un analizzatore di codice statico, sono molto bravo a trovare questo tipo di errori