假设在一个取消点(例如read )阻塞一个应用程序,并且接收一个信号并调用一个信号处理程序。Glibc/NPTL通过启用syscall期间的异步取消来实现取消点,因此据我所知,异步取消将在信号处理程序的整个期间保持有效。当然,这是非常错误的,因为有许多函数不是异步取消安全的,但是需要安全地从信号处理程序调用。
这给我留下了两个问题:
,
?
编辑:--我几乎说服了自己,任何线程,如果是pthread_cancel的潜在目标,都必须确保不能从线程上下文中的信号处理程序调用作为取消点的函数:
一方面,任何可以在可能被取消的线程中调用并使用任何异步取消-不安全函数的信号处理程序都必须在调用任何作为取消点的函数之前禁用取消。这是因为,从被信号中断的代码的角度来看,任何这样的取消都等同于异步取消。另一方面,信号处理程序不能禁用取消,除非调用信号处理程序时运行的代码只使用异步信号安全函数,因为pthread_setcancelstate不是异步信号安全的。
发布于 2011-04-20 04:18:32
要回答我自己问题的前半部分: glibc确实显示了我预测的行为。在取消点运行时在异步取消下运行的信号处理程序。要看到这种效果,只需创建一个线程,该线程调用将永久阻塞(或长期阻塞)的取消点,等待片刻,发送信号,再次等待,然后取消并加入它。信号处理程序应该对一些易失性变量进行修改,使之清楚地表明,在异步终止之前,它运行的时间是不可预测的。
至于POSIX是否允许这种行为,我仍然不能百分之百肯定。POSIX指出:
每当一个线程启用了可取消性并以该线程为目标发出取消请求,然后该线程调用任何作为取消点的函数(例如pthread_testcancel()或read()),则应在该函数返回之前对取消请求进行操作。如果线程启用了可取消性,并且在取消点挂起线程时以线程为目标提出取消请求,则将唤醒线程并对取消请求进行操作。在以下情况下,未指定是否对取消请求采取了行动,或取消请求是否仍处于未决状态,以及线程是否恢复正常执行:
。
在取消请求被执行之前。
据推测,执行信号处理程序不是被“挂起”的情况,所以我倾向于将glibc的行为解释为不符合条件。
发布于 2014-01-09 22:54:12
富有,
我在做Alex为glibc做的AC安全文档评审时遇到了这个问题。
我认为GNU C库实现(基于nptl的)并没有中断。虽然异步取消确实是围绕阻塞系统启用的(这需要作为取消点),但这种行为仍然应该是一致的。
同样,启用异步取消后的信号将导致启用异步取消后运行的信号处理程序。同样,在该处理程序中执行不属于异步取消安全性的任何操作都是危险的。
同样正确的是,如果另一个线程以正在运行的信号线程为目标调用pthread_cancel,则将立即对此取消操作。这仍然符合POSIX的“函数返回之前”的措辞(在本例中,read没有返回,目标线程在信号处理程序中)。
该信号的问题是,它导致线程处于两种同时状态,两种状态都是永远处于取消点,并执行指令。如果取消请求到达,我认为它是符合立即采取行动的。虽然奥斯汀集团可能会澄清。
glibc实现的问题是,它需要所有信号处理程序,由要取消的线程执行。只调用异步取消安全函数。这是一个不明显的要求,不是源于标准,但并不使它不符合。
解决信号处理程序脆弱性的潜在解决方案:
SIGCANCEL不为阻塞系统启用异步取消,而是启用取消implementation.
虽然张贴在堆栈溢出是有趣的,我不知道其他人读这个,可以回答您的问题所需的细节。
作为POSIX标准讨论的一部分,我认为任何进一步的讨论都应该发生在Austin邮件列表上,或者应该发生在libc上,作为glibc实现讨论的一部分。
发布于 2011-03-23 19:25:28
我认为你要找的是两件事的结合:
一些系统调用可能被信号中断,从而导致返回EINTR错误。这是正常的行为,但我从来不清楚,如果,例如,您正处于一个read的中间--没有从流中读取任何内容会发生什么?也许有人可以对此发表评论,以帮助澄清。
不应该中断的系统调用(就像您担心的那样)应该封装在对sigprocmask (或线程中的pthread_sigmask )的调用中,以防止它们被中断。一旦您重新启用信号,任何在阻塞时接收到的信号都将被传送.但是,与中断一样,如果阻塞时间太长,则可能会由于覆盖(多次接收相同的信号,计数为一个挂起的信号)而错过一些中断。
https://stackoverflow.com/questions/5408303
复制相似问题