正文
凭借多年经验,张银奎很快看出这个长地址中包含了很多可读的 ASCII 字符。稍作解释一下,内存地址的数据是由程序执行的代码或存储的数据决定的,它们往往是二进制格式,不容易直接读取为有意义的文本字符串。倘若出现了这种情况,可能会暴露程序的漏洞。攻击者可以利用这些漏洞进行恶意攻击,如通过缓冲区溢出注入恶意代码、执行任意代码、或窃取敏感数据。
为了搞清楚其中到底发生了什么,张银奎用 windbg 的 .formats 命令转换后,得到了以下结果:错误地址刚好对应的是「 :reldni」这 8 个字符。将这 8 个字符的顺序调整后,就是"indler: "(注意冒号后面还有一个空格)——为了方便描述,暂且把该漏洞称为 indler 漏洞。
0:000> .formats 203a72656c646e69
Evaluate expression:
Hex: 203a7265`6c646e69
Decimal: 2322294337798696553
Octal: 0200723446255431067151
Binary: 00100000 00111010 01110010 01100101 01101100 01100100 01101110 01101001
Chars: :reldni
Time: Wed Jan 23 00:02:59.869 8960 (UTC + 8:00)
Float: low 1.10463e+027 high 1.57927e-019
Double: 1.9725e-153
据张银奎介绍,这个 oops 是随机的,而根据 oops 提供的函数地址,发生崩溃的内核函数名叫 sysfs_file_ops,源代码如下:
static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
{
struct kobject *kobj = kn->parent->priv;
if (kn->flags & KERNFS_LOCKDEP)
lockdep_assert_held(kn);
return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
}
对此,张银奎笃定:“对于这样的内存溢出问题,这肯定不是第一现场。这只是一个受害者。”
为了找到这个“第一现场”,即造成内存溢出的元凶,
张银奎及其
内部团队试了很多办法都不能有效定位,张银奎决定采用最直接的方式:用集成在 Linux 内核中的内存错误检测工具 KASAN(Kernel Address Sanitizer),这款工具由 Google 工程师开发。
团队成员把启用了 KASAN 的内核成功运行后,很快就找到了一个内存越界写(又称为缓冲区溢出)。张银奎仔细查看了内核消息: