systemcall - syscall linux
¿Linux permite que se realicen llamadas al sistema desde los manejadores de señales? (3)
Según el manual de signal
sección 2 :
Consulte la señal (7) para obtener una lista de las funciones seguras para señales asíncronas que se pueden llamar de forma segura desde el interior de un controlador de señales.
Y el manual de signals
de la sección 7 enumera las siguientes funciones y / o llamadas al sistema junto con una descripción bastante clara:
Funciones asíncronas seguras de señal
A signal handler function must be very careful, since processing elsewhere may
be interrupted at some arbitrary point in the execution of the program. POSIX
has the concept of "safe function". If a signal interrupts the execution of
an unsafe function, and handler calls an unsafe function, then the behavior of
the program is undefined.
POSIX.1-2004 (also known as POSIX.1-2001 Technical Corrigendum 2) requires an
implementation to guarantee that the following functions can be safely called
inside a signal handler:
_Exit()
_exit()
abort()
accept()
access()
aio_error()
aio_return()
aio_suspend()
alarm()
bind()
cfgetispeed()
cfgetospeed()
cfsetispeed()
cfsetospeed()
chdir()
chmod()
chown()
clock_gettime()
close()
connect()
creat()
dup()
dup2()
execle()
execve()
fchmod()
fchown()
fcntl()
fdatasync()
fork()
fpathconf()
fstat()
fsync()
ftruncate()
getegid()
geteuid()
getgid()
getgroups()
getpeername()
getpgrp()
getpid()
getppid()
getsockname()
getsockopt()
getuid()
kill()
link()
listen()
lseek()
lstat()
mkdir()
mkfifo()
open()
pathconf()
pause()
pipe()
poll()
posix_trace_event()
pselect()
raise()
read()
readlink()
recv()
recvfrom()
recvmsg()
rename()
rmdir()
select()
sem_post()
send()
sendmsg()
sendto()
setgid()
setpgid()
setsid()
setsockopt()
setuid()
shutdown()
sigaction()
sigaddset()
sigdelset()
sigemptyset()
sigfillset()
sigismember()
signal()
sigpause()
sigpending()
sigprocmask()
sigqueue()
sigset()
sigsuspend()
sleep()
sockatmark()
socket()
socketpair()
stat()
symlink()
sysconf()
tcdrain()
tcflow()
tcflush()
tcgetattr()
tcgetpgrp()
tcsendbreak()
tcsetattr()
tcsetpgrp()
time()
timer_getoverrun()
timer_gettime()
timer_settime()
times()
umask()
uname()
unlink()
utime()
wait()
waitpid()
write()
POSIX.1-2008 removes fpathconf(), pathconf(), and sysconf() from the above
list, and adds the following functions:
execl()
execv()
faccessat()
fchmodat()
fchownat()
fexecve()
fstatat()
futimens()
linkat()
mkdirat()
mkfifoat()
mknod()
mknodat()
openat()
readlinkat()
renameat()
symlinkat()
unlinkat()
utimensat()
utimes()
Creo que esta información es más confiable que algo que escuchamos a veces en algún lugar. Entonces, Linux solo permite algunas llamadas al sistema pero no todas. Así que la respuesta a su pregunta es simplemente - no.
Mi entendimiento es que, en general, el comportamiento no está definido si llama a una función de seguridad de señal no asíncrona desde un controlador de señal, pero he escuchado que Linux le permite llamar a cualquier llamada del sistema de forma segura. ¿Es esto cierto? Además, el único comportamiento portátil para un controlador SIGSEGV es abortar o salir, pero entiendo que Linux reanudará la ejecución si regresa, ¿verdad?
Si y no
Sí:
Puede llamar a cualquier syscall real / raw dentro de un manejador de señales. El kernel tiene la responsabilidad de garantizar que sea seguro (en la vista del kernel).
1) El kernel no conoce el contexto del espacio de usuario, o diciendo que el kernel se olvida intencionalmente después de guardar el estado en el espacio de usuario cuando se entrega la señal. (NOTA: la reanudación de la ejecución es realizada por el usuario a través de un syscall con la ayuda de los estados guardados, no realmente por el kernel, el kernel ya se ha olvidado)
2) algunos hilos lib se implementan a través de singles, por lo que los hilos ya están en "manejador de señal", pero estos hilos pueden llamar a cualquier syscall.
NO:
Pero las funciones del espacio de usuario tienen su propio propósito y efecto secundario. Algunas no son seguras de reingreso , esas funciones no pueden ser llamadas desde el manejador de señales. man 7 signal
te ayudará a descubrir cuáles son seguras de reingreso.
Por ejemplo, puede llamar a sys_futex()
cualquier lugar, incluido el manejador de señales, pero si usa sys_futex()
para implementar un mutex, el manejador de señales interno sys_futex()
puede bloquearse para siempre cuando la señal interrumpa la sección crítica del mutex.
Además, el único comportamiento portátil para un controlador SIGSEGV es abortar o salir, pero entiendo que Linux reanudará la ejecución si regresa, ¿verdad?
Sí, si no puedes averiguar la razón. Algunos usuarios pueden usar SIGSEGV para su propio propósito de map-when-demand (por ejemplo, en JIT, puede traducir el código en el manejador de señales SIGSEGV y guardar el código traducido en la memoria y luego regresar), pueden llamar mmap () o mprotect () ... etc.
Yo creo que cualquier llamada al sistema real puede ser llamada desde un manejador de señales. Un verdadero syscall tiene un número en <asm/unistd.h>
(o <asm/unistd_64.h>
).
algunas funciones de posix de la sección 2 de las páginas de manual se implementan a través de un sistema de "multiplexación", por lo que en mi sentido no son "juegos de verdad".
Una llamada al sistema es una operación atómica desde el punto de vista de la aplicación; Es casi como una sola instrucción de máquina (desde dentro de la aplicación). Ver esta respuesta
Si su pregunta es: ¿ puede un manejador SIGSEGV
cambiar la asignación de direcciones defectuosas a través de mprotect
o mmap
? entonces creo que la respuesta es sí (al menos en las arquitecturas x86-64 y x86-32), como se dijo aquí en una pregunta que usted citó, pero no lo intenté. He leído que hacer eso es bastante ineficiente (el manejo de SIGSEGV
no es muy rápido, y mprotect
o mmap
también es un poco lento). En particular, imitar de esta manera los buscapersonas externos de Hurd / Mach puede ser ineficiente.