glibc/NPTL/Linux强健互斥体中的竞争条件?

R..*_*R.. 16 c linux pthreads

在对2010年自动在Unix上崩溃时自动释放互斥锁的问题的评论中,jilles声称:

glibc强大的互斥体非常快,因为glibc采用危险的快捷方式.当内核将其标记为"将导致EOWNERDEAD"时,无法保证互斥锁仍然存在.如果互斥锁被破坏并且内存映射文件替换为内存映射文件恰好包含在正确位置的最后一个拥有线程的ID而最后一个拥有线程在写入锁定字之后终止(但在从其列表中完全删除互斥锁之前)拥有的互斥锁),文件已损坏.Solaris和will-be-FreeBSD9强大的互斥体速度较慢,因为它们不想冒这个风险.

我无法理解索赔,因为除非它被解锁(因此不在任何线程的强大列表中),否则销毁互斥锁​​是不合法的.我也找不到任何搜索这样的错误/问题的参考资料.索赔是否只是错误的?

我问的原因和我感兴趣的是,这与我自己实现的相同Linux robust-mutex原语的正确性有关.

R..*_*R.. 8

我想我找到了这场比赛,而且确实非常难看.它是这样的:

线程A保持了强大的互斥锁并将其解锁.基本程序是:

  1. 将它放在线程强健列表头的"挂起"槽中.
  2. 将其从当前线程持有的强健互斥锁的链接列表中删除.
  3. 解锁互斥锁.
  4. 清除线程强健列表头的"挂起"槽.

问题是在步骤3和4之间,同一进程中的另一个线程可以获取互斥锁,然后将其解锁,并且(正确地)认为自己是互斥锁的最终用户,销毁并释放/释放它.之后,如果进程中的任何线程创建了文件,设备或共享内存的共享映射,并且它恰好被分配了相同的地址,并且该位置的值碰巧匹配仍在步骤之间的线程的pid解锁3和4,你有一种情况,如果进程被终止,内核将通过设置它认为是互斥锁所有者id的32位整数的高位来破坏映射文件.

解决方案是在上面的步骤2和4之间对mmap/munmap进行全局锁定,与我对此问题的答案中描述的屏障问题的解决方案完全相同:

可以在Linux上实现正确的故障安全流程共享障碍吗?


jil*_*les 6

FreeBSD pthread开发人员David Xu对比赛的描述:http://lists.freebsd.org/pipermail/svn-src-user/2010-November/003668.html

我不认为比赛严格要求munmap/mmap周期.共享内存也可能被用于不同的用途.这是不常见但有效的.

正如该消息中所提到的,如果具有不同权限的线程访问常见的健壮互斥锁,则会发生更多"有趣".由于拥有的健壮互斥体列表的节点位于互斥锁本身中,因此具有低权限的线程可能会损坏高权限线程的列表.这可以很容易地被利用来使高权限线程崩溃,并且在极少数情况下这可能允许高权限线程的内存被破坏.显然,Linux强大的互斥锁仅供具有相同权限的线程使用.通过将强健列表完全放在线程内存而不是链表中,可以轻松避免这种情况.

  • 此外,假设您的程序可以恢复受保护对象的状态,`EOWNERDEAD`是您可以处理的条件.`ENOMEM`或类似物不是你可以处理的条件; 如果程序无法获得等待它的锁或块,则程序无法继续.请记住,可以从取消处理程序调用`pthread_mutex_lock`,其中互斥锁需要被锁定为下一级取消处理程序的不变量... (2认同)