免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2972 | 回复: 9
打印 上一主题 下一主题

[Linux] linux打开文件的fd值不连续,而且有时会被篡改 [复制链接]

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
1 [报告]
发表于 2016-09-13 17:42 |只看该作者
回复 1# pengwater

我的应用程序打开了几个文件,但是fd的数值有时并不是连续的


正常情况,你程序链接的库也可能打开关闭文件。

而且有时候fd所指向的文件会被篡改


不是篡改,不过是文件描述符被重用而已。

论坛徽章:
0
2 [报告]
发表于 2016-09-17 11:28 |只看该作者
回复 2# MMMIX
嗯,是的,不过确实很奇怪,这个程序启动初始化的过程中,打开了一些文件,但后面没有再关闭,而是一直使用,应该不存在fd重用的情况,只是后面再打开一个文件时,它没有另外再分配一个fd值,而是直接使用了已有的值,百思不得其解。
是不是跟子进程有关,因为这个程序初始化的时候,创建了很多子进程,子进程具备父进程一样的文件描述符,会不会影响父进程的文件描述符列表?

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
3 [报告]
发表于 2016-09-17 13:16 |只看该作者
回复 3# pengwater

这个程序启动初始化的过程中,打开了一些文件,但后面没有再关闭,而是一直使用,应该不存在fd重用的情况,

不要想当然。用 strace 跟踪一下。


因为这个程序初始化的时候,创建了很多子进程,子进程具备父进程一样的文件描述符,会不会影响父进程的文件描述符列表?

不会。文件描述符每个进程各有一套。

论坛徽章:
0
4 [报告]
发表于 2016-09-17 22:05 |只看该作者
本帖最后由 pengwater 于 2016-09-17 22:08 编辑

回复 4# MMMIX
嗯,我修改代码测试过,父进程只留下初始化和创建子进程的部分,其他的注掉,也还是会出现这个问题。
不过,我还是试下strace。

论坛徽章:
0
5 [报告]
发表于 2016-09-18 16:08 |只看该作者
回复 4# MMMIX
问题定位到了,也知道原因了,这个fd的值被篡改是因为syslog。步骤如下:
1》首先我的这个程序是守护进程,他在变为守护进程前,有调用openlog以及syslog来打印日志。但没有调用closelog。

2》变为守护进程后,他调用如下代码,关掉所有的文件句柄:
  1.         max_fd = sysconf (_SC_OPEN_MAX);
  2.         for (i = 0; i < max_fd; i++)
  3.         close (i);
复制代码
同时将fd为0,1,2的重新分配
  1.         if ((i = open("/dev/null", O_RDWR)) >= 0) {
  2.                 while (0 <= i && i <= 2)
  3.                 i = dup(i);
  4.                 if (i >= 0)
  5.                 close(i);
  6.         }
复制代码
3》打开一个watchdog的文件,此时,fd的值变为3,并指向watchdog

4》再次调用openlog,进行日志打印,此时fd为3的值的指向被篡改。指向syslog的socket

解决办法:
在第一步中,在这个进程变为守护进程前,先调用closelog将syslog打开的文件描述符关掉,后面就不会有这个问题了。

疑问:
问什么调用系统的close并不能关掉syslog,而必须要使用closelog才可以?
而且就算关闭不成功,这个fd的值也不应该重新被分配啊?
不知大神可否解答一二,谢谢。

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
6 [报告]
发表于 2016-09-18 21:17 |只看该作者
回复 6# pengwater

首先我的这个程序是守护进程,他在变为守护进程前,有调用openlog以及syslog来打印日志。但没有调用closelog。


这确实是原因,调用 closelog 也确实是解决的办法。

再次调用openlog,进行日志打印,此时fd为3的值的指向被篡改。指向syslog的socket


在 glibc 实现的 openlog/syslog 中,它会用内部变量(LogFile)记录其使用的 socket 对应的 fd,同时记录是否已经连接过(connected)。当你调用 syslog 之后,glibc 的内部状态就是 LogFile 和 connected 都是有效值,那么下次再调用 syslog 的时候它就是直接 send 日志记录到对应的 socket。可是在这之前,你自己把所有的 fd 手工关闭了一遍,导致那个 LogFile 已经无效,那么第二次 syslog 中的 send 会失败。这时候它会尝试把 LogFile 关闭,然后重新打开。

对于你的情况:

1. 在变为守护进程之前,LogFile 的值为3,对应一个socket;
2. 变为守护进程之后,LogFile 值仍为3,但不对应socket;
3. 调用 syslog,发现 send 失败,关闭 3,重新建立 socket (对应 fd 仍为 3)。

论坛徽章:
0
7 [报告]
发表于 2016-09-19 12:30 |只看该作者
回复 7# MMMIX

谢谢,你的回答,完美解释了出现的问题,还有一个问题,为什么我在网上搜不到LogFile 之类的信息,
请问大神平时都是怎么搜索的,或者说有没有书可以推荐一下,谢谢。

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
8 [报告]
发表于 2016-09-19 17:44 |只看该作者
回复 8# pengwater

为什么我在网上搜不到LogFile 之类的信息,



LogFile 是 glibc 实现的 syslog 中用到的一个变量,我直接看的代码。

论坛徽章:
0
9 [报告]
发表于 2016-09-26 09:24 |只看该作者
回复 9# MMMIX

哦,好的,谢谢。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP