2012-03-07 9 views
6

Para ser claros, este es un diseño en lugar de una pregunta de implementación¿Por qué las llamadas al sistema devuelven EFAULT en lugar de enviar una segfault?

Quiero saber la razón de por qué POSIX se comporta de esta manera. Las llamadas al sistema POSIX cuando se le da una ubicación de memoria no válida devuelven EFAULT en lugar de bloquear el programa de espacio de usuario (mediante el envío de un sigsegv), lo que hace que su comportamiento sea inconsistente con las funciones de espacio de usuario.

¿Por qué? ¿Esto no solo oculta los errores de memoria? ¿Es un error histórico o hay una buena razón para ello?

+0

Para mí, un sigsegv/sigbus tiene más sentido también. En este momento estoy jugando con 2 syscalls personalizadas que también deberían tener emulaciones de espacio de usuario (más lentas). No veo por qué el syscall real y la emulación deberían comportarse de manera diferente si se pasan los búferes no válidos. Incluso POSIX parece ser de la opinión de que los usuarios no deberían tener que preocuparse de si una función del sistema es una función real de syscall o un espacio de usuario. Mi pregunta relacionada: https: //stackoverflow.com/questions/44239545/generating-segfault-from-a-custom-syscall/44251112 – PSkocik

Respuesta

2

Porque las llamadas al sistema son ejecutadas por el kernel, no por el programa del usuario --- cuando se produce la llamada al sistema, el proceso del usuario se detiene y espera a que el kernel finalice.

El kernel mismo, por supuesto, no puede segmentar el error, por lo que debe verificar manualmente todas las áreas de dirección que el proceso de usuario le da. Si una de estas comprobaciones falla, la llamada del sistema falla con EFAULT. Por lo tanto, en esta situación no se está produciendo un error de segmentación; el kernel lo ha evitado de forma explícita para asegurarse de que todas las direcciones sean válidas. Por lo tanto, tiene sentido que no se envíe ninguna señal.

Además, si una señal fuera enviada, no habría forma de que el kernel pueda conectar un contador de programa significativo a la señal, el proceso de usuario no se está ejecutando cuando se está ejecutando la llamada al sistema. Esto significa que no habría forma de que el proceso del usuario produzca diagnósticos decentes, reinicie la instrucción fallida, etc.

En resumen: mayormente histórico, pero hay una lógica real para el razonamiento. Como EINTR, esto no lo hace menos irritante de tratar.

+1

¿A qué te refieres con "adjuntar un contador de programa significativo" a la señal? ¿Quiere decir que no sabría dónde reanudar después de que se ejecutó el controlador de señal del usuario? ¿No sería eso justo después de la llamada al sistema? –

+0

Sí, ignore el tema sobre la reanudación --- pensando un poco más, eso no es realmente relevante. (Porque si el kernel falsifica un fallo de seg, puede simular fácilmente el estado de registro.) Creo que el problema principal aquí es: el kernel no te está enviando un fallo seg porque _no se ha producido realmente ningún fallo_. –

2

Bueno, ¿qué quieres quiere pasar. Una llamada al sistema es una solicitud al sistema. Si pregunta: "¿cuándo se va el ferry a Munchen?" ¿Le gustaría que el programa se cuelgue, o que obtenga return = -1 con errno = ENOHARBOR? Si le pide al sistema que coloque su auto en su bolso, ¿le gustaría que se destruya su bolso, o un retorno de -1 con errno configurado en EBAGTOOSMALL?

Hay un detalle técnico: antes o después de las llamadas de sistema, los argumentos hacia/desde el usuario/sistema -y deben convertirse (copiarse) al entrar/salir de la llamada al sistema. Sobre todo por razones de seguridad, el sistema es muy reacio a escribir en el espacio del usuario. (Linux tiene una función copy_to_user_space para esto (y viceversa), que comprueba las credenciales antes de haciendo la copia real)

+1

Ya digo lo que tendría más sentido en la pregunta: enviar una señal segfault a la aplicación. –

+0

Ah, tal vez, he entendido mal tu pregunta.Hay un problema * técnico * que copyfromuser(), copytouser() (en el caso de Linux) se ejecuta desde kernel-mode, por lo que el kernel debe realizar la verificación "manualmente", no hay SEGVE posible, el kernel * podría * realizar esta copia por usted. Así que, formalmente, no es una violación de segmentación (* * sería *, si se realiza desde el espacio de usuario) También: desde la vista del proceso de usuario, una llamada de sistema es solo una función con un valor de retorno. Se supone que las señales representan algún evento asincrónico. – wildplasser

Cuestiones relacionadas