虚拟映射的内核栈

这篇文章有些老了,2016年6月的;照例贴出文章翻译自lwn.net。内核栈可以说是在linux设计的一个薄弱点:它小到内核开发者必须不断考虑把啥放到栈里才能防止溢出。可是这些溢出经常发生,甚至在没有试图强制制造错误的攻击者时也会发生,并且,在Jann Horn最近(2016年)说明的,攻击者想要制造栈溢出是有原因的。当溢出发生时,内核甚至都不能有效检查到,能做的也很少。在内核的生命周期中,栈很少有改变,不过一些最近的工作有着使内核栈变得更加健壮的潜力。

当前的内核栈的样子

每一个进程陷入到内核代码中运行(对于进程的用户态内核态我在这里有一些论述)都会有自己的一个小栈;在当前内核,32系统的内核栈是8KB,64位系统的内核栈是16KB,位于内核的线性映射区,因此也就是物理连续的;这个物理连续的要求,在内存逐渐变得碎片化之后本身就成文问题,因为找到两个或四个物理连续的页面已经变得很困难了。直接映射的内存同样使溢出检查页不再可能(防溢出页就是在栈后的无访问权限页,我有写用户态栈如何被侦测到溢出以及内核栈怎么才能侦测溢出),因为增加溢出检查页将会浪费一个真实的内存页。

然后就导致,没有什么立刻就能指示内核栈溢出的信号。栈增加过大的就会覆盖下面(说下面是因为在大多数架构中栈向下增长)的区域,无论其中存有什么信息。有内核开发选项允许在内核栈放一个canaries,可以通过追踪栈的使用来侦测溢出。但是如果在工作环境中侦测到栈溢出,一般都是溢出实际发生了,并且未知量的破坏都已经造成。

更为有趣的是,这里还有一个很有争议的数据结构-thread_info,放在栈底区域。因此如果内核栈溢出了,thread_info这个提供了几乎所有内核知道的关于这个进程的信息的入口,将会最先被覆盖。不必说,这就使栈溢出对于攻击者来说更加有趣了;很难知道说栈底后的内存李会放着什么,但是thread_info结构却是一个广为所知的。

毫不不令人惊讶的是,内核开发者们肯定会很努力的避免栈溢出。在栈上alloc(一般都是自动变量的形式),都是被仔细检查的,并且作为一般规矩性的,递归是不允许的。但是惊喜总是以一系列的形式袭来,从一个没注意的变量申请到一个未提前算好深度的调用链。存储子系统,一个文件系统,存储技术和网络代码可以堆砌到任意深度的地方,更是这些问题的重灾区。这一系列的惊喜直接导致3.15release内核把64位内核栈扩到了16KB,限制依旧在;并且由于不是一个栈供所有进程使用,因此任何增加其大小的举动都会被放大很多倍。

防止栈溢出在一段时间内依旧是内核开发者需要面对的挑战,但是内核更好的应对栈溢出的发生也是应该考虑的。做这件事的关键,就像在Andy Lutomirski的虚拟映射内核栈补丁组看到的,已经转移到内核栈是如何被映射的了。

虚拟映射栈

几乎所有内核直接访问的内存都是通过直接映射范围内的地址访问的。这个范围是一大段直接线性映射到物理内存的地址,这就会看起来好像内核是在物理内存地址上工作。在一个64位系统,所有内存都通过这种方式映射到内核;32位系统没有能力映射全部,于是会更复杂一点。

Linux是一个虚拟内存系统,内核也是通过虚拟内存访问内存,即便是在直接映射范围内。刚巧内核预留了另一个地址范围的内存来映射虚拟内存,这个区域vmalloc()调用时所申请的,被称作vmalloc范围。这一区域的内存分配是不连续的。过去这个区域被用来获取大块虚拟连续但实际不必连续的内存。

内核栈的物理连续是几乎没有什么必要的,因此原则上讲他们可以作为独立的页来申请,并映射到vmalloc区域。这样做可以消除内核中最大的连续物理内存的应用场合,恩,算是最大的之一;使系统在内存变碎片化后更加健壮。这样还可以使栈防溢出机制生效而不浪费内存(还是用户态栈如何被侦测到溢出的问题),仅仅是增加一条页表,就可以使内核在栈溢出即立刻感知。Andy的补丁就是这样做的:他从vmalloc区申请内核栈,当内核栈溢出,他优雅的增加了溢出处理,打出一条提示,不会oops,然后溢出的进程就被杀掉了。

这个补丁组相当简单,大部分工作在于处理肮脏的不同架构的细节。看起来是对内核一次非常显著的提升,在代码审查中得到大量正面评价,也有一些尚待解决的小问题。

不太好的影响

这其中一个非常重要的问题就是性能表现,从vmalloc区分配内存,Andy说,使clone()创建进程花了1.5us。一些工作对进程创建的开销很敏感,将会受到此影响,于是linus的回复就不怎么令人惊讶了:这个问题需要在合代码前解决。Andy认为大部分开销可以通过使vmalloc()更快来解决(vmalloc从来没有被认真的优化过),linus建议保持一个小的per-cpu的缓存作为与分配的栈。他已经说的很明白了:想要在合并代码之前把性能的退化解决掉。

另外有一个潜在的开销,没有被测过的开销:TLB miss问题。直接映射的区域使用巨页映射,因此整个内核(包含代码、数据、栈)可以装到一条TLB里。整个vmalloc区却不是,使用单页映射创建窗口到内存中。由于用内核栈是普遍的,如果这些栈都是用vmalloc,那么可能TLB miss的增加就会成真了。

还有 21% 的精彩内容
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
支付 ¥1.00 继续阅读
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355