GNU/Linux >> Linux Esercitazione >  >> Linux

Come scrivere un gestore di segnale per catturare SIGSEGV?

Puoi recuperare da SIGSEGV su Linux. Inoltre puoi recuperare dagli errori di segmentazione su Windows (vedrai un'eccezione strutturata invece di un segnale). Ma lo standard POSIX non garantisce il recupero, quindi il tuo codice sarà molto non portabile.

Dai un'occhiata a libsigsegv.


Quando il tuo gestore di segnale ritorna (supponendo che non chiami exit o longjmp o qualcosa che gli impedisce di tornare effettivamente), il codice continuerà nel punto in cui si è verificato il segnale, rieseguendo la stessa istruzione. Dato che a questo punto la protezione della memoria non è stata modificata, lancerà semplicemente di nuovo il segnale e tornerai nel tuo gestore di segnale in un ciclo infinito.

Quindi per farlo funzionare, devi chiamare mprotect nel gestore del segnale. Sfortunatamente, come osserva Steven Schansker, mprotect non è asincrono, quindi non puoi chiamarlo in sicurezza dal gestore del segnale. Quindi, per quanto riguarda POSIX, sei fottuto.

Fortunatamente sulla maggior parte delle implementazioni (tutte le moderne varianti UNIX e Linux per quanto ne so), mprotect è una chiamata di sistema, quindi è sicuro chiamare dall'interno di un gestore di segnale, quindi puoi fare la maggior parte di ciò che desideri. Il problema è che se vuoi ripristinare le protezioni dopo la lettura, dovrai farlo nel programma principale dopo la lettura.

Un'altra possibilità è fare qualcosa con il terzo argomento del gestore del segnale, che punta a una struttura specifica del sistema operativo e dell'arco che contiene informazioni su dove si è verificato il segnale. Su Linux, questo è un ucontext struttura, che contiene informazioni specifiche della macchina sull'indirizzo $PC e altri contenuti del registro in cui si è verificato il segnale. Se lo modifichi, cambi dove tornerà il gestore del segnale, quindi puoi cambiare $PC in modo che sia subito dopo l'istruzione di errore in modo che non venga rieseguito dopo il ritorno del gestore. Questo è molto difficile da correggere (e anche non portatile).

modifica

Il ucontext la struttura è definita in <ucontext.h> . All'interno del ucontext il campo uc_mcontext contiene il contesto della macchina e all'interno di quello , l'array gregs contiene il contesto generale del registro. Quindi nel tuo gestore di segnale:

ucontext *u = (ucontext *)unused;
unsigned char *pc = (unsigned char *)u->uc_mcontext.gregs[REG_RIP];

ti darà il pc dove si è verificata l'eccezione. Puoi leggerlo per capire quale istruzione era difettosa e fare qualcosa di diverso.

Per quanto riguarda la portabilità di chiamare mprotect nel gestore del segnale, qualsiasi sistema che segua la specifica SVID o la specifica BSD4 dovrebbe essere sicuro:consentono di chiamare qualsiasi chiamata di sistema (qualsiasi cosa nella sezione 2 del manuale) in un segnale gestore.


Sei caduto nella trappola che fanno tutte le persone quando provano per la prima volta a gestire i segnali. La trappola? Pensare di poter effettivamente fare qualsiasi cosa utile con gestori di segnale. Da un gestore di segnale, puoi chiamare solo chiamate di libreria asincrone e rientranti.

Consulta questo avviso CERT sul perché e un elenco delle funzioni POSIX che sono sicure.

Nota che printf(), che stai già chiamando, non è in quella lista.

Né mprotect. Non sei autorizzato a chiamarlo da un gestore di segnale. Potrebbe lavoro, ma posso prometterti che incontrerai problemi lungo la strada. Fai molta attenzione con i gestori di segnali, sono difficili da correggere!

MODIFICA

Dato che al momento sono già un coglione della portabilità, ti farò notare che non dovresti nemmeno scrivere su variabili condivise (cioè globali) senza prendere le dovute precauzioni.


Linux
  1. Come risolvere:impossibile scrivere nella partizione Ext3 o Ext4

  2. Come scrivere testo sull'immagine usando il comando Linux

  3. Quanto è grande il buffer del tubo?

  4. Come scrivere uno script di avvio per Systemd?

  5. Come segnalare la fine dell'ingresso Stdin?

Come installare Signal Messenger su Ubuntu 20.04

Come scrivere uno script di shell in Ubuntu

Come installare l'app di messaggistica Signal su Ubuntu 20.04

Come scrivere ed eseguire un programma C in Linux

Come installare Signal Messaging su Ubuntu 20.04

Come scrivere su una webcam virtuale in Linux?