Da C a Cyclone
Considera il seguente programma C che dovrebbe stampare la sottostringa
della stringa passata come argomento, dopo la x:
#include<stdio.h>
#include<string.h>
char * foo(char *s){
char c[10];
strcpy(c,s);
// questa è una funzione della librerira che cerc aun
// carattere in una string
return strchr(c,'x');
}
int main (int argc, char ** argv){
char * c = foo(argv[1]);
c++;
printf("sottostringa %s",c); return (*c);
}
Se compilo con gcc compila senza warning:
gcc -o ptr_c.exe ptr_c.c
Ma non funziona tanto bene:
ptr_c.exe pippoxcc
sottostringa a
Posso anche avere buffer overflow e non accorgermi oppure accorgermi:
$ ./ptr_c.exe pixxpxffsssaddsdssdfsfdsfds
17334 [main] ptr_c 1360 _cygtls::handle_exceptions: Error while dumping state
(probably corrupted stack)
Segmentation fault (core dumped)
Per prima cosa devo usare il malloc
char *c = malloc(sizeof(char)*10);
adesso funziona tranne se ho più di 10 caratteri:
<< QUI SOTTO LINUX FUNZIONA, SOTTO WINDOWS NO>>
oppure se non ho una x:
./ptr_corr ISOID
Segmentation fault
oppure se non ho alcun argomento dopo la riga di comando.
./ptr_corr
Segmentation fault
in cyclone
Nella prima traduzione semplicemente uso i fat pointer per s e per argv:
Sostituisco * con ?:
#include<string.h>
#include<stdio.h>
char * foo(char ?s){
char * c = malloc(sizeof(char)*10);
strcpy(c,s);
return strchr(c,'x');
}
int main (int argc, char ?? argv){
char * c = foo(argv[1]);
c++;
printf("sottostringa %s",c);
return (*c);
}
Se compilo ottengo
cyclone ptr.cyc
ptr.cyc:5: actual argument has type
char @{1024U}@nozeroterm`foo
but formal has type
char ?`foo
char @{1024U}@nozeroterm`foo and char ?`foo are not compatible.
(not both zero terminated)
ptr.cyc:6: actual argument has type
char @{1024U}@nozeroterm`foo
but formal has type
const char ?
`H and `foo are not compatible.
ptr.cyc:6: returns value of type const char ? but requires char *
@true and @true are not compatible.
Il problema è che la funzione strchr restuituisce un const:
nessun problema, posso modificare e mettere const:
const char * foo(char ?s){
... const char * c = foo(argv[1]);
quando però eseguo ho un errore: sto cercando di convertire in
char* un char?
Cioè un puntatore fat in uno non fat.
metto char ? foo al posto di char* fooo
const char ? foo(char ?s){
... const char ? c = foo(argv[1]);
Adesso funziona tranne in alcuni casi (però non
darà mai
segmentation fault).
Nel caso in cui non abbia un 'x' nella string, la strchr restituisce
null: devo mettere il controllo a null.
O in questo modo utilizzando il puntatore not null:
const char @ c = foo(argv[1]);
o con if(c!=NULL) ...
Se chiamo il comando con più di 10 caratteri?
Per finire posso costruire il buffer di dimensione giusta (vedi
ptr_c_numlets.cyc):
char ? c = malloc(sizeof(char)*numelts(s));
Uso di strumenti per l'analisi statica:
flaw finder
[garganti@pcelvinia cyclone]$ flawfinder ptr_c_1.c
Flawfinder version 1.26, (C) 2001-2004 David A. Wheeler.
Number of dangerous functions in C/C++ ruleset: 158
Examining ptr_c_1.c
ptr_c_1.c:6: [4] (buffer) strcpy:
Does not check for buffer overflows when copying to destination.
Consider using strncpy or strlcpy (warning, strncpy is easily misused).
ptr_c_1.c:5: [2] (buffer) char:
Statically-sized arrays can be overflowed. Perform bounds checking,
use functions that limit length, or ensure that the size is larger than
the maximum possible length.
Hits = 2
Lines analyzed = 18 in 0.54 seconds (454 lines/second)
Physical Source Lines of Code (SLOC) = 18
Hits@level = [0] 0 [1] 0 [2] 1 [3] 0 [4] 1 [5] 0
Hits@level+ = [0+] 2 [1+] 2 [2+] 2 [3+] 1 [4+] 1 [5+] 0
Hits/KSLOC@level+ = [0+] 111.111 [1+] 111.111 [2+] 111.111 [3+] 55.5556 [4+] 55.5556 [5+] 0
Minimum risk level = 1
Not every hit is necessarily a security vulnerability.
There may be other security vulnerabilities; review your code!