先分享一则有意思Q&A,来自[The FreeBSD Funnies 17.4](https://www.freebsd.org/doc/en_US.ISO8859-1/books/faq/funnies.html) 。

Where does data written to* /dev/null* go?



It goes into a special data sink in the CPU where it is converted to heat which is vented through the heatsink / fan assembly. This is why CPU cooling is increasingly important; as people get used to faster processors, they become careless with their data and more and more of it ends up in /dev/null, overheating their CPUs. If you delete /dev/null (which effectively disables the CPU data sink) your CPU may run cooler but your system will quickly become constipated with all that excess data and start to behave erratically. If you have a fast network connection you can cool down your CPU by reading data out of /dev/random and sending it off somewhere; however you run the risk of overheating your network connection and / or angering your ISP, as most of the data will end up getting converted to heat by their equipment, but they generally have good cooling, so if you do not overdo it you should be OK.

写入* /dev/null* 的数据去了哪里?

它们进入了CPU的“垃圾槽”中并被转化为热量最终由散热装置吹走了 ;)这也是为什么CPU的散热越来越重要;随着人们习惯于使用那些飞快的CPU,他们也对那些被送入 /dev/null 的数据不那么关心了——于是CPU可倒霉了。如果你删掉了/dev/null(这会马上堵住CPU的“垃圾槽”。真的可以删掉。。。),你的CPU可能会舒服点但是你的系统也会因为那些无处可去的额外数据而马上”便秘“。如果你的网挺快,也可以试试从dev/random读取数据并发到网上(后面会讲解random是如何工作的),以此来为你的CPU降温。然而这也是有风险的,毕竟网络和你的磁盘也会发热(I/O桥??),电信运营商也会抓狂——那些数据会被他们的设备转化为热量。不过他们的散热一般很好,所以偶尔搞一搞也是无妨的 ; )


下面开始正经的说一说/dev下的Pseudo-devices:

/dev/random与/dev/urandom

首先介绍一下随机数的性质分类(学过密码学的跳过吧)

  1. 随机性——不存在统计学的偏差,是完全杂乱的数列(前几天看家伟做的一道线性同余的题就是这种)。
  2. 不可预测性——不能从过去的数列推测出下一个出现的数。
  3. 不可重现性——除非将数列记录下来,否则不可能重现相同的数列。

以上三个性质中,越往下越严格。密码技术中所使用的随机数,仅仅具备随机性是不够的,至少还要具备不可预测的性质。 一般的,将以上三个性质分别称为”弱伪随机数“,”强伪随机数“,”真随机数“。

给真随机数举一个简单的例子:你不小心把一个玻璃杯打碎了,这个玻璃杯打碎过程中的破碎轨迹,破碎后碎片的分布对所有人来说都是随机的,也是当前几乎无法完全重现的。真随机数生成麻烦,一般用来做伪随机数的种子,以此来利用扩张的随机性。

为了方便计算机获得真随机数(不用你去砸杯子了),新型的X86 CPU中都内置了数字随机数生成器(Digital Random Number Generator, DRNG),并提供了RDSEED和RDRAND两条指令。这种CPU生成随机数的原料(随机信号源)来自于电路中产生的热噪声。(如果你用过GnuPG生成对称密钥,它会提醒你移动鼠标或者使用磁盘,这也是为了方便收集真随机数)。

从Linux 1.3.30开始,/dev有了random和urandom两个character special files,通过这两个接口,用户可以使用内核的随机数字发生器。

随机数字发生器会收集硬件驱动产生的背景噪声(真随机数),并把它们放在随机池里。同时发生器会时时记录下随机池里剩余的随机数。通过这个随机池,我们就可以产生很多伪随机数了。

那这两个文件有什么区别呢?

当random文件/设备被读时,它仅仅只会返回随机池里的真随机数,所以random文件适合于那些需要非常高安全性的场合——比如需要使用一次性密码本或者作为其他伪随机数生成器的种子(比如密钥生成器)。当随机池空的时候,random会暂停输出知到新的热噪声被收集到池子中。(你可以试一下cat /dev/random,待到输出停止后再移动一下鼠标或者打开一个视频,新的真随机数就会继续被输出。)

而当你读urandom文件/设备时,它不会为了等待新的噪声而暂停输出。如果池子里的真随机数不够,它会调用内核里的一个伪随机发生器来继续产生随机数。所以,在这种情况下攻击是可能的,但是到目前为止没有发现针对这个文件/设备的有效攻击。不放心的话就用random吧。

从3.16的内核开始,从urandom读的话最多能收到32MB的随机数,从random的话有512bytes(2.6以前只有340bytes)。

如果你向random或者urandom写数据的话,写入的数据会覆盖掉随机池里的真随机数,但是这不会提高安全性;也不会提高从random读出随机数的速度。

提醒一下,很多伪随机数的库函数都仅仅满足了随机性,例如C的rand,java的java.util.Random等等,以后写安全方面的代码时要注意。 (上次一航讲的一个web500就用到了弱伪随机数的可预测性)

/dev/full

这个文件通常被用来测试软件是如何处理磁盘空间不够的情况,当你向这个文件写数据时,会收到一个ENOSPC error。从该文件读的话会得到一连串NULL('\00')字符。

frank@under:~$ echo hello > /dev/full
bash: echo: write error: No space left on device

/dev/null

”talk is cheap, show me the code“,就按着kernel的源码来讲吧。

声明:

static const struct file_operations null_fops = {
.llseek = null_lseek,
.read = read_null,
.write = write_null,
.read_iter = read_iter_null,
.write_iter = write_iter_null,
.splice_write = splice_write_null,
};

只分析read_null和write_null,其他的类似。

read_null():

static ssize_t read_null(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
return 0;
}

可以看到,如果从null里面读取数据的话就是返回有符号整型”0“,也不会处理用户给他的file指针或者buffer指针和其他数据。,通常情况下这就是一个EOF——你得不到任何数据。

write_null():

static ssize_t write_null(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
return count;
}

这个也是”毫无用处“,仅仅只是返回我们告诉null我们想要写入文件的字节大小(也是有符号整型)。通过这种通用的”写入成功“返回方式,使得一般的软件将流定向到null可以收到”正确写入“的消息,猜想这会方便软件无用流的编写。

/dev/zero

上面说到读null会得到一个有符号整型“0”。那么zero呢?你会得到一连串的NULL字符('\0')(说明处理了文件指针)。

$ dd if=/dev/null of=file count=10
0+0 records in
0+0 records out
0 bytes (0 B) copied, 0.000276193 s, 0.0 kB/s $ dd if=/dev/zero of=file count=10
10+0 records in
10+0 records out
5120 bytes (5.1 kB) copied, 0.00090775 s, 5.6 MB/s

声明:

static const struct file_operations zero_fops = {
.llseek = zero_lseek,
.write = write_zero,
.read_iter = read_iter_zero,
.write_iter = write_iter_zero,
.mmap = mmap_zero,
.get_unmapped_area = get_unmapped_area_zero,
#ifndef CONFIG_MMU
.mmap_capabilities = zero_mmap_capabilities,
#endif
};

仅分析一下zero_lseek和write_zero。

zero_lseek:

#define zero_lseek	null_lseek

/*
* Special lseek() function for /dev/null and /dev/zero. Most notably, you
* can fopen() both devices with "a" now. This was previously impossible.
* -- SRB.
*/
static loff_t null_lseek(struct file *file, loff_t offset, int orig)
{
return file->f_pos = 0;
}

f_pos定义在file结构体(定义在<linux/fs.h>),表示文件当前的读写位置,因此现在可以appending的方式打开这两个特殊文件了。

write_zero:

#define write_zero	write_null

static ssize_t write_null(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
return count;
}

这就很有意思了,看起来向zero写文件和null应该是一个效果。。。(不过这么写代码的话别人会觉得奇怪吧)

看来null和zero很像两兄弟,不过传统上还是建议把null当成一个”只写“的黑洞,把zero当成一个只读的NULL字符(‘\0’)产生器吧。

ps:

  1. 大家可能会对null返回的整型“0“和zero返回的NULL字符 '\0'的区别感到疑惑,可以参考stackoverflow上一篇文章
  2. /dev/zero 通常被用来创建swap。
  3. 详细的文档可以man full、urandom、zero等。

happy hacking!

参考:

  1. https://en.wikipedia.org/wiki//dev/random
  2. https://en.wikipedia.org/wiki/Null_device
  3. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/char/mem.c?id=refs/tags/v4.9-rc3#n774
  4. https://stackoverflow.com/questions/3690273/did-i-understand-dev-urandom
  5. https://www.reddit.com/r/linuxquestions/comments/5b5wq5/eli5_how_does_devnull_work/
  6. https://unix.stackexchange.com/questions/63238/purpose-of-dev-zero
  7. https://unix.stackexchange.com/questions/254384/difference-between-dev-null-and-dev-zero
  8. 《图解密码学》第三版
  9. Linux Programmer's Manual

Pseudo-devices On GNU/Linux的更多相关文章

  1. Gnu/Linux的学习探索

    1.Gnu/Linux是一个基于POSIX和UNIX的多用户多任务 支持多线程多CPU的类UNIX的操作系统. 继承了UNIX以网络为核心的设计思想 是性能稳定的多用户网络操作系统. 1991年10月 ...

  2. GNU Linux启动时文件系统mountall挂载出错问题的处理

    /********************************************************************* * Author  : Samson * Date    ...

  3. (转)完全用GNU/Linux工作 by 王珢

    完全用GNU/Linux工作 王珢      (看完这篇博文,非常喜欢王珢的这篇博客,也我坚定了学gnu/linux的决心,并努力去按照国外的计算机思维模式去学习编程提高自己.看完这篇文章令我热血沸腾 ...

  4. GNU/Linux复习笔记(1)

    第一次接触GNU/Linux还是大四上学期实习的那两个月在window里装了 个虚拟机玩红帽的系统,那段时间稍微学了一点命令就不玩了.后来大四下学期认识了王总,装了双系统,那段时间又对linux有了进 ...

  5. 下一代GNU/Linux显示服务Wayland 1.12正式发布

    导读 最近,Bryce Harrington很高兴地宣布了“面向GNU/Linux操作系统的Wayland 1.12.0显示服务已正式发布”的消息.与它一同到来的,还有Weston 1.12.0合成器 ...

  6. ZFS(一):ZFS在Debian GNU/Linux上的安装

    以下内容翻译自https://pthree.org/2012/04/17/install-zfs-on-debian-gnulinux/,并附有原文,由于是第一次翻译,如有任何翻译不恰当之处,欢迎指出 ...

  7. debian7 请把标有“Debian GNU/Linux 7.1.0 _Wheezy_ - Official amd64 DVD Binary-1 20130615-23:06”的盘片插入驱动器“/media/cdrom/”再按回车键

    有时候,在通过apt-get install 安装软件的时候,会出现: 更换介质:请把标有“Debian GNU/Linux 7.1.0 _Wheezy_ - Official amd64 DVD B ...

  8. 完全用 GNU/Linux 工作(转)

    转自:http://www.chinaunix.net/old_jh/4/16102.html 看到一半,实在太长,但已觉得很好,转来分享一下. 完全用 GNU/Linux 工作 - 摈弃 Windo ...

  9. 世纪大争论:Linux还是GNU/Linux?

    我们在网上已经习惯用“Linux”来称呼Linux操作系统了,然而,偶尔也用“GNU/Linux”来称呼和指代同样的操作系统和软件.同时人们也在争论这两种称呼哪个更合适. 本文将不会选边站队,仅力图向 ...

  10. GNU/Linux Distribution Timeline v12.10

    GNU/Linux Distribution Timeline v12.10 原图下载 GNULinux Distribution Timeline 12.10.png GNU/Linux Distr ...

随机推荐

  1. php 例子 如何转换ISO8601为 utc时间

    //firstpowertime "2017-01-02T13:22:22" 获取时间$firstpowertime=$list[$i]['firstpowertime'];//判 ...

  2. 基础教程:ASP.NET Core 2.0 MVC筛选器

    问题 如何在ASP.NET Core的MVC请求管道之前和之后运行代码. 解 在一个空的项目中,更新 Startup 类以添加MVC的服务和中间件. publicvoid ConfigureServi ...

  3. 教你如何实现微信小程序与.net core应用服务端的无状态身份验证

    随着.net core2的发布,越来越多人使用.net core2开发各种应用服务端,下面我就结合自己最近开发的一款小程序,给大家分享下,怎么使用小程序登录后,小程序与服务端交互的权限控制. .net ...

  4. DNS:域名系统

    概述: DNS的作用在于将域名转换为对应的IP地址. DNS名字空间和UNIX文件系统相似,也是树形结构.以"."结尾的域名称为FQDN(Full Qualified Domain ...

  5. python3学习笔记(2)

    一.面向对象(初识)由类和方法组成,类里面封装了很多功能,根据这个类,可以创建一个这个类的对象,即对象是根据这个类创建的,以后这个对象要使用某个功能的时候就从这个类里面的找.例:str -功能一 -功 ...

  6. Vue-cli创建项目从单页面到多页面2-history模式

    之前讲过怎样将vue-cli创建的项目改造成多页面(vue-cli创建项目从单页面到多页面),今天说一下怎样在多页面的前提下使用history模式. 如何使用history模式 因为vue默认的has ...

  7. SurfaceView 及相关概念

    ============================================================= SurfaceView=========================== ...

  8. [对smartMenu.js改进] 解决右键菜单栏在边缘弹出后,移出视图区域无法操作的问题

    当用户在视图边缘(如右下角)右键召唤菜单栏的时候,菜单仍然从选中元素的右下角弹出,这时二级菜单栏一般都离开了视图区域,用户无法进一步操作. 这个问题挺常见的,原作者的留言板: 但是作者应该是已经不再维 ...

  9. 开始你的第一个npm脚本工具

    在实际开发中,一般刚开始一个项目或者刚接手一个项目,我们会运行 npm install 下载安装所有依赖, 在实际开发中,可能也会使用各种命令行-- 来提高我们开发的效率. 与它相处了这么久,你真的了 ...

  10. SaltStack 部署案例 02

    远程执行 salt '*' state.sls apache '*':代表所有主机 state.sls :是一个模块 apache : 状态 ,表示需要部署的内容,后缀.sls YAML:三板斧 1. ...