PDA

View Full Version : [C] Zona di memoria "sicura"


anx721
13-01-2005, 17:27
Salve,

sapete se c'è un modo per porre delle variaili di un programma in una zona di memoria 'sicura', in cui non ci possano essere accessi illegali, ad esempio evitando che si acceda a quella zona al di fuori di una funzione?

Il mio obiettivo è registrare una funzione che viene richiamata se si genera un segmentation fault; in C ciò è possibile registrando una funzione come handler per il segnale di segmentation fault; quando l'errore si verifica, la funzione viene eseguita, ad esempio tale funzione puo semplicemente stampare una stringa del tipo:

"C'è stato un errore di segmentation fault".

Il prolema è pero che se il segmentation fault si è verificato, alcuni dati del programma possono essere stati alterati, quindi la stessa stringa può essere stata danneggiata...il mio scopo era allora far in modo che non si potesse accedere all'aria di memoria che corrisponde a quella stringa, al di fuori della funzione handler, in modo che quella variabile non venga di sicuro alterata.

Come si puo fare?

Ciao e grazie.

cionci
14-01-2005, 07:51
This function changes the access protection on a region of committed pages in the virtual address space of the calling process.

BOOL VirtualProtect(
LPVOID lpAddress,
DWORD dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
);
Parameters
lpAddress
[in] Pointer to the base address of the region of pages whose access protection attributes are to be changed.

All pages in the specified region must be allocated in a single call to the VirtualAlloc function.

The pages cannot span adjacent regions that were allocated by separate calls to VirtualAlloc.
dwSize
[in] Specifies the size, in bytes, of the region whose access protection attributes are to be changed.

The region of affected pages includes all pages containing one or more bytes in the range from the lpAddress parameter to lpAddress+dwSize. This means that a 2-byte range straddling a page boundary causes the protection attributes of both pages to be changed.
flNewProtect
[in] Specifies the new access protection.

You can specify any one of the following flags, along with the PAGE_GUARD and PAGE_NOCACHE protection modifier flags, as necessary.
Value Description
PAGE_READONLY Enables read access to the committed region of pages.

An attempt to write to the committed region results in an access violation.

If the system differentiates between read-only access and execute access, an attempt to execute code in the committed region results in an access violation.
PAGE_EXECUTE Enables execute access to the committed region of pages.

An attempt to read or write to the committed region results in an access violation.
PAGE_EXECUTE_READ Enables execute and read access to the committed region of pages.

An attempt to write to the committed region results in an access violation.
PAGE_GUARD Pages in the region become guard pages.

An attempt to access a guard page causes the system to raise a STATUS_GUARD_PAGE exception and turn off the guard page status. Guard pages thus act as a one-shot access alarm.

The PAGE_GUARD flag is a page protection modifier. An application uses it with one of the other page protection flags, with one exception: it cannot be used with PAGE_NOACCESS.

When an access attempt leads the system to turn off guard page status, the underlying page protection takes over.

If a guard page exception occurs during a system service, the service typically returns a failure status indicator.
PAGE_NOACCESS Disables all access to the committed region of pages.

An attempt to read from, write to, or execute in the committed region results in an access violation exception, called a general protection (GP) fault.
PAGE_NOCACHE Allows no caching of the committed regions of pages.

The hardware attributes for the physical memory should be specified as no cache. This is not recommended for general use. It is useful for device drivers; for example, mapping a video frame buffer with no caching.

This flag is a page protection modifier and is valid when used with a page protection other than PAGE_NOACCESS.

ilsensine
14-01-2005, 08:22
Originariamente inviato da anx721
Il prolema è pero che se il segmentation fault si è verificato, alcuni dati del programma possono essere stati alterati, quindi la stessa stringa può essere stata danneggiata...il mio scopo era allora far in modo che non si potesse accedere all'aria di memoria che corrisponde a quella stringa, al di fuori della funzione handler, in modo che quella variabile non venga di sicuro alterata.

Come si puo fare?

Utilizzando una zona di memoria a sola lettura. Una stringa const char * dovrebbe essere posta in .rodata, ma non è garantito (credo stia al buon senso del compilatore). Puoi allocare un pò di memoria tramite mmap privato, inizializzarla, e poi renderla a sola lettura tramite mprotect. E' un pò il modo illustrato da Cionci per sistemi win32.
La man page di mprotect mostra un esempio tramite malloc+mprotect (ti consiglio comunque di usare mmap al posto della malloc).

cionci
14-01-2005, 15:00
Ah...cavolo non avevo pensato se era per Windows o per Linux :doh:
Anzi credo che fosse proprio per Linux...visto il "Segmentation Fault"...

anx721
14-01-2005, 15:35
Grazie,

ho capito l'esempio di mrotect+malloc, ma non ho capito a che serve mmap e come dovrei usarla al posto di malloc

anx721
14-01-2005, 15:36
Originariamente inviato da cionci
Ah...cavolo non avevo pensato se era per Windows o per Linux :doh:
Anzi credo che fosse proprio per Linux...visto il "Segmentation Fault"...

in realtà se riuscissi a farla per entrambi sarebbe meglio
;)

ilsensine
14-01-2005, 15:47
Originariamente inviato da anx721
Grazie,

ho capito l'esempio di mrotect+malloc, ma non ho capito a che serve mmap e come dovrei usarla al posto di malloc
mmap serve a "mappare qualcosa" (file, dispositivo, memoria fisica, memoria "anonima"...) nel tuo spazio di indirizzamento.
A te serve memoria "anonima".
Questo esempio è analogo a quello che trovi nella manpage, ma fa uso di mmap:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>

int main(void)
{
void *map;
char c;
char *p;
map = mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if(map==MAP_FAILED) {
perror("mmap");
return -1;
}
p = map;
c = p[666];
fprintf(stderr, "Read 1 ok c=%d\n", c);
p[666] = 42;
fprintf(stderr, "Write 1 ok\n");
if(mprotect(p, 1024, PROT_READ)) {
perror("mprotect");
return -1;
}
c = p[666];
fprintf(stderr, "Read 2 ok c=%d\n", c);
p[666] = 42;
fprintf(stderr, "Write 2 ok\n");
munmap(map, 1024);
return 0;
}

Dovresti ottenere un segfault sulla seconda write.

anx721
14-01-2005, 16:19
Grazie per l'esempio,

volevo pero capire una cosa; leggendo la documentazione mi sembrava di capire che mprotect deve ricevere come indirizzo iniziale un indirizzo che coincide con l'inizio di una pagina di memoria (difatti nell'esempio della manpage si allineava il valore di p con il primo indirizzo multiplo di 4096 se la pagina è di 4096 bytes). mmap restituisce deirettamente un puntatore all'inizio di una pagina o anche in questo caso bisogna eseguire quell'allineamento? E poi perche conviene usare mmap al posto di malloc?

Grazie e ciao.

ilsensine
14-01-2005, 16:52
mmap lavora solo per multipli di pagina. Anche se ho chiesto 1024 byte, alloca almeno una pagina. La memoria ovviamente è già allineata. Lo stesso per mprotect.

E poi perche conviene usare mmap al posto di malloc?

E' solo con la mmap che il funzionamento è garantito. Da man mprotect:

POSIX.1b says that mprotect can be used only on regions of memory obtained from mmap(2).

malloc può allocare memoria con syscall diverse da mmap (ad es. brk). Il fatto che mprotect funzioni anche con memoria ottenuta tramite brk è incidentale, e non richiesto dallo standard posix.