麒麟操作系统内核同其他操作系统内核的相似性分析
Copyright (c) 2006 Dancefire (dancefire#gmail).
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".
作者:Dancefire (dancefire # gmail dot com )
( PDF格式及分析所用脚本程序下载连接:http://www.dancefire.org/file/kernel_similarity_analysis_1.0.zip )
原始链接:http://www.dancefire.org/article/Kernel_Similarity_Analysis.html
一、引言
麒麟操作系统是由国防科技大学、中软公司、联想公司、浪潮公司和民族恒星公司五家单位合作研制的服务器操作系统。按照麒麟官方的说法:
“Kylin服务器操作系统是国家863计划的重大研究成果,拥有完全自主版权的内核,与Linux在应用上二进制兼容,并支持64位,是中国独立研发成功的、具有完全自主知识产权的服务器操作系统。”[1]
--- 来自麒麟官方网站 http://www.kylin.org.cn/news.htm和
863计划官方网站[2] http://www.863.org.cn/863_105/indust/indust_news/200409160008.html
“银河麒麟操作系统是针对未来的主流网络服务和高性能计算服务的需求,参照国际主流标准,参考Darwin、FreeBSD、Linux和其它商用操作系统,借鉴UNIX操作系统和微内核操作系统的设计思想,设计并实现具有自主版权的、可支持多种CPU芯片和多种计算机体系结构的、具有高性能、高可用性与高安全性的、并与Linux应用和设备驱动二进制兼容的中文服务器操作系统,”
摘自麒麟操作系统2.0.21内自带的帮助文档
近日,有不少人对麒麟操作系统宣称的“完全自主版权”和“中国独立研发成功”这两个核心问题产生了质疑。随着麒麟2.0.14和2.0.21系统可以通过麒麟的官方网站下载后( http://www.kylin.org.cn/download.htm ),这种质疑的声音越来越大。麒麟除内核以外的应用大部分都来自自由组织GNU的代码,这些代码并不属于“中国独立研发”,而且他们的版权也不属于麒麟操作系统的开发者。更有甚者,有人开始通过反汇编麒麟操作系统内核发现和美国的FreeBSD开放源代码操作系统非常相似。随后又有人成功的用FreeBSD的内核启动了麒麟操作系统。按照麒麟官方的介绍,麒麟具有Linux的二进制兼容的能力,可是丝毫没有提及与FreeBSD的兼容性,使得麒麟内核与FreeBSD的关系变得比较引人注目。在官方介绍中的简简单单的“参考”是无法解释这种相似程度的。
在强烈的关注声中,麒麟开发人员在2006年2月16日,给出了一个说明,《关于银河麒麟操作系统的说明》[3],发布在 http://www.kylin.org.cn/download.htm 。其中提到了和FreeBSD的关系:
“课题组通过评测和分析,认为当时正在研发中的FreeBSD 5.0 具有比Unix SVR4.2 更好的发展势头,特别是SMPng 项目的开展,为FreeBSD 5.0 支持SMP 对称多处理器系统奠定了良好的基础,因此银河麒麟操作系统的系统服务层从SVR4.2 升级到当时正在研发中的FreeBSD 5.0。”
声明发出后一定程度上得到了大家谅解,可是虽然提及和FreeBSD的关系,却又十分隐晦,既没有明确的对官方网站新闻中的报道失实承认错误,没有明确阐述麒麟的操作系统是否具有“完全知识产权”以及是否是“中国独立研发”,甚至也没有对官方页面上的事实报道进行修正。而且,既然说明使用了FreeBSD 5.0的代码,却又说仅限于系统服务层,而丝毫未提及所占比例。这依旧让人们对这个获得863计划软件重大专项的资助的操作系统到底有多少创新产生一个大大的疑问。
为了调查清楚麒麟操作系统内核自主创新的百分比,以及与其它操作系统之间的关系,我将麒麟操作系统内核与FreeBSD、NetBSD、OpenBSD、Linux和Solaris的内核进行了可执行代码的相似度分析。
在整个过程中,我将尽量保持客观的原则进行分析。由于麒麟操作系统属于封闭源代码系统,因此在无法获得内核源代码的情况下,我将只进行二进制可执行代码文件的相似度分析。由于可执行代码受编译环境、内存分布情况以及模块的变动的影响很大,因此,会产生即使采用同一套代码,却产生很低的相似度情况。但是,对操作系统内核这种大型软件系统来说,却不会因为不同的代码而产生很高的相似度的情况。因此,我们将这次对二进制可执行代码分析所得的相似度作为相似度的下限。换句话说,真实的相似度应该会高于此次分析结果,但是由于分析方法的局限性,无法取得上限。
二、可执行文件的相似度比较
二进制可执行文件的相似度分析一直是一个难题。大家都知道,即使是同一份源代码,使用同一个编译器,可用不同的编译参数进行编译后,代码也会产生极大的差异。
当发生有人因为盗用别人的源代码而产生的侵权后,如果不能够将二者的源代码拿出进行比较的话,判断是否抄袭非常困难。因此,一直以来或多或少,总会有人无所顾忌的将开放源代码的软件拿来加入到自己的软件中,或者干脆就是在那些源代码的基础上稍加修改和更换了版权信息就宣称是自己研发的。因为他们知道,只要不把自己的源代码公诸于众,那么抄袭就很难判定。
下面我就详细说一下我采用的分析方法。
2.1 ELF可执行文件相似度分析方法
这次分析起始,我就碰到了一些难题。如果对二进制可执行文件进行基于字节的相似性分析,即使匹配上某些字节,也很难说明两段代码的相似性,另外匹配也很容易受到各种噪音的干扰而产生很低的相似度,可是噪音却无法被去除。
因此,使最小比较单元具有明确的语义和合理的过滤噪音是我首先要解决的问题。
2.1.1 反汇编
二进制文件的比较难以确定最小单元语义的根本问题在于二进制文件是以字节为单位,然而每个字节却没有特定的含义。你很难说89 e5和83 EC 89中的89相同说明什么,在这个例子中,前者的89 e5是i386的一条指令,而后者的89则是一个立即数,所以他们相同实际上什么都不说明。
针对这次分析,由于都是可执行代码,而且都采用了ELF的文件格式。由于这个特点,我首先将所有操作系统的内核通过objdump反汇编成汇编代码。这样做有一个直接的好处,就是每一行都是一条汇编语句,而每一条汇编语句又是一个程序不可分的最小逻辑单元。这样,接下来的分析就可以基于行来进行相似性的分析,因为每出现一行相同就说明有一个最小的逻辑单元相同,如果出现连续的行相似,那么就说明有连续的代码段相似。相同的行越多两个内核就越相似。
并且经过反汇编后,就避免了因文件内包含的其他无关信息,如字符串、资源文件、数据文件等,对分析结果产生的影响。
这个方法依旧无法避免因编译参数差异所造成的相似度下降的影响。虽然如此,但是我很幸运,从这次分析的结果看,依旧得到了不低的相似度。
2.1.2 过滤噪音
噪音的出现有很多原因,可能是内存分布不同、代码的增删导致的偏移地址的变化,对相同含义的常量而数值却不同等等。这些值的差异,可能会造成不同的执行结果,但是却对两段代码的相似性比较影响不大。请看下列两个代码段:
c043e9e8 <freebsd4_sigcode>: c04431d8 <freebsd4_sigcode>:
freebsd4_sigcode(): freebsd4_sigcode():
c043e9e8: call *0x10(%esp) c04431d8: call *0x10(%esp)
c043e9ec: lea 0x14(%esp),%eax c04431dc: lea 0x14(%esp),%eax
c043e9f0: push %eax c04431e0: push %eax
c043e9f1: testl $0x20000,0x54(%eax) c04431e1: testl $0x20000,0x54(%eax)
c043e9f8: jne c043e9fd <freebsd4_sigcode+0x15> c04431e8: jne c04431ed <freebsd4_sigcode+0x15>
c043e9fa: movl 0x14(%eax),%gs c04431ea: movw 0x14(%eax),%gs
c043e9fd: mov $0x158,%eax c04431ed: mov $0x158,%eax
c043ea02: push %eax c04431f2: push %eax
c043ea03: int $0x80 c04431f3: int $0x80
c043ea05: jmp c043ea05 <freebsd4_sigcode+0x1d> c04431f5: jmp c04431f5 <freebsd4_sigcode+0x1d>
c043ea07: nop c04431f7: nop
左边的代码是来自FreeBSD 5.3内核的,而右边的代码来自麒麟2.0.21/18的内核。通过人的分析,我们可以得出这两段代码实际上是相同的。可是对于计算机程序比较的时候,就不尽然。
请注意上述的有颜色的数字。用蓝色表示的代码地址[4]、绿色表示的偏移地址、红色表示的立即数、深蓝色表示的函数偏移地址和粉色表示的函数地址,这些数字的不同,就造成了代码比较时候的失败。上述13行代码,如果就这样比较的话,只有函数名一行可以匹配。因此虽然是相同的代码,却只有7.7%的相似度。下面我们就来去除这些干扰。
首先,我们将代码行地址、函数跳转地址和函数偏移地址去除。代码行所在的地址,实际上是说明了代码所在内存的位置,内存的位置会随着代码的删改而很容易产生变动,这些对我们比较代码逻辑没有意义。其中有些绝对地址,我们将其替换为“{Address}”,这样既不受地址变化的影响,又不至影响了代码的含义。
然后我们将绿色的偏移地址替换成特定字符串“{Offset}”。产生偏移地址的原因一般有两种,一种是结构体,另一种是数组。即使不对结构体删改,而仅仅是对结构体的声明顺序的变动都可以造成偏移地址的不同,我们在这里只关心程序在这里用到了一个偏移地址,而不关心用的到底是偏移了多少。数组的用法虽然不常出现,但是即使出现其中的位置也是很容易发生变动的。因此在这里,我们也将偏移地址的数值替换成统一的字符串。
最后,我们来处理红色的立即数。当然立即数并不是只有上述的几种情况下出现,虽然在上述的例子中,两边的立即数都完全一样,单是在某些情况下还是会出现不同。
立即数在程序中一般是常量,而常量有可能是与系统相关的数值,或者仅仅是一个符号,而不在乎具体数值。无论是什么含义,常量虽然在执行过程中不会改变,在设计过程中却很容易发生变动。不过对我们分析代码逻辑没有太大的影响,因此,在分析的时候我们对数值进行模糊化,将其替换为“{Number}”这个特定字符串。
至此,上述代码将会变为:
<freebsd4_sigcode>: <freebsd4_sigcode>:
freebsd4_sigcode(): freebsd4_sigcode():
call *{Offset}(%esp) call *{Offset}(%esp)
lea {Offset}(%esp),%eax lea {Offset}(%esp),%eax
push %eax push %eax
testl {Number},{Offset}(%eax) testl {Number},{Offset}(%eax)
jne <freebsd4_sigcode+{Offset}> jne <freebsd4_sigcode+{Offset}>
movl {Offset}(%eax),%gs movw {Offset}(%eax),%gs
mov {Number},%eax mov {Number},%eax
push %eax push %eax
int {Number} int {Number}
jmp <freebsd4_sigcode+{Offset}> jmp <freebsd4_sigcode+{Offset}>
nop nop
现在这两段代码的相似度将变成真实的100%。
2.1.3 代码段顺序调整
经过上面的噪音过滤后,代码已经能够在基本不影响代码逻辑的前提下去除了噪音的影响。可是,还有一种情况会对匹配结果带来较大的影响。就是代码块位置的前后变动,我们来看下面这两段代码的比对。
begin(): <
mov {Address},%eax <
lea {Offset}(%eax),%esp <
xor %ebp,%ebp <
mov {Address},%esi <
mov %esi,{Offset}(%eax) <
pushl {Address} <
call <init386> <
add {Number},%esp <
call <mi_startup> <
add {Number},%esp <
sigcode(): sigcode():
call *{Offset}(%esp) call *{Offset}(%esp)
lea {Offset}(%esp),%eax lea {Offset}(%esp),%eax
push %eax push %eax
testl {Number},{Offset}(%eax) testl {Number},{Offset}(%eax)
jne <sigcode+{Offset}> jne <sigcode+{Offset}>
movl {Offset}(%eax),%gs movw {Offset}(%eax),%gs
mov {Number},%eax mov {Number},%eax
push %eax push %eax
int {Number} int {Number}
jmp <sigcode+{Offset}> jmp <sigcode+{Offset}>
nop nop
> begin():
> mov {Address},%eax
> lea {Offset}(%eax),%esp
> xor %ebp,%ebp
> mov {Address},%esi
> mov %esi,{Offset}(%eax)
> pushl {Address}
> call <init386>
> add {Number},%esp
> call <mi_startup>
> add {Number},%esp
和刚才一样。左边来自FreeBSD 5.3的代码,右边来自Kylin 2.0的代码(但是为了举例,函数前后顺序稍作调整)。在两段代码实际上非常相似,但是由于代码前后的顺序不同,导致只有一个代码块sigcode()可以匹配的上,相似度仅为47.6%。
针对这类情况,我的解决办法是将代码块按照标号/函数名进行排序。经过排序,上述代码段比对将变为:
begin(): begin():
mov {Address},%eax mov {Address},%eax
lea {Offset}(%eax),%esp lea {Offset}(%eax),%esp
xor %ebp,%ebp xor %ebp,%ebp
mov {Address},%esi mov {Address},%esi
mov %esi,{Offset}(%eax) mov %esi,{Offset}(%eax)
pushl {Address} pushl {Address}
call <init386> call <init386>
add {Number},%esp add {Number},%esp
call <mi_startup> call <mi_startup>
add {Number},%esp add {Number},%esp
sigcode(): sigcode():
call *{Offset}(%esp) call *{Offset}(%esp)
lea {Offset}(%esp),%eax lea {Offset}(%esp),%eax
push %eax push %eax
testl {Number},{Offset}(%eax) testl {Number},{Offset}(%eax)
jne <sigcode+{Offset}> jne <sigcode+{Offset}>
movl {Offset}(%eax),%gs movw {Offset}(%eax),%gs
mov {Number},%eax mov {Number},%eax
push %eax push %eax
int {Number} int {Number}
jmp <sigcode+{Offset}> jmp <sigcode+{Offset}>
nop nop
现在,这两段代码只有一行不同,相似度也就变为了95.2%。
但是这种依赖于标号/函数名排序的做法有效的程度实际上是有局限的。首先,并不是所有函数名都会保存于可执行代码中,至少inline函数就会在编译时扩展到调用的语句位置,还有一些函数在编译器优化时被优化掉。所以,不同的编译器,或者不同的编译参数都有可能导致某些函数名在执行体中消失,从而导致排序失败。另外,不是所有的可执行体都会保留函数名,对于Windows的PE文件来说,如果不用debug模式编译的话,除了导出函数外,其他的函数名一般不会保存在执行文件中,
在我用同样的方法分析Windows文件内核的时候出现了比较严重的问题,即使血亲关系很近的两个版本的Windows内核,无论排序或者不排序,相似度都非常的低,对于这类PE文件根本无法反映出相似度。所以,在最终的分析中,我剔出了原本列在比较目标中的XP内核。
因为ELF的这个特点,这次我的分析将只对使用ELF的文件格式的内核进行分析。
2.1.4 比较
在原本的计划中,我曾考虑采用常用于字符串相似度比较的编辑距离(Levenshtein Distance)算法[5]。这个算法的含义,是计算两字符串之间的距离有多远。编辑距离是指,从原字符串变化到目的字符串最少需要进行多少次包括添加、修改、删除在内的操作。举例而言:
如果计算kitten和sitting之间的编辑距离,我们最少需要进行3次操作,
1、 kitten -> sitten (修改s->k)
2、 sitten -> sittin (修改i->e)
3、 sittin -> sitting (增加 g)
因此,kitten和sitting之间的编辑距离是3。这个算法是俄国的科学家Vladimir Levenshtein在1965年提出的。这个算法主要是应用在DNA分析、拼字检查、语音辨识和抄袭侦测上。[6]
但是这个算法的计算复杂度太高,是O(nm)的复杂度。对于平均大小在100万行的操作系统内核源代码来说,就是万亿次级别的比对。对于普通的计算机,平均每两个内核的比对就要花去数小时。而此次参与比对的内核将有20个左右,完成一个比较完整的比对过程将会出现几百次比对,那么就要花数个月的时间,不太现实。
因此,这次我采用的是简化的比对办法。通过diff命令来比较两个内核源文件的差异。Diff使用的是一种更聪明的计算方法,虽然最坏情况差不太多,但是大多数情况下具有较高的性能[7]。
通过diff给出的结果可以得知第一个文件增改多少行代码后,就可以变为第二个文件。diff的算法和其实对于修改我们并不介意,我们只关心增加多少行代码就可以变为第二个文件。
假设内核A的代码有a行,内核B的代码有b行。而从内核A变化到内核B需要添加c行,由内核B变化到内核A需要d行。由此,我们可以得知,在内核A中,存在有b-c行代码和内核B是相同的。因此,我们将内核A中所存在的内核B的代码行数除以内核A自身的代码行数定义为两个内核的相似度,即
A->B的相似度 = (b-c) / a
由公式可知,A->B和B->A的计算结果将有可能不同。因为我们判断相似度的原因不单纯是看二者的差异,更重要的是看他们之间的血亲关系的远近,因此我们取双向转换中的最大值,作为A<->B之间的相似度。
A-B间的相似度 = max( (b-c) / a, (a-d) / b )
2.1.5 小结
分析方法还有待完善,可以看出,二进制可执行文件的分析依旧还有很大的难度,很容易受到各种外围环境的变化而导致相似度大幅下降,而无法反映真实的相似度。因此对于那些刻意隐瞒相关性的二进制可执行文件来说还是比较容易的逃过这种分析方法的检测。
但是,分析方法的缺陷却只会导致相似度的下降,而不会导致差异很大的代码产生很高的相似度。因此,我这次采用这次分析方法主要就是确定麒麟操作系统内核与其他操作系统之间的相似度的下限,并从数据中试图分析出他们的血亲关系。
2.2 多种操作系统内核相似度比较
为了比对尽量客观,这次参加比对的操作系统内核包括,FreeBSD, NetBSD, OpenBSD, Linux, Solaris和银河麒麟操作系统,共6个操作系统,22个内核。
原计划中,要将Mac OS X中的Darwin 8.0.1, 7.0.1拿来比对,可是由于其文件格式是Mach-O的,而我又没有支持Mach-O的objdump,所以暂时无法参与比对。另外,原计划曾打算拿相关性更差的Windows NT系列的系统内核来进行比对,可是由于之前所说的PE格式问题而导致的相似度没有参考价值,所以,这次也没有将其列入最终的比对。
为了确认比对的有效性,我们将先对FreeBSD, NetBSD和OpenBSD之间的比对来审视其比对效果。
2.2.1 FreeBSD间不同版本内核相似度分析
FreeBSD是一种Unix衍生操作系统,由BSD, 386BSD和4.4BSD发展而来的Unix的一个重要分支。而BSD的全称是“伯克利软件发布”,是美国伯克利大学计算机系统研究组所制作的一套包括内核在内完整的操作系统,起源于AT&T的Unix V6,但是后来由于与AT&T的版权纠纷问题,彻底的删除了AT&T在BSD内核中的代码,大约占10%左右。也正是这场官司,而给了Linux得以飞速发展的机遇。在版权问题解决后,BSD借助其高质量的代码,在开放源代码的世界里有了飞速的发展,分别产生了3个重要的分支,FreeBSD, OpenBSD, NetBSD。FreeBSD发展至今,已经成为公认的相当可靠和健壮的操作系统。[9,10]
因为焦点集中在FreeBSD身上,而且特别是5.x和6.x的系统上,因此这回参与比较的FreeBSD的内核版本较多,分别有FreeBSD 5.0, 5.1, 5.2, 5.2.1, 5.3, 5.4, 5.5 beta 4和6.0。
原始内核\目标内核
汇编行数
freebsd_5.0
freebsd_5.1
freebsd_5.2
freebsd_5.2.1
freebsd_5.3
freebsd_5.4
freebsd_5.5.b4
freebsd_6.0
freebsd_5.0
913,353
-
697423
712361
714811
969174
1001579
1016967
1146371
freebsd_5.1
958,699
652223
-
682433
681769
1029692
1002484
1034263
1112613
freebsd_5.2
1,048,418
572280
604662
-
3252
817759
865407
850969
1124929
freebsd_5.2.1
1,049,592
493098
607199
2078
-
816434
870479
881654
1124304
freebsd_5.3
1,161,593
742327
762747
705826
724190
-
35581
78219
977778
freebsd_5.4
1,174,287
744511
811979
732332
733290
22906
-
25985
901307
freebsd_5.5.b4
1,187,447
741616
783626
735617
734211
40295
12975
-
358820
freebsd_6.0
1,271,723
791490
805184
905427
907359
753022
766311
622653
-
上表中所列出的是FreeBSD的各个版本之间的差异行数,即前面所说到的c。左边列出的是原始内核,顶端列出的是目的内核。左边给出了原始内核的行数。
差异行数和相似度具有相同的含义,毕竟相似度也是通过差异行数计算出来的,因此在以后的叙述中,我们将只列出相似度对比的表格。
下面就是FreeBSD各个版本之间的内核相似度比较。
原始内核\目的内核
汇编行数
freebsd_5.0
freebsd_5.1
freebsd_5.2
freebsd_5.2.1
freebsd_5.3
freebsd_5.4
freebsd_5.5.b4
freebsd_6.0
freebsd_5.0
913,353
-
28.61%
36.79%
36.65%
21.07%
18.91%
18.67%
13.72%
freebsd_5.1
958,699
27.24%
-
38.18%
38.37%
13.76%
17.92%
15.98%
16.60%
freebsd_5.2
1,048,418
32.53%
33.77%
-
99.80%
32.80%
29.46%
32.09%
14.00%
freebsd_5.2.1
1,049,592
40.04%
33.49%
99.69%
-
32.89%
28.95%
29.13%
14.05%
freebsd_5.3
1,161,593
14.72%
16.87%
29.49%
28.01%
-
98.03%
95.49%
25.31%
freebsd_5.4
1,174,287
14.38%
12.49%
26.92%
26.94%
96.97%
-
98.91%
31.54%
freebsd_5.5.b4
1,187,447
14.46%
14.74%
26.34%
26.56%
94.43%
97.80%
-
76.88%
freebsd_6.0
1,271,723
9.58%
12.07%
11.24%
11.18%
32.13%
32.08%
44.41%
-
由于操作系统是逐步发展而来的,因此从5.0-5.5 beta 4都是在前者的基础上,修补前者中出现的bug,并增添新的特性而产生的。我们可以从这个FreeBSD的相似度表中看到这种传承关系。我们可以看出,基本上是越靠近当前版本相似度越高,而离当前版本越远相似度就越低。其中有一些特例的情况,5.1和5.2似乎比较特殊,可能是由于某种原因在5.1中策略有所调整,而在5.2.1或者5.3中又逐渐的恢复回来。
5.2.1和5.2的相似度达到了99.80%,这是正常的,由于在5.2之后,有一系列关键服务,如wu-ftp, OpenSSH和XFree86等的缓冲区溢出的漏洞被揭露出来,致使FreeBSD出于安全考虑而在5.2发布后仅一个月多的时间就立即发布了新的版本,因此5.2.1和5.2的内核上的差异实际上很低,主要是在外围程序上修补了很多安全漏洞[15]。但是出乎我意料的,我没想到在很容易被干扰而降低相似度的情况下,竟然可以达到这么高的相似度,说明这种分析方法对于代码相似度分析在一般情况下是有效的。究其原因,应该是因为FreeBSD的前后传承关系,所以不同的版本虽然代码有不少变动,但是默认的内核配置文件变动不大,因此才有可能出现这种比较高的相似度。另外我们也可以看出,FreeBSD在5.3以后,包括5.4和5.5的内核变动量都不大,由此可以感觉到5.x的系统可能已经基本成熟。
FreeBSD 6.0与5.3以前版本的相似度都不太高,主要是因为6.0已经是和5.x属于不同的代码分支,相对于5.x来说代码有了较大的变化。而另一方面,6.0的分支是在5.4版本发布后建立的,因此,6.0的内核与之前内核的相似度偏低,却和FreeBSD 5.3, 5.4, 5.5 beta 4的相似度较高。
总体上,基本符合版本相近,代码相近的客观事实,分析方法是成功的。
2.2.2 FreeBSD、NetBSD和OpenBSD的内核相似度分析
NetBSD和FreeBSD一样,也是从美国加州伯克利大学的4.3BSD和386BSD衍生出来的Unix操作系统。它以设计简洁、代码规范和高可移植性的特点而著称。从服务器到嵌入式设备都有它的身影[10]。而OpenBSD则是从NetBSD 1.0衍生而来的[11]。因此OpenBSD和NetBSD相对FreeBSD而言具有更近的血亲关系。
原始内核\目标内核
汇编行数
freebsd_5.3
freebsd_6.0
netbsd_2.1
netbsd_3.0
openbsd_3.7
openbsd_3.8
freebsd_5.3
1,161,593
-
25.31%
16.55%
16.61%
16.78%
16.74%
freebsd_6.0
1,271,723
32.13%
-
16.65%
16.22%
15.89%
16.24%
netbsd_2.1
1,503,585
13.08%
13.68%
-
53.35%
17.53%
16.72%
netbsd_3.0
1,616,659
11.76%
12.65%
24.40%
-
13.96%
14.61%
openbsd_3.7
1,228,137
15.60%
16.54%
20.77%
18.44%
-
88.89%
openbsd_3.8
1,260,707
15.26%
16.52%
20.65%
18.47%
84.56%
-
从这个数据表中,我们可以看出计算出来的数据可以反映这种已知的血亲关系。FreeBSD 与NetBSD和OpenBSD的相似度基本在16.5%左右,而NetBSD与OpenBSD的相似度则相对较高。NetBSD 2.1和OpenBSD的相似度为20.65% ~ 20.77%,NetBSD 3.0和OpenBSD的相似度也有18.44%,都高于FreeBSD与NetBSD和OpenBSD的相似度。虽然数值差别并不大,但是具有规律性,基本上也是客观地反映了真实的情况的。
2.2.3 Kylin与FreeBSD, OpenBSD, NetBSD, Linux, Solaris的内核相似度分析
现在我们开始对银河麒麟操作系统进行相似度比对。参与比对的开放源代码操作系统内核有FreeBSD 5.0, FreeBSD 5.2, FreeBSD 6.0, NetBSD 2.1, NetBSD 3.0, OpenBSD 3.7, OpenBSD 3.8, Linux 2.6.16, OpenSolaris 5.11,共9个内核。
除了刚才介绍过的FreeBSD, NetBSD和OpenBSD外,还增加了Linux和Solaris。Linux是Linus基本上从零起步写出来的操作系统,虽然参考了Minix和Unix的实现,但是基本上没有大量的使用任何其它Unix发布的代码[12]。因此,虽然Linux也是一个类Unix系统,然而由于是独立开发的,所以它和前面所列出的BSD衍生操作系统和后面将要提到的Solaris的血亲关系比较远。
从历史的角度来讲,Solaris和BSD很有渊源。在80年代,Sun基于BSD Unix发布了自己版本的UNIX,SunOS。而在90年代初,由于受到AT&T与BSD的官司影响,Sun将其SunOS 4替换为与AT&T共同开发的UNIX System V Release 4的一个版本,并更名为Solaris 2[13]。在2004年早期,Sun开始了一项计划,名为OpenSolaris,将Solaris逐步的放到开放源代码社区中。并在2005年的6月中旬开放了大部分的Solaris源代码[14]。现在已经有一些基于OpenSolaris源代码的操作系统,这次采用的就是一个名为Belenix的Live CD发布版本0.4.2种的内核,uname显示的是SunOS 5.11。
此次引入Solaris来进行比对,也是从一方面希望能够从分析数据中客观地反映出Solaris,相比Linux而言,和BSD有更近的血亲关系。
关于参与比对的麒麟操作系统内核,我们将从发布版本中获得的四个版本的内核拿来进行比对,Kylin 2.0.0, Kylin 2.0.14, Kylin 2.0.21, Kylin 2.0.21 lsb。需要说明的是,官方网站上发布了2.0.14和2.0.18。其中Kylin 2.0.0是来自于麒麟系统安装盘的引导部分,通过uname –a显示出的版本是2.0.0。Kylin 2.0.21虽然是官方网站给出的光盘镜像的版本号,可是启动后,通过uname –a得到的版本号却是2.0.18,这点可能是麒麟开发组在版本管理上的混乱所导致的。
下面就是分析后得到的数据表;
原始内核\目标内核
汇编行数
fb 5.0
fb 5.2
fb 6.0
k 2-0
k 2-14
k 2-21
k 2-21 lsb
l 2.6.16
nb 2.1
nb 3.0
ob 3.7
ob 3.8
os 5.11
freebsd_5.0
913,353
-
36.79%
13.72%
40.53%
30.43%
30.43%
40.53%
6.46%
11.24%
11.37%
10.91%
10.87%
5.02%
freebsd_5.2
1,048,418
32.53%
-
14.00%
48.18%
34.02%
34.02%
48.18%
5.75%
11.02%
10.91%
10.95%
10.94%
4.55%
freebsd_6.0
1,271,723
9.58%
11.24%
-
12.63%
13.19%
13.14%
12.63%
6.61%
16.65%
16.22%
15.89%
16.24%
5.21%
kylin_2.0.0
1,120,079
31.92%
41.94%
14.55%
-
91.06%
91.06%
100.00%
5.38%
10.83%
10.31%
10.20%
10.35%
4.35%
kylin_2.0.14
1,190,443
23.55%
29.98%
24.61%
85.60%
-
100.00%
85.60%
5.04%
10.63%
10.64%
10.30%
10.44%
4.06%
kylin_2.0.21
1,190,562
23.52%
29.95%
21.04%
85.57%
99.99%
-
85.57%
5.03%
10.72%
10.63%
10.29%
10.44%
4.06%
kylin_2.0.21_lsb
1,120,079
31.92%
41.94%
14.55%
100.00%
91.06%
91.06%
-
5.38%
10.83%
10.31%
10.20%
10.35%
4.35%
linux_2.6.16
666,204
9.47%
9.71%
13.13%
5.38%
5.38%
5.39%
5.38%
-
11.89%
12.09%
12.21%
12.07%
6.30%
netbsd_2.1
1,503,585
6.49%
7.42%
13.68%
8.06%
8.18%
7.97%
8.06%
5.20%
-
53.35%
17.53%
16.72%
4.10%
netbsd_3.0
1,616,659
6.19%
7.11%
12.65%
7.54%
7.90%
7.89%
7.54%
4.98%
24.40%
-
13.96%
14.61%
3.73%
openbsd_3.7
1,228,137
7.95%
9.58%
16.54%
9.27%
9.97%
9.71%
9.27%
6.43%
20.77%
18.44%
-
88.89%
5.20%
openbsd_3.8
1,260,707
7.72%
8.84%
16.52%
8.88%
9.53%
9.52%
8.88%
6.29%
20.65%
18.47%
84.56%
-
5.00%
OpenSolaris_5.11
396,534
11.87%
12.00%
16.84%
12.50%
12.46%
12.46%
12.50%
13.37%
15.90%
15.82%
16.66%
16.49%
-
从数据表中反映出来的血亲关系来看,Kylin 2.0的内核和FreeBSD 5.x的血亲关系最近,在30.43%-48.18%之间,和FreeBSD 6.0的关系稍远,在14.55%-24.61%之间。而和其他的操作系统关系都比较疏远。和NetBSD、OpenBSD的相似度在10%左右,而同Linux的相似度只有5.38%,
与OpenSolaris的相似度虽然比NetBSD和OpenBSD还高,达到了12.50%,但是这个绝对数值不应该视为OpenSolaris与麒麟的关系更接近。因为,OpenSolaris的代码行数仅有396,534行,仅相当于NetBSD的1/4。在相似度计算公式中,分母较小,容易致使结果的相似度较大,因此不应该说麒麟内核和Solaris更相似,应该说麒麟内核同Solaris,NetBSD和OpenBSD的相似度相当。
另外,我们可以注意到OpenSolaris和FreeBSD 6, NetBSD, OpenBSD的相似度略高于其他系统内核,但是都比较低。我们从这个不大的差异中可以感觉到Solaris同BSD的或近或远的关系。其实虽然Solaris代码已经不是基于BSD构建的Unix了,但是由于SVR4中也吸收了BSD的部分代码,因此Solaris在相似度上,还是客观的体现了和BSD偏近的关系。
从数据中我们还可以看到麒麟的这几个内核的相似度很高。Kylin 2.0.0和Kylin 2.0.21 lsb的相似度是100%,Kylin 2.0.14和2.0.21的相似度也是接近100.00%。其中的具体差异行数如下:
原始内核\目标内核
汇编行数
kylin_2.0.0
kylin_2.0.14
kylin_2.0.21
kylin_2.0.21_lsb
kylin_2.0.0
1,120,079
-
170,553
170,641
0
kylin_2.0.14
1,190,443
101,029
-
145
101,029
kylin_2.0.21
1,190,562
101,328
26
-
101,328
kylin_2.0.21_lsb
1,120,079
0
170,553
170,641
-
我们可以看出其实光盘引导用的内核同安装后的/boot/kernel_lsb/ 目录下的内核是相同的。而Kylin 2.0.21和2.0.14相比仅仅修改了几十行代码而已,变动很小,从数值上看,变动主要是增加了一些代码。而从2.0.0到2.0.14变动稍大一些。
在后面的分析中,我们没必要对很相似的内核一起进行重复分析,因此,将基于Kylin 2.0.0和Kylin 2.0.21这两个麒麟内核进行分析。
从现在的结果我们已经可以看出麒麟和FreeBSD的5.x版本有很近的血亲关系,最高达到了与FreeBSD 5.2的48.18%的相似度,这种相似性甚至已经明显超过了和FreeBSD具有很近的同源关系的NetBSD, OpenBSD。即使是最初基于NetBSD的代码而建立的OpenBSD,在与其渊源极深的NetBSD比较时,最高也不过20.77%的相似度。
至此,我们基本上可以确定麒麟操作系统内核中有大量的FreeBSD 5.x 的源代码。为了进一步确定麒麟操作系统和FreeBSD的相似性到底有多少,我们接下来将针对Kylin内核和FreeBSD的内核作比较。
2.2.4 Kylin与FreeBSD各个版本间的内核相似度分析
这次我们针对Kylin和FreeBSD这两个操作系统的内核进行相似度的比对。参与比对的将包括Kylin的2个典型内核和FreeBSD 5.x全系列内核,具体是Kylin 2.0.0, Kylin 2.0.21, FreeBSD 5.0, FreeBSD 5.1, FreeBSD 5.2, FreeBSD 5.2.1, FreeBSD 5.3, FreeBSD 5.4, FreeBSD 5.5 beta4。
原始内核\目标内核
汇编行数
fb 5.0
fb 5.1
fb 5.2
fb 5.2.1
fb 5.3
fb 5.4
fb 5.5.b4
kylin_2.0.0
kylin_2.0.21
freebsd_5.0
913,353
-
28.61%
36.79%
36.65%
21.07%
18.91%
18.67%
40.53%
30.43%
freebsd_5.1
958,699
27.24%
-
38.18%
38.37%
13.76%
17.92%
15.98%
28.94%
26.11%
freebsd_5.2
1,048,418
32.53%
33.77%
-
99.80%
32.80%
29.46%
32.09%
48.18%
34.02%
freebsd_5.2.1
1,049,592
40.04%
33.49%
99.69%
-
32.89%
28.95%
29.13%
48.15%
34.47%
freebsd_5.3
1,161,593
14.72%
16.87%
29.49%
28.01%
-
98.03%
95.49%
57.94%
50.48%
freebsd_5.4
1,174,287
14.38%
12.49%
26.92%
26.94%
96.97%
-
98.91%
56.24%
51.88%
freebsd_5.5.b4
1,187,447
14.46%
14.74%
26.34%
26.56%
94.43%
97.80%
-
39.47%
50.16%
kylin_2.0.0
1,120,079
31.92%
20.99%
41.94%
41.97%
60.26%
59.04%
42.59%
-
91.06%
kylin_2.0.21
1,190,562
23.52%
16.68%
29.95%
29.93%
52.04%
50.87%
50.35%
85.57%
-
Kylin 2.0.0和FreeBSD 5.3的相似度达到了60.26%,与FreeBSD也达到了59.04%的相似度。我们可以注意到,即使是FreeBSD的5.0 – 5.3版本之间的相似度也没有超过40.04%。5.3、5.4和5.5的高相似度前面已经解释了,应该是5.x系列的内核趋于稳定了,因此修补较多增添新的特性较少所致。
按照麒麟开发人员的解释,麒麟操作系统内核服务层使用的是FreeBSD 5.0的代码。可是,从我们的分析数据可以明显看出,Kylin 2.0.0和FreeBSD 5.0的相似度有40.53%,而与FreeBSD 5.3的相似度达到了60.26%,因此我们有理由相信麒麟使用的是FreeBSD 5.3或者5.4的代码。
当然,我们可以理解为这是开发人员的声明[3]中的一个笔误,他想说FreeBSD 5.x,而不是FreeBSD 5.0。但是,另一方面,如果说仅仅是外围服务层使用的是FreeBSD的话,那么麒麟与FreeBSD 5.3的相似度不应该高过FreeBSD自家不同版本之间的相似度。既然麒麟2.0.0内核与FreeBSD 5.3达到了60.26%的相似度,那么我们可以肯定地说,麒麟操作系统内核源代码至少有一半以上使用的是FreeBSD 5.3的源代码。
2.2.5 Kylin与FreeBSD 5.3, 5.4不同编译配置下的内核相似度分析
为了能够进一步了解麒麟操作系统内核同FreeBSD内核的相似度,接下来,我们将对FreeBSD 5.3和5.4在不变动任何源代码的情况下,重新进行编译,增加一些在Kylin 2.0中出现的模块。这样做的是希望在不修改FreeBSD代码的前提下,看看不同的编译配置是否能够使得FreeBSD与麒麟操作系统内核的相似度更高。
这次,我们在FreeBSD的内核编译配置文件GENERIC中增加如下三个选项:
options COMPAT_LINUX
options LINPROCFS
device sound
因为麒麟内核的一个亮点就是可以做到和Linux的二进制兼容,所以这主要是增加FreeBSD的Linux兼容性。其实事实上FreeBSD已经可以很好的兼容Linux二进制代码了,按照FreeBSD的内核设计,它完全可以同时支持多种ABI(应用程序二进制接口),并支持同时运行不同系统可执行文件。通过加载COMPAT_LINUX模块,FreeBSD就已经做到了和Linux可执行文件间的二进制兼容,可以执行大部分Linux程序[17]。
而LINPROCFS模块则是模拟了Linux的进程文件系统,也就是我们在Linux下见到的/proc目录,很多Linux的程序需要用到这个系统,因此加载这个模块后,可以让Linux更好的在FreeBSD上运行[18]。
最后增加了sound设备,因为我们通过分析,发现Kylin内核里面加载了各种声卡驱动。需要提及的是,麒麟系统启动比较慢,有可能也是因为编译了过多的不必要的模块进内核所导致的。
原始内核\目标内核
汇编行数
freebsd_5.3
freebsd_5.3_1
freebsd_5.4
freebsd_5.4_1
kylin_2.0.0
kylin_2.0.21
freebsd_5.3
1,161,593
-
97.47%
98.03%
73.12%
57.94%
50.48%
freebsd_5.3_1
1,198,401
93.78%
-
80.82%
98.07%
56.49%
56.64%
freebsd_5.4
1,174,287
96.97%
94.55%
-
96.58%
56.24%
51.88%