前段时间有个同事问我说,他 cat /dev/null有数据。这个颠覆大家认知的问题最终却是个小问题。
我们来看/dev/null的操作函数:
static const struct memdev {
const char *name;
umode_t mode;
const struct file_operations *fops;
struct backing_dev_info *dev_info;
} devlist[] = {
[1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi },
#ifdef CONFIG_DEVKMEM
[2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi },
#endif
[3] = { "null", 0666, &null_fops, NULL },-------------操作/dev/null的ops
#ifdef CONFIG_DEVPORT
[4] = { "port", 0, &port_fops, NULL },
#endif
[5] = { "zero", 0666, &zero_fops, &zero_bdi },
[7] = { "full", 0666, &full_fops, NULL },
[8] = { "random", 0666, &random_fops, NULL },
[9] = { "urandom", 0666, &urandom_fops, NULL },
#ifdef CONFIG_PRINTK
[11] = { "kmsg", 0644, &kmsg_fops, NULL },
#endif
#ifdef CONFIG_CRASH_DUMP
[12] = { "oldmem", 0, &oldmem_fops, NULL },
#endif
};
static const struct file_operations null_fops = {
.llseek = null_lseek,
.read = read_null,
.write = write_null,
.aio_read = aio_read_null,
.aio_write = aio_write_null,
.splice_write = splice_write_null,
};
很显然,我们应该看read_null和write_null的实现,
static ssize_t read_null(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
return 0;
}
static ssize_t write_null(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
return count;
}
很显然,不应该有任何内容存在才对,因为往/dev/null里面写的时候,直接return count,读的时候,啥都不返回,那为什么会有数据呢?
再仔细一看,这个/dev/null有点蹊跷:
[root@centos7 stap_all]# ls -alrt /dev/null
rw-r-r-. 1 root root 1, 3 7月 6 09:35 /dev/null
而正常的/dev/null的权限是:
[root@localhost ~]# ls -alrt /dev/null
crw-rw-rw- 1 root root 1, 3 Aug 1 17:51 /dev/null
一开始想不明白,然后我手贱删除/dev/null再touch /dev/null,却复现了这个问题。
[root@centos7 ~]# rm /dev/null && touch /dev/null
rm:是否删除字符特殊文件 "/dev/null"?y
[root@centos7 ~]# ls -alrt /dev/null
-rw-r--r--. 1 root root 157 8月 7 20:00 /dev/null
然后再cat一下:
[root@centos7 ~]# cat /dev/null
--2018-08-07 20:00:50-- http://10.47.242.88:3220/getdevid_type
正在连接 10.47.242.88:3220... 失败:没有到主机的路由。
。
好吧,其实就是因为某个进程做了跟我类似的动作导致的。
接下来,使用audit来抓这个进程就ok了。