Подтвердить что ты не робот

Линукс разрешает любой системный вызов из обработчиков сигналов?

Я понимаю, что в целом поведение undefined, если вы вызываете функцию неасинхронного сигнала с помощью обработчика сигнала, но я слышал, что linux позволяет безопасно звонить на любой системный вызов. Это правда? Кроме того, единственным переносимым поведением для обработчика SIGSEGV является прервать или выйти, но я понимаю, что linux действительно возобновит выполнение, если вы вернетесь, true?

4b9b3361

Ответ 1

Я бы поверил, что любой реальный системный вызов можно вызвать из обработчика сигнала. Истинный syscall имеет число в <asm/unistd.h> (или <asm/unistd_64.h>).

некоторые функции posix из раздела 2 справочных страниц реализованы через "мультиплексирование" syscall, поэтому они не являются "истинными syscalls" в моем смысле

Системный вызов - это атомная операция с точки зрения приложения; это почти как отдельная машинная инструкция (изнутри приложения). См. этот ответ.

Если ваш вопрос: может ли обработчик SIGSEGV изменить неправильное сопоставление адресов через mprotect или mmap? то я считаю, что ответ да (по крайней мере, на архитектуре x86-64 и x86-32), поскольку сказал здесь в вопросе, который вы цитировали, но я не пробовал. Я читал, что это довольно неэффективно (обработка SIGSEGV не очень быстро, а mprotect или mmap также немного медленнее). В частности, имитируя этот способ, внешние пэды Hurd/Mach могут быть неэффективными.

Ответ 2

Согласно разделу 2 signal руководство:

См. сигнал (7) для списка функций, защищенных от асинхронного сигнала, которые могут быть безопасно вызван изнутри обработчика сигнала.

И раздел 7 signals руководство содержит следующие функции и/или системные вызовы, а также довольно четкое описание:

Асинхронные сигнальные функции

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

Я считаю, что эта информация более надежна, чем то, что мы иногда слышим где-то. Поэтому Linux разрешает только некоторые системные вызовы, но не все из них. Так что ответ на ваш вопрос просто - нет.

Ответ 3

Да и НЕТ

Да:

Вы можете вызвать любой реальный/необработанный syscall внутри обработчика сигнала. Ядро несет ответственность за обеспечение безопасности (с точки зрения ядра).

1) Ядро не знает контекста пользовательского пространства или говорит, что ядро ​​умышленно забывает его после того, как оно сохраняет состояние в пользовательском пространстве при подаче сигнала. (ПРИМЕЧАНИЕ: возобновление выполнения выполняется пользователем через syscall с помощью сохраненных состояний, а не на самом ядре, ядро ​​уже забыто)

2) некоторые потоки lib реализуются через синглы, поэтому потоки уже находятся в "обработчике сигналов", но эти потоки могут вызывать любой syscall.

NO:

Но функции пользовательского пространства имеют свои собственные цели и побочные эффекты. Некоторые из них не являются re-entry safe, эти функции нельзя вызывать из обработчика сигналов. man 7 signal поможет вам узнать, какие из них безопасны для повторного входа.

Например, вы можете вызывать sys_futex() где угодно, включая обработчик сигналов, но если вы используете sys_futex() для реализации мьютекса, внутренний обработчик сигнала sys_futex() может заблокироваться навсегда, когда сигнал прерывает критический раздел мьютекса.

Кроме того, единственным переносимым поведением для обработчика SIGSEGV является прерывание или exit, но я понимаю, что linux фактически возобновит выполнение, если вы return, true?

Да, если вы не можете узнать причину. Некоторые пользователи могут использовать SIGSEGV для своей собственной цели по карте (например, в JIT, вы можете перевести код в обработчике сигнала SIGSEGV и переместить код в память, а затем вернуться), они могут вызывать mmap() или mprotect()...и т.д.