Does linux allow any system call to be made from signal handlers?

谁都会走 提交于 2019-11-26 14:37:22

问题


My understanding is that, in general, the behavior is undefined if you call a non-async signal safe function from a signal handler, but I've heard that linux allows you to call any system call safely. Is this true? Also, the only portable behavior for a SIGSEGV handler is to abort or exit, but I understand linux will actually resume execution if you return, true?


回答1:


I would believe that any real system call can be called from a signal handler. A true syscall has a number in <asm/unistd.h> (or <asm/unistd_64.h>).

some posix functions from section 2 of man pages are implemented thru a "multiplexing" syscall, so they are not "true syscalls" in my sense

A system call is an atomic operation from the point of view of the application; it is almost like a single machine instruction (from inside the application). See this answer.

If your question is: can a SIGSEGV handler change the faulty address mapping thru mprotect or mmap ? then I believe the answer is yes (at least on x86-64 & x86-32 architectures), as said here in a question you quoted, but I did not try. I've read that doing that is quite inefficient (SIGSEGV handling is not very fast, and mprotect or mmap is also a bit slow). In particular, mimicking this way Hurd/Mach external pagers might be inefficient.




回答2:


According to section 2 signal manual:

See signal(7) for a list of the async-signal-safe functions that can be safely called from inside a signal handler.

And section 7 signals manual lists the following functions and/or system calls along with a pretty clear description:

Async-signal-safe functions

   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()

I believe this information to be more reliable than something that we hear sometimes somewhere . So Linux does allow only some system calls but not all of them. So the answer to your question is simply — no.




回答3:


Yes and NO

Yes:

You can call any real/raw syscall inside a signal handler. The kernel has the responsibility to ensure it is safety(in the view of the kernel).

1) The kernel don't know the context of the userspace, or saying the kernel forget it intentionally after it saves the state to userspace when delivered signal. (NOTE: execution resuming is done by the user via a syscall with the help from the saved states, not really by the kernel, the kernel has already forgotten)

2) some thread lib is implemented via singles, so threads are already in "signal handler", but these threads can call any syscall.

NO:

But user space functions have their own purpose and side-effect. Some are not re-entrance safe, those functions can't be called from signal handler. man 7 signal will help you find out which are re-entrance safe.

Take example, you can call sys_futex() anywhere including signal handler, but if you use sys_futex() to implement a mutex, the sys_futex() inside signal handler may blocked for ever when the signal interrupts the critical section of the mutex.

Also, the only portable behavior for a SIGSEGV handler is to abort or exit, but I understand linux will actually resume execution if you return, true?

Yes, if you can't find out the reason. Some user may use SIGSEGV for their own map-when-demanded purpose(example, in JIT, you can translate the code in SIGSEGV signal handler and mmap the translated code to the memory and then return), they can call mmap() or mprotect() ...etc.



来源:https://stackoverflow.com/questions/11675040/does-linux-allow-any-system-call-to-be-made-from-signal-handlers

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!