Warning: Can only detect less than 5000 characters
发表于3月22日,2021 20:52 UTC(Mon)由Cyberax(✭支持者✭,#52523)[链接]
多年来我发现奶牛很糟糕,最好避免它们。
如果你'重新打破API兼容性,*然后你可能只是告诉人们使用vfork()或posix_spawn(),因为那些已经成熟并且很好地理解的接口,并且后者甚至是便携式的。顺便提一下,在研究这一评论时,我偶然发现了来自克隆(2):&gt的TIDBIT;与Glibc包装器相比,原始克隆()系统调用>接受空值作为堆栈参数(克隆3()同样允许> cl_args.stack为null)。在这种情况下,孩子使用A>父母' s堆栈的副本。 (编写编写的语义保证>当孩子&gt时,孩子会在>过程修改堆栈时单独的堆叠副本。)在这种情况下,对于正确而GT;操作,不应指定CLONE_VM选项。 (如果是>孩子因使用> clone_vm标志而分享父级' s内存,那么没有发生编写的复制复制和混乱和gt;很可能会导致。)听起来像是这样的声音打电话的乐趣。现在我想知道是否有任何开发者已经决定他们"需要"绕过Glibc并在我的任何系统上拉这类暗示......(我是一个SRE,所以如果它在生产中闯入,那么我的问题是我的问题。 "幸运的是,"大多数虫子I'已经看到的往往比这更高,但它仍然有点可怕,即内核将让你做那样的事情。 *这显然不会在内核和#39;不打破用户空间的粉丝奉献,但是假装一会儿。
发表于3月23日,2021年10:08 UTC(Tue)由Pbonzini(✭支持者✭,#60935)[链接]
posix_spawn()不是单个系统调用(技术上,Fork()和vfork()是克隆(2)周围的包装器,但至少后者是单个系统调用)。
肯定,但在(荒谬)假设我们'重新消除牛的假设,内核可能需要延伸与类似于Fork + Exec的能力的接口,并且该接口的POSIX标准名称是posix_spawn。
发表于3月23日,2021 23:00 UTC(Tue)由Cyberax(✭支持者✭,#52523)[链接]
显然,人们不喜欢posix_spawn。也许我们会展现一个完整的更换,允许创建暂停的过程,调整其属性(使用基于文件句柄的API),然后恢复它。但我觉得我们实际上的实际上是一种基于IO_URE的API,它可以使用BPF来实现这一点。
我们_almost_已经有了一个API:Ptrace。轻微的问题是ptrace真的很糟糕。它的建议也太糟糕了,添加了基于Saner处理的版本。
几年前我们讨论了这篇论文,这争辩说,Fork()基本上是错误的原始原始,可以构建OS流程管理:https://lwn.net/arlicle/785430/
发表于3月23日,2021年14:17 UTC(TUE)通过ABATTERS(✭支持者✭,#6932)[链接]
我最近考虑过vfork(),但在遇到有关它的警告太多时最终会反对它。例如,请参阅Posix_spawn()的Vfork()的glibc历史:glibc< = 2.23:posix_spawn()使用vfork()如果设置了posix_spawn_usevfork,或者如果在IT Exec(3)之前没有预期的清除,则S请求的文件。但是,这种vfork()的实现是许多错误的来源。 Linux Glibc> = 2.24:glibc提交9ff72da471a509a8c19791fe4697910469791046979105C19791046979110POSIX_SPAWN()从vfork()交换到克隆(克隆_vm | clone_vfork),它使用单独的堆栈为孩子。这修复了许多vfork() - 相关的错误("可能的父clobber到期堆栈溢出"),使其可以通过默认和忽略posix_spawn_usevfork来实现。最近的非Linux Glibc Glibc提交CCFB2964726512F6669FEA99A43AFA714E2E6A80 POSIX_SPAWN_USEVFORK被忽略,始终使用常规叉(),由于难点vfork()在没有Linux特定的克隆()语义的情况下工作。请注意,使用CLONE(CLONE_VM | CLONE_VFORK)安全地需要阻止所有信号,包括NPTL内部信号。但是Glibc包装器Don' t让您阻止NPTL-Internal Signal,使得在Glibc之外更难以做到。查看所有血腥细节的Glibc实现。
Naïve非内核开发人员视角:这似乎_intually_就像问题的错误解决方案一样。孩子仍然可以访问该页面,所以肯定应该被标记为访问该页面,只要它确实有一个引用,而不是假装它并没有访问该页面只是因为它是munmap' d。只是因为页面已经是Munmap' d并不意味着这个过程可以' t从中读取,为什么页表表删除了?但是,我假设它是一个非常好的原因,为什么这样做了。有人可以清理我的误解吗?
>孩子仍然可以访问该页面,所以肯定应该被标记为访问该页面,只要它确实有一个引用,而不是假装它并没有访问该页面只是因为它是munmap' d。我不确定我理解你的观点,但是通过提交来阻止这个问题。当孩子想要采取额外的参考(对于VMSPLICE()),它会获得副本而不是与父级共享的页面。之后,孩子的页面表和管道点持有的引用点对此新副本,以及对父级的访问丢失。 >只是因为页面已经是Munmap' d并不意味着这个过程可以' t从中读取,为什么页表表删除了?这只是Munmap()的语义 - 它 - 它必须调整VMA树和ZAP Page表条目,以便在那里不再表示Munmapped Range。然后,如果该过程尝试读取/写入该区域内的地址,IT SEGFAULTS。我们可以' t留下页表条目,仅是因为另一个引用存在。从管道读取并通过这些页面表。
作为非内核开发人员,我'好奇:回想起来,这头牛是根本错误的吗?为什么不治疗VMSplice参考"参考资料"在Munmap之后,可以使用户空间过程无法进入的页面,同时仍然保持内核' s引用?
原则是,但是你有其他问题。例如,MMAP可用于在固定地址处分配内存。难以判断任何给定的地址是否合适(因为其他页面等可能是在路上),但如果您只是刚刚映射它,那么在同一地址和大小的后续MMAP中,它将真的很奇怪。用户佩勤可能会假设它不需要检查该案例中mmap的错误代码(或者它可能没有合适的恢复代码,并且只需呼叫中止(3))。因此,现在您的解决方案需要在隐藏页面顶部堆叠堆叠新页面,或重新定位隐藏页面,其中任何一个都是不动的。甚至没有提到您需要教导VMSplice以与Pages Do相同的方式跟踪VMSplice以跟踪每个进程的引用,而没有用户空间页面映射中实际存在的页面。这些都是解决的问题,这是一个安全问题,因此解决了难题不是修复的理想形式。在简单的牛休息中投掷是一种更直接的解决方案(但是,作为故事暗示,可能会有一些并发症,他们未能解释)。
>如果您只是刚刚Munmapped它,对于同一地址和大小的后续MMAP,它将非常奇怪。用户佩勤可能会假设它不需要检查该案例中mmap的错误代码(或者它可能没有合适的恢复代码,并且只需呼叫中止(3))。这让我想起了一个古老的错误:大约十年前,Firefox(使用Jemalloc的代码)会尝试做一个大的对齐分配,如" p = mmap(null,size * 2); Munmap(P); p = mmap(round_up(p,对齐),大小);"即,使用第一个MMAP + MUNMAP在地址空间中发现足够大的孔,然后在该孔中的正确对齐地址处分配。如果第二个MMAP and#39; t返回请求的地址,必须有一个竞争条件与另一个线程分配在同一个孔中,因此它会循环并再次尝试,并希望下次更好运气。这正常工作好,直到它在内核上运行了随机MMAP的安全功能,并完全忽略了地址参数(从技术上都是可以的,因为它被定义为只是一个提示,而不是要求),因此代码被困在无限循环。这是固定的年龄,但它确实可以合理于某些用户空间代码可能仍然同样不明智的假设。
PTE必须消失,因为那个' s被指定为dummap()是什么。此外,它的事实' s t
......