2012-07-26 56 views
15

我的理解是,在一般情况下,如果你调用从信号处理非异步信号安全功能的行为是不确定的,但我听说Linux允许您安全地调用任何系统调用。这是真的?此外,SIGSEGV处理程序的唯一可移植行为是中止或退出,但我知道如果你返回true,linux实际上会恢复执行。Linux是否允许从信号处理程序进行任何系统调用?

+1

你从哪里听说过? – moooeeeep 2012-07-26 17:52:30

+2

特别是这个问题的答案:http://stackoverflow.com/questions/2663456/write-a-signal-handler-to-catch-sigsegv – 2012-07-26 17:53:23

+0

我希望你已经添加了术语“原始系统调用”的标题: - ) – 2017-09-20 07:30:54

回答

5

我相信,任何真正的系统调用可以从信号处理程序被调用。一个真正的系统调用在<asm/unistd.h>(或<asm/unistd_64.h>)中有一个数字。

从手册页第2部分POSIX功能通了“复用”的系统调用来实现,因此他们不是在我的感觉“真正的系统调用”

系统调用是从点原子操作申请视图;它几乎就像一个机器指令(来自应用程序内部)。见this answer

如果你的问题是:可以在SIGSEGV处理程序更改错误地址映射直通mprotectmmap那么我相信答案是(至少在x86-64 & x86-32体系结构),因为said here在你引用的问题,但我没有尝试。我读过,这样做是非常低效的(SIGSEGV处理不是非常快,而且mprotectmmap也有点慢)。特别是,模仿这种方式Hurd/Mach external pagers可能效率低下。

+0

系统调用是有点原子的,但它们可以将控制权返回给用户代码,无论它们是从哪里调用的,还是到信号处理程序中。正常的行为是信号处理程序做一些事情,然后返回,然后中断的系统调用返回EINTR。 (并且glibc可以再次调用它,我认为会发生什么。)如果您从信号处理程序内部进行系统调用,则我认为操作系统会将更多信号排队,直到完成。或者,如果您调用一个不在保证安全列表中的系统调用,可能会有些奇怪。 – 2014-12-03 14:54:27

+0

只有当我看到Linus自己写的in-tree文档时,我才会相信它! :-) – 2017-09-20 07:30:29

16

根据section 2 signal manual

查看信号(7)的可 可安全地从一个讯号处理器中被称为异步信号安全函数列表。

而且section 7 signals manual列出了以下功能和/或系统调用连同一个非常明确的说明:

异步信号安全功能

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只允许一些系统调用,但不是全部。所以你的问题的答案就是 - 不。

+1

虽然这似乎是posix而不是linux专用。我知道linux是(应该是)posix兼容,所以我认为这意味着至少这些功能是安全的,我想了解是否有任何以上和以上(尤其是mprotect),以及。 – 2012-07-26 18:03:38

+1

@ gct:这是Linux特定的手册页。这是查看源代码后可以得到的最准确的东西。如果你想通过源代码并进行更好的分析...去吧:) – 2012-07-26 18:31:33

+0

@gct:顺便说一句,有一个更好的方式来处理信号没有这个限制 - 你必须使用'epoll'与'signalfd'。然后你可以在处理程序中做任何你想做的事情,参见http://www.kernel.org/doc/man-pages/online/pages/man2/signalfd.2.html – 2012-07-26 18:49:34

6

YES和NO

是:

可以调用一个信号处理程序内的任何真正的/原始的系统调用。内核有责任确保它是安全的(在内核视图中)。

1)内核不知道用户空间的情况下,或者说在内核忘记它有意将其保存在传递信号给用户空间的状态后。 (注意:执行恢复是由用户通过系统调用在保存状态的帮助下完成的,而不是内核,内核已经忘记了)

2)某些线程库是通过单线程实现的,所以线程是已经在“信号处理程序”中,但这些线程可以调用任何系统调用。

NO:

但是用户空间的功能是有自己的目的和副作用。有些不是re-entrance safe,这些函数不能从信号处理程序调用。 man 7 signal将帮助您找出哪些重新进入安全。

采取例如,你可以调用sys_futex()任何地方,包括信号处理,但如果你使用sys_futex()实现互斥,信号处理函数中sys_futex()可以阻止永远当信号中断互斥的关键部分。

此外,对于SIGSEGV处理程序的唯一便携式的行为是中止或 退出,但我明白Linux将真正恢复执行,如果你 回报,真的吗?

是的,如果你找不到原因。某些用户可能会将SIGSEGV用于他们自己的map-when-requested目的(例如,在JIT中,您可以翻译SIGSEGV信号处理程序中的代码并将翻译后的代码mmap到内存然后返回),他们可以调用mmap()或mprotect ()...等。

+0

“您可以在信号处理程序中调用任何真实/原始系统调用”您是否有任何资源(例如内核文档,注释)来支持该声明? – 2017-09-20 07:03:54

相关问题