设为首页 收藏本站
查看: 1221|回复: 0

[经验分享] 内核版本升级和添加Linux系统调用

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2013-12-17 10:39:48 | 显示全部楼层 |阅读模式
一、  系统调用简介
所谓系统调用,就是内核提供的、功能十分强大的一系列的函数。这些系统调用是在内核中实现的,再通过一定的方式把系统调用给用户,一般都通过门陷入(gate trap)实现。系统调用就是用户空间应用程序和内核提供的服务之间的一个接口。由于服务是在内核中提供的,因此无法执行直接调用;相反,您必须使用一个进程来跨越用户空间与内核之间的界限。在特定架构中实现此功能的方法会有所不同。
实现系统调用的方法有多种,最常用的是一个特殊的中断,即陷入(int指令),其中断向量号是$0x80。因此,系统调用的处理过程也就是int $0x80的处理过程。当执行到指令int $0x80时,处理器会将堆栈切换到当前进程的系统堆栈,并在栈顶自动压入SS、ESP、EFLAGS、CS、EIP,而后跳转到system_call。
程序system_call的处理流程如下:
(1)将EAX中的系统调用号压入栈顶。
(2)将其余的寄存器压入栈顶,形成一个pt_regs结构。值得注意的是服务函数都通过堆栈接收参数,而处于栈顶位置的寄存器(EBX、ECX、EDX、ESI、EDI、EBP)恰好是传递给服务函数的参数。
(3)检查EAX中的系统调用号是否越界。
(4)根据EAX中的系统调用号查系统调用表sys_call_table,获得该调用号对应的服务函数,调用该函数完成系统调用的服务处理工作。系统调用服务函数通过堆栈接收参数,参数的个数是预先约定好的。
(5)当服务函数返回时,用EAX中的返回值替换栈顶的ax。
(6)关闭中断(CLI)。
(7)善后处理:1)根据当前进程的设置完成必要的审计工作;2)如果当前进程需要调度,则调度它;3)如果当前进程有待处理的信号,则处理它;4)弹出栈顶,恢复各段寄存器、各通用寄存器及EIP、CS、EFLAGS、ESP、SS等寄存器的值,返回用户态,继续执行int $0x80之后的指令。此时,EAX中值是栈顶的ax,及系统调用的返回值。
二、  实验环境
Windows 7(2G内存)中安装了VMware 9.0.0虚拟机;
虚拟机中安装了Ubuntu 12.04(LTS)版(512M内存)。
三、  实验内容
(1)   linux内核版本升级
(2)   添加linux系统调用
四、  实验步骤
1、获取当前内核版本:
通过命令 uname –a获取当前内核版本,主要便于后来对比观察内核版本升级是否成功。可以看到我当前的版本为linux-3.2.0-29
2、下载内核源码:
1)到网站https://www.kernel.org/ 下载新的内核源码,(如果单单只做添加系统调用的实验的话,也可以使用系统中带有的源代码,在/usr/src/中)。本次实验我下载的是比较新一点的内核版本linux-3.10。2)下载之后,是一个压缩文件,叫做linux-3.10.tar.xz,这里我们把它移动到/usr/src/目录下,(其实这里的移动不是必须的,只是网上有好多教程都做了移动)。在终端(shell)中进入下载目录后,执行命令sudo mv linux-3.10.tar.xz /usr/src/输入密码,移动成功后,解压文件,进入/usr/src/后执行命令:sudo tar –xvf linux-3.10.tar.xz,解压出文件夹linux-3.10。(z:通过gzip支持压缩或解压缩。还有其他的压缩或解压缩方式,比如j表示bzip2的方式。x:解压缩。c是压缩。v:在压缩或解压缩过程中显示正在处理的文件名f:f后面必须跟上要处理的文件名。)
3、下载并安装用于源码配置的工具,这一部分,可以参考一下ubuntu论坛的文章,http://forum.ubuntu.org.cn/viewtopic.php?t=134404,不过他编译的内核为2.6.25,我们这里只是将命令粘出来,实际上就是下载了几个包,在我们编译配置时可能会用到。sudo apt-get install build-essential kernel-package libncurses5-dev4、修改源码,我们的目的是添加一个新的系统调用。(提醒一下,修改源码需要较高的权限,可以使用命令sudo gedit 文件名,或者su gedit 文件名)1)/usr/src/linux-3.10/kernel/sys.c添加头文件  #include <linux/linkage.h>文末添加自定义的系统调用函数: Center.jpg 2)/usr/src/linux-3.10/arch/x86/syscalls/syscall_32.tbl(如果你的虚拟机是64位的,则需修改syscall_64.tbl)在系统调用向量表里添加自定义的系统调用号(这个可以适当选取一个没有用到的号): Center.jpg 其中356是我为hello这一系统调用定义的功能号。3)/usr/src/linux-3.10/arch/x86/include/asm/syscalls.h在适当的位置添加系统调用函数声明: Center.jpg 5、内核编译(这是一个漫长的过程,由于我是在虚拟机中运行的,编译一次至少用4个小时)1)如果不是第一次进行内核编译,需要对之前的设置进行清理,清理以前编译留下的临时文件;如果是刚刚解开的源码包,不用执行此步:sudo make mrproper2)内核配置http://blog.iyunv.com/xuyuefei1988/article/details/8635539sudo make menuconfig(基于文本选单的配置界面,字符终端下推荐使用)sudo make xconfig(基于图形窗口模式的配置界面,Xwindow下推荐使用)sudo make oldconfig(如果只想在原来内核配置的基础上修改一些小地方,会省去不少麻烦)这里为了方便我们直接将内核配置默认为原来内核的配置,执行以下命令即可:sudo make olddefconfig3)编译内核和模块(依次执行“make”、“make modules”、“make modules_install”、“make install”,如果前面的配置没有问题的话,耐心等待一段时间就可以得到编译好的内核和模块了。)在Ubuntu下,安装kernel-package这个包之后,就可以使用make-kpkg来简化编译流程了。sudo make-kpkg clean  (清理)sudo make-kpkg  --initrd  --append-to-version=wrm128 kernel-image kernel-headers(在版本后追加字符串wrm128,生成kernel-image和kernel-headers文件)。编译成功后: Center.jpg 4)安装内核编译完成后,在/usr/src/中会看到生成两个deb文件。执行以下命令进行安装:sudo dpkg -i linux-image-3.10.0wrm128_3.10.0wrm128-10.00.Custom_i386.deblinux-headers-3.10.0wrm128_3.10.0wrm128-10.00.Custom_i386.deb(这两个文件名有点儿长,敲命令时可以用tab键补全)。这两个文件解压安装成功之后,在usr/src/目录下会生成文件linux-headers-3.10.0wrm128,也就是替换成功的新内核。5)重启系统执行命令:sudo reboot 重启系统。如果一切顺利的话,应该能够重启成功。 Center.jpg 键入命令:uname  -a,查看一下现在的内核版本: Center.jpg 可以看到现在的内核版本已经变为3.10.0wrm128,说明内核升级及编译已经成功喽!6、测试系统调用1)在主文件目录(/home)下创建文件夹:mkdir test进入/home/test/目录下,创建文件testHello.c:gedit testHello.c编写测试代码: Center.jpg 在我的系统调用函数中有一个char *的字符串参数,故在调用时不仅要将系统调用号356传入,还要将char * 的字符串传入。syscall是内核提供为用户程序的一个函数,如果不使用syscall函数,也可以使用宏定义,但是在2.6.20以后的版本里,没有宏定义,需要自己从其他版本里复制过来添加。
2)编译,运行进入/home/test/目录,执行命令:gcc  -testHello.c  -o  testHello编译成功后,执行命令:./testHello Center.jpg 3)查看内核日志查看系统调用在内核空间的运行情况,执行命令:dmesg Center.jpg 可以看到参数”wrm”已传入,系统调用函数成功执行!OK,终于大功告成!小结:第一次因为电耗尽了,没有带电源,然后4个小时就废了;第二次(4个多小时)内核升级成功了而系统调用失败了,查了半天,才发现自己太蠢,follow网上教程将系统调用号定义在了syscall_64.tbl中,而忽略了自己的系统是32位的;第三次编译了1个多小时时报错了:arch/x86/built-in.o:(.rodata+0x610): undefined reference to `sys_hello' make: *** [vmlinux] Error 1 网搜有类似错误却没有答案,只好一个文件一个文件查看,看哪里出了问题,致使找不到sys_hello,最后发现syscalls.h中好像找不到我添加的系统调用函数的声明。只好手动添加,然后重新编译。。。第四次,编译了至少5个小时,从晚上8点到1点多,终于OK!佩服自己竟然没有中途放弃。。。最终编译成功是失败三次的结果,实验证明在虚拟机中编译内核真的是一个无比漫长的过程。不同的操作系统及内核版本的操作流程可能会有所不同,不能完全参照网上的教程,这个需要试验和摸索。经过几次失败之后,对内核编译和添加系统调用一定会有更深的理解!

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-11759-1-1.html 上篇帖子: Linux常用的进程管理和查看指令 下篇帖子: Linux Kernel本地权限提升漏洞 版本升级 Linux
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表