微信号:programmer_club

介绍:程序员第一自媒体,与你探讨码农人生路上遇到的各类泛技术话题,定期为你推荐码农人生思考、感悟以及启迪!

C 的表达式 x == x,何时为假?!

2016-11-21 21:58 围城莫


……………………我在想,也许是你们前几天出去玩去了,也许你们相互之间,这么久了,应该差不多都认识了。


所以前几天的数据应该是你们集体爆炸了…………



好了,我们来看今天这道菜,不……这道题。


C的表达式 x == x,何时为假呢?


即下面的代码:


什么时候输出为”Not equal”呢?看上去很有趣吧。x与自己比较,怎么会不等呢?


这个问题也是最近才发现的,而最终的解决方案是判断x == x何时为false。


就是下面的代码:


编译gcc -g -Wall test.c,看执行结果:


最后两行的输出是不是有点surprise啊。

下面先简单解释一下:

1. 当float x = 0xffffffff:这时将整数赋给一个浮点数,由于float和int的size都是4,而浮点数的存储格式与整数不同,其需要将某些位作为小数位,所以float的范围要小于int的范围。因此这里牵涉到了整数转换浮点的规定——这个大家可以查一下资料。因为这个转换其实很少用到,我也就不查了。但是总之,这个转换是合法的。但是最终的值很可能不是你想要的结果——尤其是当浮点的范围小于整数的范围时。

2. 即使整数转换成浮点,数值再不是期望值,但它也一定是一个合法的浮点数值。所以第一个x == x,一定为true,且x不是大于0,就是小于0。这时x存的并不是0xffffffff。

3. 当使用memcpy将0xff填充到x的地址时,这时x存的保证为0xffffffff。结果很遗憾,这个不是一个合法的float的值。因此奇怪的现象发生了,x并不等于x。原因则是由cpu的浮点指令相关,有兴趣的同学可以搜索一下。

4. 作为一个非法的float值,当它与其它任何数值比较时,都会返回false。这也就造成了,后面惊奇的结果,x既不大于等于0,也不小于0。

总结一下:一般来说,浮点类型很少被使用,也不应该在程序中鼓励使用。不仅其效率比整数低,且由于浮点类型特殊的存储格式,很容易造成一些意想不到的错误。如果真的无法避免时,一定要小心小心再小心。特别要注意今天的主题,这种非法的浮点值,会导致任何比较判断都失败。而判断这种浮点值的方法也很简单,如果x != x,那么该浮点即为非法浮点值。

有的朋友说是不同类型的比较。固然不同类型的比较会容易引起问题,但是这里并不是不同类型比较造成的。将文中的0换成浮点类型0.0,结果不变。重点是在于非法的浮点值。

另外,还有朋友认为这是由于示例中使用memcpy来填充浮点导致的问题。其实这里我只是选用这种方法而已。还有其它方法可以导致产生这种浮点的exception,即NaN。也许其它方法更自然。这里我选用memcpy只是为了对比,将0xffffffff直接赋给浮点这种情况。


…………………………………………………………………………………………………………………

东西说完,我们来讲讲最近,

Linux 漏洞的事,

就是长按回车键70秒即可获得root权限的这个漏洞。


漏洞来源

这个安全问题来源于Cryptsetup存在的一个漏洞(CVE-2016-4484)。Cryptsetup是在Linux统一密钥设置(Linux Unified Key Setup, LUKS)中用来加密磁盘的软件,而LUKS则是Linux系统中标准的磁盘加密。

漏洞其实是出现在系统后Cryptsetup处理密码输入错误的时候,它会允许用户多次重试输入密码。而当用户输入错误93次后,程序就会给用户一个带root权限的shell(busybox)。

也就是说,如果你重复93次输错密码,或者持续按回车键大概70秒,你就能够获得root initramfs (initial RAM filesystem) shell。获取shell之后,你就可以复制、修改或者破坏整个硬盘,或者也可以使用网络传输数据。

漏洞能被远程利用

西班牙安全研究员Hector Marco和Ismael Ripoll发现了这一漏洞,影响范围覆盖几乎所有的Linux发行版,包括Debian, Ubuntu, Fedora, Red Hat Enterprise Linux (RHEL)和SUSE。

研究人员在今年奥地利维也纳举行的DeepSec会议上演示了细节:

“黑客可以从受影响系统中获取root initramfs shell。并且漏洞的成功率非常高,因为他不依赖某个特定的系统或者某个配置……这个漏洞在图书馆、ATM机、机场、实验室等场景下特别有用,因为在这些场景下,开机的过程受到(加密)保护,而我们只有键盘/鼠标。”

看到这里,你可能会认为漏洞只能在攻击者有物理接触的情况下才有可能发生。但实际上,漏洞也可以被远程触发。如果你使用的是基于linux的云服务,就可以在没有物理接触的条件下利用漏洞。

漏洞到底有多严重

值得注意的是,攻击者无法利用这个漏洞来获取加密磁盘的内容,但能进行下面的这些操作:

权限提升:

由于boot分区一般都是不加密的,因此利用漏洞黑客可以用SetUID存储一个可执行文件,然后再用本地用户身份执行进行提权。

攻击者也可以替换内核和initrd镜像。

信息泄露:

虽然攻击者无法直接读取加密的磁盘,但他能做的事还是很多的。比如,他可以把磁盘复制到外部设备,之后进行暴力破解,

DoS攻击:

黑客可以删除磁盘上的内容。

这个漏洞的影响范围包括Debian, Ubuntu, Fedora和其他一些Linux发行版本。Arch Linux和Solus用户不受影响。

解决方案

尽管漏洞能轻易触发并且影响范围大,但它的修复方案也异常简单:

首先,在LUKS密码提示窗处按压回车键70秒,检查系统是否存在漏洞。

如果存在漏洞,检查下你所使用的Linux是否发布了补丁。

如果官方没有发布补丁,你可以自行修改cryptroot文件:



关于…………这个漏洞是怎么被发现的。


大概……


可能……


也许……


是因为他家的猫……



什么鬼理由!!?


 
程序员之家 更多文章 C 的表达式 x == x,何时为假?! 计算机的这些原理你都不知道? Android 混淆怎么玩,你玩对了吗? Linux系统出问题之后,你会几种恢复方法? CSS中的这些技巧你还不知道,那你还装什么逼?
猜您喜欢 在VS2010资源文件中导入电脑图片的注意事项 大宝推荐设计师阅读书单,历史上最值得你分享的推荐干货 企业安全:为何总有修不完的漏洞? Docker为整个软件生命周期提供安全保障 深度剖析容器之“状态”