bug分析:内核工具链更新到2024-07-23后,系统启动报错EFault的问题。

相关issue

问题分析

一开始以为是linkme库的问题,就去调整了内核编译的RUSTFLAGS,额外在env.mk里面添加了

export RUSTFLAGS := -C link-args=-znostart-stop-gc
export RUSTDOCFLAGS := -C link-args=-znostart-stop-gc

结果发现仍然能偶尔复现这个bug。

打印日志发现在内核do_execve函数里面,克隆envp数组的时候出错,envp的值很不正常。原本预期应该是PATH=/bin,结果显示的是
image

于是看了一下内核拷贝字符串的代码:


https://code.dragonos.org.cn/xref/DragonOS/kernel/src/syscall/user_access.rs?r=2eab6dd743e94a86a685f1f3c01e599adf86610a&mo=1452&fi=73#73

发现是用的String而不是CString。因此猜测是FFI的问题:不同Rust版本之间的String的解析算法不一致。

问题1

那么,另一端是谁呢?找了找之后,发现是novashell创建的/etc/profile文件。于是去找novashell的代码,发现在写入文件的时候并没有转为cstring,而是直接写入了&str的字节到文件里面(我趣,这样写的话确实有问题啊)


https://code.dragonos.org.cn/xref/NovaShell/src/env.rs?r=001f2a751fdbbe2ca1054f72891585ac8ce77932#21

并且在读取、执行命令、写历史命令的时候,novashell也都是完全纯字节操作,而没有使用rust的char、&str这些,应该是因为这样而导致了错误。

问题2

内核处理路径的时候,用的是String,并且直接把String转字节写到了用户栈上。因此也需要进行修改。

可能de修改方式

  • 作为应急,我将把Novashell的工具链版本临时升级到2024-07-23
  • 后续:需要把上述bug真正解决掉,并且验证使用2023-08-15的工具链的Novashell依然能正常运行在新的内核上。
  • 修改内核,写用户栈的地方,以及涉及到FFI的,改为CString

@MemoryShore

2 个赞


PR#864 中写用户栈的函数中,单引号被修改为双引号,导致传入的参数由[u8]变为[[u8]],压入栈的数据变成了一个指向’\0’的指针。
打印日志查看写入大小:

大小为8说明确实压入了一个指针
image
正确情况:
image
envp的值也正常
image

错误日志中envp的值"PATH=/"后面的乱码是’\0’边界丢失导致的错误读取。
@longjin

1 个赞

确实噢!这里我搞错了,我再检查一下

这个pr后来在合并主线之前,已经更新修掉了这个地方了。

你说哪个pr,PR#864

对的,是pr 864


没有啊,我看pr里是没改的

你pull一下就有了。这个地方在合入主线的时候已经改掉了。

哦。记错数字了,不是864,我昨天那个合入的改了。

哦,那个我知道。我昨天找到问题的时候还想提个pr的,才发现你已经全改完了哈哈哈

哈哈哈xs哈哈哈