2012-03-07 9 views
6

Per essere chiari, si tratta di un progetto piuttosto che di una domanda di implementazionePerché le chiamate di sistema restituiscono EFAULT invece di inviare un segfault?

Desidero conoscere la logica alla base del perché POSIX si comporta in questo modo. Le chiamate di sistema POSIX quando viene assegnata una posizione di memoria non valida restituiscono EFAULT anziché arrestare il programma userspace (inviando un sigsegv), il che rende il loro comportamento incoerente con le funzioni userspace.

Perché? Questo non nasconde solo bug di memoria? È un errore storico o c'è una buona ragione per questo?

+0

Anche a me un sigsegv/sigbus ha più senso. In questo momento sto giocando con 2 syscalls personalizzate che dovrebbero avere anche emulazioni di userspace (più lente). Non vedo perché l'attuale syscall e l'emulazione dovrebbero comportarsi in modo diverso se vengono passati buffer non validi. Persino POSIX sembra essere dell'opinione che gli utenti non debbano preoccuparsi se una funzione di sistema sia una funzione reale di syscall o di uno spazio utente. I miei correlati domanda: https: //stackoverflow.com/questions/44239545/generating-segfault-from-a-custom-syscall/44251112 – PSkocik

risposta

2

Perché chiamate di sistema vengono eseguite dal kernel, non dal programma utente --- quando si verifica la chiamata di sistema, il processo utente si ferma e attende per il kernel alla fine.

Il kernel stesso, naturalmente, non è permesso di seg guasto, quindi deve controllare manualmente tutte le aree di indirizzamento processo utente dà esso. Se uno di questi controlli fallisce, la chiamata di sistema fallisce con EFAULT. Quindi in questa situazione non si è verificato un errore di segmentazione --- è stato evitato dal kernel che verifica esplicitamente che tutti gli indirizzi siano validi. Quindi ha senso che nessun segnale viene inviato.

Inoltre, se un segnale è stato inviato a, non è possibile che il kernel possa allegare un contatore di programma significativo al segnale, il processo utente non viene effettivamente eseguito quando la chiamata di sistema è in esecuzione. Ciò significa che non ci sarebbe modo per il processo dell'utente di produrre una diagnostica decente, riavviare l'istruzione fallita, ecc.

Per riassumere: per lo più storico, ma esiste una logica effettiva del ragionamento. Come EINTR, questo non lo rende meno irritante da affrontare.

+1

Che cosa si intende per 'collegare un contatore di programma significativo' al segnale? Vuoi dire che non saprebbe dove riprendere dopo che il gestore del segnale dell'utente è stato eseguito? Non sarebbe solo dopo la chiamata di sistema? –

+0

Sì, ignora il bit sulla ripresa --- pensandoci un po 'di più, questo non è realmente rilevante. (Perché se il kernel sta simulando un errore di seg, può facilmente falsare lo stato del registro.) Penso che il problema principale qui sia: il kernel non ti sta mandando un errore di seg perché _no l'errore di segmento in realtà si è verificato_. –

2

Beh, cosa vorresti vuole ciò accada. Una chiamata di sistema è una richiesta al sistema. Se chiedi: "quando parte il traghetto per Munchen?" vorresti che il programma si arresti in modo anomalo o che ottenga return = -1 con errno = ENOHARBOR? Se chiedi al sistema di mettere la tua auto nella tua borsetta, ti piacerebbe avere la borsa distrutta o un ritorno di -1 con errno impostato su EBAGTOOSMALL?

C'è un dettaglio tecnico: prima o dopo syscalls, argomenti da/utente/sistema -land devono essere convertiti (copiati) entrando/lasciando la chiamata di sistema. Principalmente per motivi di sicurezza, il sistema è molto riluttante a scrivere nello spazio dell'utente. (Linux ha una funzione copy_to_user_space per questo (e viceversa), che controlla le credenziali prima di eseguendo la copia effettiva)

+1

Ho già detto cosa avrebbe più senso nella domanda: inviare un segnale segfault all'app. –

+0

Ah forse, ho frainteso la tua domanda.C'è un problema * tecnico * copyfromuser(), copytouser() (nel caso Linux) vengono eseguiti dalla modalità kernel, quindi il controllo deve essere eseguito "manualmente" dal kernel, non c'è SEGVE possibile, il kernel * potrebbe * eseguire questa copia per te. Quindi, formalmente, non è una violazione di segmentazione (sarebbe * dovrebbe * essere, se eseguita dallo userspace) Inoltre: dalla vista del processo utente, un syscall è solo una funzione con un valore di ritorno. I segnali dovrebbero rappresentare un evento asincrono. – wildplasser

Problemi correlati