亚马逊AWS大规模重启服务器背后的故事

分类:首页 > 官方博客 > 交流随笔     来源:港讯互联官方博客     发布时间:2014-10-13

9月23日,XEN官方来了个帽子戏法,一口气爆出3个漏洞。随后,就有关于亚马逊AWS大规模重启服务器的消息爆出。这次重启事件不论是影响到的产品、还是持续的时间都是史无前例的,整个修复周期持续5天,从9月25日下午7点到9月30日下午5点,影响的产品包括EC2、RDS、ElastiCache、RedShift,其中EC2最为严重,大约占到AWS EC2总量的10%.由于是发生在美国,所以国内这块的报道较少,很多同学可能还不知道是什么漏洞,让亚马逊做如此大范围的重启操作。下面我们一块看看这三兄弟到底是啥来头。

这次的三个漏洞,危害有哪些?

1、CVE-2014-7154这个可以说是三兄弟中的老大,为何?因为它在关键位置有人,因为它老爹是dom0.dom0在XEN架构中的地位非常重要,它包含控制硬件的驱动和控制虚拟机的工具集。所以它会影响到整个物理机上面所有的虚拟机,这样的漏洞是最恐怖的,波及范围广,修补起来又需要重启,那就得业务中断啊,还有,如果重启起不来咋办?? 

2、CVE-2014-7155这个可以排行老二,客户机可以利用该漏洞加载自己的IDT或GDT,可能导致虚拟机的宕机,还可以获取root权限。看到这里我们也不要太慌张,因为这里不是虚拟机逃逸,而是获取虚拟机的root权限。危害也不小,“黑阔”又多了一个提权利器。

3、CVE-2014-7156与上述那俩老大哥比起来,就个漏洞危害就要差一些了。利用该漏洞,可能导致虚拟机的宕机,但宕机也不是小事,不容小觑,只是生不逢时。

神马是XEN?

在进行技术分析之前,我们先了解一下关于XEN的背景知识。

VMware大家都很熟悉了,无论是WorkStation还是企业级的ESX,XEN就是类似于ESX的一个软件,不过是开源的(类似的还有KVM)。现在KVM已经是Linux官方加入到内核中的虚拟化技术。

XEN最早由剑桥大学开发,现在被Citrix收购,亚马逊的AWS就是基于XEN技术的。

通过下图我们来了解下XEN技术架构:

bf7507c1-30b3-40de-8583-bf8d1f13376a.jpg

从上面可以看出,XEN hypervisor直接运行在硬件之上,负责处理CPU、内存、中断等。它是运行完bootloader之后第一个运行的程序。在hypervisor之上允许虚拟机,在XEN里面,一个虚拟机实例被称为domain或者guest.其中,domain0是一个特殊的domain,它包含所有控制硬件的驱动,同时包含控制管理虚拟机的工具集。

除了domain0之外,其它的虚拟机就是我们熟悉的guest,大致分为两种类型:Paravirtualization(PV)半虚拟化 和 Full Virtualization(HVM)全虚拟化。

PV是由XEN引入的,后来被其它虚拟化平台采用。半虚拟化是一种高效、轻量的虚拟化技术,它不需要物理机CPU含有虚拟化扩展,但却需要一个Xen-PV-enabled内核和PV驱动,说白了就是需要修改虚机系统的内核,好在Linux、BSD、OpenSolaris等提供了该内核,但是Windows就不行了,因为只有微软可以修改它的内核。

HVM使用了物理机CPU的虚拟化扩展来虚拟出虚拟机。该技术需要Intel VT或者AMD-V硬件扩展。Xen使用Qemu来仿真PC硬件,包括BIOS、IDE硬盘控制器、VGA、USB控制器、网卡等等。由于使用虚拟机硬件扩展来提高仿真性能,所以HVM不需要修改内核,因此其上可以运行Windows系统。

技术揭秘

现在我们大致了解了这三漏洞有啥危害了,下面我们跟着官方的漏洞通告和补丁文件,来具体分析下这些漏洞。

1、CVE-2014-7154

CVE-2014-7154说的是在HVMOP_track_dirty_vram里面存在竟态条件,HVMOP_track_dirty_vram是一个用来控制脏显存跟踪设置的函数。下面是官方给出的补丁:

p2m_type_t t;- struct sh_dirty_vram *dirty_vram = d->arch.hvm_domain.dirty_vram;+ struct sh_dirty_vram *dirty_vram;struct p2m_domain *p2m = p2m_get_hostp2m(d);

if ( end_pfn < begin_pfn || end_pfn > p2m->max_mapped_pfn + 1 )

@@ -3495,6 +3495,8 @@ int shadow_track_dirty_vram(struct domai p2m_lock(p2m_get_hostp2m(d));paging_lock(d);

+ dirty_vram = d->arch.hvm_domain.dirty_vram;+ if ( dirty_vram && (!nr ||

从补丁中可以看出,在没有打补丁的代码里,系统在获取paging_lock之前,已经获取到了dirty_vram的值。这里有一个潜在的问题,两个并发的hypercall会尝试同时释放dirty_vram,那么两者中,第二个尝试进行释放的是一个野指针。另外,两个并发的hypercall也可能会尝试同时创建一个新的dirty_vram结构体,那么最先创建的那块内存会泄漏,因为第二个dirty_vram创建之后,两个指针都指向新的dirty_vram结构体。

所以修补起来也很简单,就是将获取d->arch.hvm_domain.dirty_vram的值放到获取了paging_lock之后。

2、CVE-2014-7155 CVE-2014-7155讲的是在x86的HLT、LGDT、LIDT、LMSW指令模拟时没有做特权检查,这些指令都是用来加载全局描述附表、中断描述符表或者局部描述符表等。恶意的客户机程序可以安装自己的IDT(中断描述符表),这些恶意行为会导致客户机宕机,或者进行提权。

case 0xf4: /* hlt */ + generate_exception_if(!mode_ring0(), EXC_GP, 0);ctxt->retire.flags.hlt = 1;break;

@@ -3710,6 +3711,7 @@ x86_emulate(break;case 2: /* lgdt */ case 3: /* lidt */ + generate_exception_if(!mode_ring0(), EXC_GP, 0);generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);fail_if(ops->write_segment == NULL);memset(&reg, 0, sizeof(reg));@@ -3738,6 +3740,7 @@ x86_emulate(case 6: /* lmsw */ fail_if(ops->read_cr == NULL);fail_if(ops->write_cr == NULL);+ generate_exception_if(!mode_ring0(), EXC_GP, 0);if ( (rc = ops->read_cr(0, &cr0, ctxt)) )

goto done;

从补丁中可以看出,系统通过在模拟htl、lgdt、lidt、lmsw的时候,增加了generate_exception_if()宏来解决该问题。该宏对运行在非ring0模式下的htl等指令,会产生EXC_GP异常。下面是generate_exception_if的宏定义:

#define generate_exception_if(p, e, ec) \({ if ( (p) ) { \ fail_if(ops->inject_hw_exception == NULL); \ rc = ops->inject_hw_exception(e, ec, ctxt) ? : X86EMUL_EXCEPTION; \ goto done; \ } \ })

 

从generate_exception_if(!mode_ring0(), EXC_GP, 0)

可以看出,对运行在ring0模式的指令不做任何操作,对运行在非ring0模式的指令,执行了检查。首先看是否定义了inject_hw_exception函数,如果没有定义,则ops->injdect_hw_exception == NULL的结果为真,根据fail_if的宏定义可以发现直接产生X86EMUL_UNHANDLEABLE:

#define fail_if(p) \ do { \ rc = (p) ? X86EMUL_UNHANDLEABLE : X86EMUL_OKAY; \ if ( rc ) goto done; \ } while (0)

如果在ops中定义了inject_hw_excption,则调用hvmemul_inject_hw_exceptio()函数来设置该异常的相关信息:

static int hvmemul_inject_hw_exception(uint8_t vector,int32_t error_code,struct x86_emulate_ctxt *ctxt)

{ struct hvm_emulate_ctxt *hvmemul_ctxt = container_of(ctxt, struct hvm_emulate_ctxt, ctxt);

hvmemul_ctxt->exn_pending = 1;hvmemul_ctxt->exn_vector = vector;hvmemul_ctxt->exn_error_code = error_code;hvmemul_ctxt->exn_insn_len = 0;

return X86EMUL_OKAY;}

通过查看宏定义,发现X86EMUL_OKAY的值为0:

/* Completed successfully. State modified appropriately. */ #define X86EMUL_OKAY 0 /* Unhandleable access or emulation. No state modified. */ #define X86EMUL_UNHANDLEABLE 1 /* Exception raised and requires delivery. */ #define X86EMUL_EXCEPTION 2

所以当inject_hw_exception不为NULL的时候,generate_exception_if在调用hvmemul_inject_hw_exception设置完相应的异常信息之后,产生X86EMUL_EXCEPTION异常。从上面的宏定义可以看出,不论是X86EMUL_UNHANDLEABLE异常还是X86EMUL_EXCEPTION异常,都会导致指令不执行。

3、CVE-2014-7156 CVE-2014-7156讲的是在x86中模拟软中断的时候,没有做特权检查,恶意的HVM客户机上面的代码能够使客户机宕机。

补丁说明只允许在实模式中进行软中断模拟,所以补丁也很简单,检测到在非实模式下模拟软中断的时候就退出:

case 0xcd: /* int imm8 */ src.val = insn_fetch_type(uint8_t);swint:+ fail_if(!in_realmode(ctxt, ops)); /* XSA-106 */ fail_if(ops->inject_sw_interrupt == NULL)

总结

其实我们看看3个补丁,发现貌似没做啥啊,只是换了换代码的位置,或加了一个函数或者宏。这说明XEN其实已经有解决问题的方案,只不过在某些指令的处理上,没有考虑到所有的使用场景,因此漏掉了相应的检查。那是不是其它指令在某些场景下还会有类似的问题呢?嘿嘿,我只能说漏洞时时有,这阵子特别多,所以我们多关注关注XEN的官方漏洞通告页面就知道了。

再看看IaaS云老大亚马逊AWS,不得不说他们的响应速度很快,对安全也重视,没有侥幸心理,该补的补,该重启的重启,重视安全的态度由此可见。但话说回来,出发点虽好,但是有没有更好的处理方式呢,既可以修补漏洞又可以不重启服务器的?

必须有!UCloud的内核团队这方面有很深入的研究:内核热补丁。通过该技术可以给运行中的Linux服务器打上内核补丁,既可以解决存在的问题,最重要的是不需要重启服务器。这项技术在UCloud已经广泛使用,已经免重启修复过十几个内核BUG.

来源:www.ip110.com      发布时间:2014-10-13

港讯互联,专业的香港空间香港服务器服务商。本文版权所有,转载请注明出处。

共有条评论

参与评论

验证码:      发言请文明用语并遵守相关规定,评论内容会在15分钟之后显示。

最新评论

相关阅读 评论 返回顶部