免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1597 | 回复: 1

[其他] 系统调用时的字符串拷贝 [复制链接]

论坛徽章:
13
程序设计版块每日发帖之星
日期:2016-06-29 06:20:00每日论坛发贴之星
日期:2016-08-14 06:20:00操作系统版块每日发帖之星
日期:2016-08-14 06:20:00每日论坛发贴之星
日期:2016-08-13 06:20:00数据库技术版块每日发帖之星
日期:2016-08-13 06:20:00程序设计版块每日发帖之星
日期:2016-08-13 06:20:00IT运维版块每日发帖之星
日期:2016-08-13 06:20:00每日论坛发贴之星
日期:2016-08-12 06:20:00数据库技术版块每日发帖之星
日期:2016-08-12 06:20:00程序设计版块每日发帖之星
日期:2016-08-12 06:20:00操作系统版块每日发帖之星
日期:2016-08-12 06:20:00综合交流区版块每日发帖之星
日期:2016-08-09 06:20:00
发表于 2016-08-10 15:27 |显示全部楼层
本帖最后由 karma303 于 2016-08-11 10:11 编辑

  linux内核的系统调用的入口,也就是sys_xxx()里,通常都会调用getname(),把字符串从用户空间拷贝到内核空间。其实最终调用的是strncpy_from_user()系列的函数。
  原先看vfs的sys_open时候,就发现这个问题了。明明内核是可以直接访问用户空间的。今天又在sys_execve里看到这样的代码:filename = getname((char *) regs.ebx),终于忍不住google了一把。

  SO上已经有人问了:
  stackoverflow.com/questions/12666493/why-do-you-have-to-use-copy-to-user-copy-from-user-to-access-user-space-from
  最佳答案说,sys_caller传进来的指针不保险,比如指向不存在页(尚未映射),或者指向内核空间。所以要检查一下。
  提问者又接着问了,那我可不可以自己检查呢,我确认它安全之后,再直接访问,总可以了吧?
  然后得到的回答是,I'm not sure what you mean。。。
  其实有时候提问者是比回答者想的更深的。

  最后,终于找到了一篇博客,是从安全角度解释的。
  它提到了double fetch的概念。 内核要避免double fetch,即多次直接访问用户空间的同一个数据
  举个例子,用户空间有一个结构体:
  struct  lstr{ int len;  char *s; } lstr;
  内核通过系统调用得到指向它的指针pstr,并do something:
  char *buf = kmalloc( pstr->len);                                //first fetch
  memcpy(buf, pstr->s, pstr->len);                              //second fetch
  这两句代码可能造成内核崩溃。为什么呢,假如kmalloc之后,memcpy之前,用户空间的lstr结构体的内容被修改了(被另一个线程),len字段修改成了更大的数。 那memcpy就会越界。
  所以要避免double fetch。换言之,应该先把它拷贝到内核空间,再访问¹。
   linux在do_getname()的开头也注释道,"In order to reduce some races 。。"。 这儿的race,说的也是同一件事。
  这篇博客基本上能说明问题了。 中途扫了一眼地址栏,发现竟然是微软的技术博客,唏嘘不已。
  blogs.technet.microsoft.com/srd/2008/10/14/ms08-061-the-case-of-the-kernel-mode-double-fetch/
  可见这儿是一个漏洞,windows和linux都注意到了,并且都采取了相同的应对措施,就是strncpy_from_user()。

  另一篇描述这个漏洞的文章:
  lwn.net/Articles/245630/
  它讲的是"system call wrappers"(系统调用钩子)存在的安全漏洞。说要避免这个漏洞,除了关闭这个功能,别无它法————linux就没有开放自己的system call table。 但这又是一个很有用的功能,BSD上的很多软件都用到了,像比FreeBSD上的CerbNG firewall。
  只看懂这么多。不过后面的评论我看懂了。

Please educate a curious cat

Posted Aug 16, 2007 5:27 UTC (Thu) by felixfix (subscriber, #242) [Link]
I understand what is going on; a pointer or some other piece of user data is changed by a user program, in a different thread probably, between validation and use.
I haven't written this kind of code; the last OS work I did passed all syscall parameters in registers. But I am a bit confused. Wouldn't it be very simple to avoid these race conditions by copying the user data to kernel memory before validating? Obviously this wouldn't work with the infamous setuid switcheroo, but for syscall parameters, it would seem to work very well. The only case I can think of to make it difficult would be where the user data in question is too large for easy copying to kernel memory.


【注】
【1】
  对于上面的例子,就应该这样写:
  struct lstr lstr;
  memcpy(&lstr, pstr, sizeof(*pstr));
  char *buf = kmalloc( str.len);   
  memcpy(buf, lstr.s str.len);
  这个例子跟最开始说的sys_execve()那个例子相差了十万八千里,大家能领会我的意思就好了。   

评分

参与人数 1信誉积分 +5 收起 理由
nswcfd + 5 解释的非常到位。

查看全部评分

论坛徽章:
20
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16赛季CBA联赛之江苏
日期:2017-06-26 11:05:5615-16赛季CBA联赛之上海
日期:2017-07-21 18:12:5015-16赛季CBA联赛之青岛
日期:2017-09-04 17:32:0515-16赛季CBA联赛之吉林
日期:2018-03-26 10:02:16程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:512015亚冠之萨济拖拉机
日期:2015-08-17 12:21:08
发表于 2016-08-16 16:24 |显示全部楼层
本帖最后由 nswcfd 于 2016-08-16 16:24 编辑

不信任用户态传入的一切信息
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP