ChinaUnix.net 首页 | 博客 | Linux | 论坛 | 人才 | 培训 | 知识库 | 资料 | 读书 | 手册 | 精华 | 下载 | 沙龙 | 搜索
Linux首页 | Linux论坛 | 论坛精华 | 开源新闻 | 技术文章 | 专题专栏 | 新手指南 | 迁移方案 | 产品方案 | 开源项目 | 开源图书 | 软件下载 | 人才招聘 | Linux博客
  搜索

  产品与方案
·中科红旗全面打造现代化邮政体系
·红旗助力“网上审批服务” 推动电子政务
·红旗正版化开创呼和浩特网吧建设新起点
·红旗Linux助信息产业部邮件服务器“快跑”
·中标普华Linux 为电子政务信息化保驾护航
·中标普华Linux助力基金产业
·中标普华Office率先支持UOF标准
·中标普华邮件系统助力西藏政府信息化建设
·红旗Linux助力国库集中支付系统改革
·红旗助中信卫星 掀起GIS通信应用风暴
·红旗软件助力烟草总局 全面建设“数字烟草”
·红旗助力“信访阳光工程”打造畅通信访渠道
·红帽联合FIS发布下一代实时核心银行平台
·红旗助力金盾 打造全无忧出入境信息系统
·红旗Linux全力打造中国邮政总局名址信息库
·爱尔兰证交所从Unix迁移到红帽企业Linux
·一流的意大利银行选择使用红帽企业Linux
·PLUS Finanzservice选择使用红帽企业Linux
·红帽助力TransACT Communications 公司
·法国零售业巨头Lapeyre采用Redhat Linux
·旅游预订网站选择使用红帽企业Linux
·马哈拉施特拉邦政府的红帽解决之道
·美国联邦政府案例
·红帽为慕尼黑展览会提供现代化集群系统
·Yuba郡用开源软件和红帽产品提高了效率
·红帽企业Linux助印度理工建立高性能计算中心
·采用红帽Linux 将系统维护时间缩短了65%
·从UNIX迁移到Linux使Peñoles公司获益非浅
·Hikal公司用红帽企业Linux开展任务关键的ERP项目
·KDE3.5.4新版本发布
·芝加哥商业交易所从Unix向Linux迁移
·南方基金管理有限公司成功案例 Red Hat Linux
·广东北电通讯设备有限公司成功案例
·挪威国家石油公司从UNIX迁移到红帽Linux,成本减半
·中央电视台CCTV动画部案例 Red Hat Linux

  图书

鸟哥的Linux私房菜基础学..


Linux程序设计.第3版


Linux设备驱动开发详解


  下载
·Endian Firewall
·linux kernel(Linux 内核)
·CentOS
·Fedora Core 6
·Scientific Linux
·Slackware 11.0
·Gentoo Linux
·ubuntu-6.10-i386服务器版本
·ubuntu-6.10-amd64服务器版
·ubuntu-6.10-i386桌面版
·ubuntu-6.10-amd64桌面版
·Engarde Linux
您的位置: Linux时代 > 技术文档 > 内核研究 >

详解Linux操作系统的内核空间保护

日期:2007-02-01 作者:huangfu 来自:linux.chinaunix.net


  看了LINUX代码,感觉其对内核内存的保护做得不是很好,还有感觉大家有些地方理解不对(主要是 LINUX的代码看起来的样子和实际的样子不太一样),所以谈谈我对LINUX系统内核空间的保护和用户空间与系统空间数据传递的代码看法。注意我说的都是I386体系结构,别的体系结构可以看相应的代码,不敢保证结果是否是如我所说。

  LINUX建立进程的时候建立了两套段描述符,在文件Segment。h有说明。

        #ifndef _ASM_SEGMENT_H

        #define _ASM_SEGMENT_H

        #define __KERNEL_CS 0x10

        #define __KERNEL_DS 0x18

        #define __USER_CS 0x23

        #define __USER_DS 0x2B

        #endif

  一个用于内核代码,一个用于用户代码。运行内核代码的时候用内核的段描述符号就可以直接访问用户空间,但运行用户代码的时候用户段描述符不能访问内核空间,这是用的保护模式一些机制,具体代码不再介绍。不懂的就得看看介绍保护模式的一些书籍了。

  在用户代码调用系统函数的时候,程序进入了系统内核代码,描述符也已经切换到了内核的描述符,这时可以直接访问用户空间或者内核空间,两者的参数数据传递也很简单,可以直接拷贝等。但看了LINUX代码的都知道,系统函数代码里面的用户空间与内核空间参数传递是没有这么直接拷贝的,那是为什么呢?大家想一想,用户调用的一些指针参数等,可以指向内核空间,如果不加以检测直接拷贝,那么用户空间代码就可以通过系统调用读写内核空间了,这显然是不准许的。所以内核代码里面就采用了统一的一些函数:copy_from_user/copy_to_user和 __generic_copy_from_user/__gerneric_copy_to_user等,而在这些函数里面实现用户调用传递的指针合法性检测,用户参数提供的指针等不能指向系统空间,这样编写内核代码的时候只要调用这些函数就能实现了对内核空间的保护,编写也比较方便。这就提醒大家自己编写内核代码的时候,千万不要图方便直接用户空间与内核空间的参数拷贝,其实那些COPY函数并不是说用户空间与内核空间要怎么切换才能拷贝,这点我看很多人都没有真正的理解。

  我们再仔细看看那些COPY函数是怎么实现的内核空间保护呢。原来是在每个进程的进程数据结构里面保存了一个用户空间范围, current- >addr_limit,因为内核空间在用户空间上面,所以只要简单检测用户传递参数访问的空间是不是小于等于这个范围就是了。下面是相关的几个文件的相关内容。

  文件 uaccess:

        #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })

        #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)

        #define USER_DS MAKE_MM_SEG(PAGE_OFFSET)

        #define get_ds() (KERNEL_DS)

        // 取得内核空间范围

        #define get_fs() (current->addr_limit)

        // 取得用户空间范围

        #define set_fs(x) (current->addr_limit = (x))

        // 设置用户空间范围

        文件 processor。h :

        typedef struct {

        unsigned long seg;

        } mm_segment_t;

        文件 page。h :

        include        

        #define __PAGE_OFFSET (PAGE_OFFSET_RAW)

        #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)

        文件page_offset。h:

        #include

        #ifdef CONFIG_1GB

        #define PAGE_OFFSET_RAW 0xC0000000

        #elif defined(CONFIG_2GB)

        #define PAGE_OFFSET_RAW 0x80000000

        #elif defined(CONFIG_3GB)

        #define PAGE_OFFSET_RAW 0x40000000

        #endif

        // 这个显然可以配置用户空间与系统空间大小

  大家看那get_ds()、get_fs()、set_fs()等函数可能不是你刚看到时想的那么一回事吧?他们看来好象是访问或者设置段,其实只是访问或者设置一个进程变量罢了。

  你看那些COPY函数使得传递的一些参数只能是指向用户空间,那么内核代码对系统一些函数的调用怎么办呢,因为那时的参数都在内核空间里面呀。你仔细看看上面不是有个set_fs(x)调用吗,那就是设置这个用户空间限制的调用,只要临时设置用户空间限制为内核空间的范围,调用完了过后恢复就是了。你再看下面代码就对那几个set_fs()的作用清楚了吧。

        ->filename is in our kernel space

        unsigned long old_fs_value = get_fs();

        set_fs(get_ds()); /* after this we can access the user space data */

        open(filename, O_CREAT|O_RDWR|o_EXCL, 0640);

        set_fs(old_fs_value); /* restore fs。。。 */

  好了,原理讲完了,代码大家也看明白了,我们再看看这种编程好不好呢?其实这种编程显然不好。 缺点如下:

  1、还没有形成统一的保护方式,对内核空间的保护不好。内核代码编程不注意的话就可能使得用户程序突破内核空间的保护。这点编写内核代码的同志一定得注意用户空间与系统空间的拷贝一定得用那些COPY函数,不要自己简单的直接拷贝。

  2、内核代码对系统函数调用时设置用户空间限制不好。这点如果设置了哪个进程的用户空间限制还没有设置回去的时候如果进程用户代码得到运行(应该不太可能吧)那么就突破了内核空间限制。还有如果内核代码不注意忘了恢复用户空间限制那么也使得内核空间保护失效。

  其实有好的办法,实现也很简单。就是用一个内核全局变量保存用户空间范围,这个启动的时候根据配置计算好,内核调用的时候可以很方便的引用这个变量对用户代码的调用参数实现检测,用另一个内核全局变量来区分程序是在内核态还是用户态运行,如果在内核态再调用系统函数就可以不用检测系统调用的参数是在内核空间还是用户空间。这样就可以避免修改那个全局变量的麻烦。

本文被浏览



 相关新闻

内核开发人员Jens Axboe专访2007-02-01 09:17:16
如何成为一个Linux系统内核开发者2007-01-31 15:47:23
Linux内核: 修改TCP/IP调优参数2007-01-29 10:25:13
2007年Linux内核峰会的计划2007-01-24 11:12:31
Jonathan Corbet谈近来Linux内核的改进2007-01-22 09:25:09
打造适合自己Slackware机器的内核2007-01-08 15:21:59
Linux内核2.6.20增加虚拟化解决方案KVM2006-12-18 10:11:17
使用 SystemTap 调试内核2006-12-15 15:23:44


 相关评论
关于我们 | 联系方式 | 广告合作 | 诚聘英才 | 网站地图 | 免费注册

Copyright © 2001-2006 ChinaUnix.net All Rights Reserved

感谢所有关心和支持过ChinaUnix的朋友们

京ICP证041476号