漏洞编号和级别
CVE 编号:CVE-2019-8912,危险级别:严重,CVSS 分值:9.8
影响版本
Linux 2 .6 ~ Linux 4.20.11
Red Hat Enterprise Linux 7,Package: kernel-alt
Debian,Release:Jessie,Version:3.16.56-1+deb8u1
Debian,Release:Jessie (security),Version:3.16.56-1
Debian,Release:stretch,Version:4.9.144-3
Debian,Release:stretch (security),Version:4.9.110-3+deb9u6
Debian,Release:buster,Version:4.19.16-1
Debian,Release:sid,Version:4.19.20-1
漏洞概述
近日,Linux git 中发布一个 commit 补丁,该补丁对应的漏洞是一个本地提权漏洞 CVE-2019-8912,漏洞影响范围较广。根据 git 中的 commit 信息可知,该漏洞出现在内核 'crypto/af_alg.c'中的af_alg_release 函数中,可以通过 sockfs_setattr 函数触发,漏洞类型是 use after free,可以导致本地代码执行进行权限提升。
Linux Crypto 模块简介Linux 内核从版本2.5 开始引入了加密机制,为内核提供加密功 能,应用包括:硬件加密设备驱动、内核代码签名、硬件随机数生成器、文件系统加密等。 从版本 2.6.6 之后,内核源码提供了丰富的密码学算法支持,并可以通过配置编译选项将加 密算法作为模块编入内核。内核编译配置如下图所示:
但是该加密功能提供的 API 接口只能在内核层进行使用,用户层无法调用。2010 年, 有位维护者向Linux Crypto 维护组提交了一份 Crypato API 用户接口,类似于netlink,基 于socket 进行通信,便于用户层访问内核加密子系统。功能实现代码在文件crypto/af_alg.c 中。
漏洞验证
漏洞存在于 crypto 模块中的 af_alg_release()函数中。af_alg_release()函数在进行对象 释放时,未将对象置空。对应commit:9060cb719e61b685ec0102574e10337fa5f445ea 补 丁代码如下,补丁添加了一行代码:sock->sk = NULL;
在未添加补丁之前,如果该 sock->sk 引用计数是1,当调用sock_put()进行释放后没有 置空,就直接返回,会产生一个 sock->sk 悬挂指针。
为了分析这个漏洞的前因后果,先分析下相关的socket 代码。对每个新创建的socket, Linux 内核都将在 sockfs 中创建一个新的 inode。Sockfs_*系列函数就是用来操作 sockfs 文 件系统的。Sockfs_setattr()函数就是设置 socket 文件属性的。在 net/socket.c 文件中 sockfs_setattr()函数将会使用sock->sk 对象。
根据提交的commit:9060cb719e61b685ec0102574e10337fa5f445ea 细节可知,在该 漏洞披露之前,Linux 已经修复了sock_close()和sockfs_setattr()之间的条件竞争漏洞,对应 commit 为 6d8c50dcb029872b298eea68cc6209c866fd3e14,具体先看下 sockfs_setattr() 函数中的补丁。补丁代码如下:
行 544,首先判断 sock->sk 是否为空,如果不为空,行 545 再将用户层传进来的 iattr->ia_uid 赋值为sock->sk->sk_uid。然后看sock_close ()函数中的补丁。补丁代码如下:
行1186,替换成了新函数__sock_release(),该函数多了一个参数inode。__sock_release() 函数实现如下:
行 601,对 inode 进行判断,如果不为空,然后调用 inode_lock()函数对其进行上锁。 其实该 inode 本身和要进行释放的 socket 对象是对应的。行 603,调用 ops 中 release()函 数进行释放操作。这个ops 中release()函数只是一个函数指针,最终会根据用户注册哪种套 接字类型决定。行 604,再次判断 inode 是否为空,如果不为空,再进行解锁。通过对 inode 加锁,防止在对socket 对象释放时进行其他操作。
从 commit :6d8c50dcb029872b298eea68cc6209c866fd3e14 提供的细节可知, sock_close()函数和 sockfs_setattr()函数之间的条件竞争可以通过用户层 fchownat()函数引 发。根据man 手册可知,该函数是用于设置文件属性的,例如 uid 和gid,在内核中对应的 sockfs_setattr()函数,如下图所示:
细节中描述,该函数不会保持文件 fd 的引用计数,这也是导致存在条件竞争的原因。 根据前文可知,sockfs_setattr()函数其实就是设置 UID 才操作sock->sk 对象的。
如果再继续向前追溯的话,从 commit:86741ec25462e4c8cdce6df2f41ead05568c7d5e 提供的细节可知UID 的来龙去脉。该补丁提交于2016 年。由于socket 协议中的结构体struct sock 在大多时候都是和用户层的 sockets 一一映射的,sockets 对应的内核结构体为 struct socket。考虑到方便操作,便通过向 struct sock 添加一个sk_uid 字段来简化对struct socket中的UID 的匹配,也因此添加了一个关键函数。如下图所示:
由此可知,本来存在于 sock_close()和sockfs_setattr 之间的条件竞争已经被修复,由于 crypto/af_alg.c 中af_alg_release()函数没有将释放后的 sock->sk 及时置空,导致前面所做的 安全补丁全部失效。
修复建议
该漏洞补丁已经给出,请及时升级到最新版本。https://github.com/torvalds/linux/co mmit/9060cb719e61b685ec0102574e10337fa5f445ea
参考链接
https://access.redhat.com/security/cve/cve-2019-8912
https://nvd.nist.gov/vuln/detail/CVE-2019-8912
https://mp.weixin.qq.com/s?__biz=MzAwNTI1NDI3MQ==&mid=2649613887&idx=1 &sn=04b441a67101ef2463e264336b7ccc28&chksm=83063b2fb471b239f308e8906fabb5 1a768b3f492b1f88ed4ab259ca062c1ff1e2bcefaaed29&mpshare=1&scene=1&srcid=0225 kHPQ674XTCwBWcOAH1ef#rd
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。