d驱动进入林操
通过成功把内核Linux
模块移植
到D语言
,来证明在Linux
内核中使用现代语言
的可行性.移植了virtio
框架的virtio_net
网络驱动.
设计和实现
依赖指定D语言
技术,以改进Linux
内核驱动.由于D语言提供的安全优势
,性能成本
可忽略不计.
提供了一种内核Linux
移植模块到D语言
的方法.通过成功移植证明,该方法可用来移植
其他Linux
内核模块.
使用D移植和增强内核模块的方法
A
.在Linux
内核中引入D代码
有两种方法可向Linux
内核添加新功能:
(1)
,直接静态链接
新目标文件
到内核核心
(2)
,按可加载
模块编译
代码,并按需链接
到内核中.
一般经验
是按可加载
模块添加新功能
.优点
是保持内核代码
尽量干净,且更易维护.此外,还允许更大程度上定制
,因为可按需加载和卸载
必要功能.此外,使可信计算基础(TCB)
保持较小
,并降低了整体对入侵的敏感性,从而提高了安全性
.
无论必须构建哪种类型
模块,内核
构建系统都假定源文件
是用C编写的.因此,无法成功编译
另一种语言编写
的源文件,并且生成
将失败.对D
语言也一样.同时,模块入口和出口点函数
必须用C语言,以便内核
可访问它们.总之,移植模块
到D语言
需要:
1,用D
编写相应源码
2,按C接口
函数提供模块入口
3,更新构建
系统文件,来链接新模块
第二个要求,必须在内核
和D编写的模块
间实现C接口
.此C接口
应仅包含入口
函数和无法移植
到D
的函数宏和函数绑定
.接口表明新功能至少需要两个源码
文件:一个是C格式
,另一个是D格式
.因此,必须相应编写Linux
内核构建
文件中的指令
,来满足第三个要求.
内核构建
系统假定它正在处理C源文件
,并试相应构建
目标文件.幸好,构建系统
还按依赖项(a)
接受预构建
的对象二进制文件,它(a
)与它构建
的目标文件链接
来创建内核模块
.
这是通过从module-file.o
更改依赖项名
为module-file.o_shipped
来完成的.要链接D目标
文件到内核模块
,必须先编译D源文件
,并使其名字带有.o_shipped
后缀.
源文件可由带-betterC
开关的D编译器
编译.可选择使用基于LLVM
的(LDC)
编译器和基于GCC
的(GDC)
编译器.独立
编译后,把它们传递到内核
构建系统,并与其他C对象
链接在一起.
B
.移植内核模块
移植
内核模块,包括测试
和基准测试
,有5个步骤:
1,移植模块内使用的数据结构
.确保每个新移植构
的大小
和布局
与原始构的相同.
2,一次一个
函数的移植模块实现
.每新移植
函数后检查
模块功能.
3,执行
第一组基准:求值
模块行为.比较模块
的D和C
版本.
4,在代码中,引入D惯用构造和功能
.添加检查边界
,用元编程
替换宏和转换
,添加@safe,@trusted
和其他有用的功能.
5,执行第二组
基准:求值添加的惯用代码
效果.比较模块的惯用D
和粗略
的D版本.比较模块的D和C
版本.
第一步,移植
数据结构最复杂.在内核
模块中,一些在模块
代码中定义构
,而其他构
则来自不同的头文件
.为了可生成可从C程序
传递和接收构
的对象,D
编译器(与其他编译器一样)必须知道这些C构
的内存布局
.表明要移植
它们到D
.
可用是编译器包装器
的dpp
来移植,它解析扩展叫.dpp
的D源文件,并原位
扩展遇见的#include
指令,翻译所有C
或C++
符号为D
,然后传递结果给D编译器".但是,头文件中的高级
分支或递归
包含可能会导致不能用dpp
.
此时,有两种选择:
(1)
手动移植数据结构
(2)
使dpp
与Linux
内核头文件
一起使用.
这里选择了前者.
无论移植
方法如何,移植到D
的每个新构
的大小和布局都应与C
中原始构的相同.可比较D
中字段
偏移与C对应项
偏移来轻松检测大小或布局不匹配
.
在D中,可用.offsetof
字段属性取字段
的偏移.在Linux
内核中,可用offsetof(TYPE,MEMBER)
宏来取它.
要考虑区别是空构
大小:空构
的C核
大小为0
,而在D
中,该构大小为1字节
.可用D强大的编译时自省
来解决该问题.此外,应该考虑D语言
不隐式支持位域
事实.但是,使用std.bitmanip.bitfields
库类型可实现相同的功能.
在移植实现时,必须使用extern(C)
链接属性注解从C调用的D函数
.该属性指示
链接器使用C命名和调用约定
,而不是D的
.在D标头
声明用C
实现的函数
时,也必须同样注解.
在D中,不变
的全局变量放在(TLS)
线本存储中,而在C
中,它们放在全局存储
中.要实现函数奇偶校验
,必须使用__gshared
属性注解D全局变量
.
此外,在D中,const
限定符是可传递
的,表明以递归方式
应用限定符到类型
的每个子组件
.
原语
数据类型的等价性也可能有问题.
在内核模块
中,并非所有使用或实现
的功能
都值得移植.某些宏
就是如此,它们反之调用其他宏
等,并且深深
植根于内核代码
中.
使用扩展了标准C语言
的GCC
功能的某些内核函数
同样,且可能无法在D编译器
中实现.
可创建C绑定
(仅调用
其他函数的函数),来避免
移植这些宏或函数
,可向D对象
公开并应在模块的C接口
中创建
这些绑定.
每新移植
函数之后,应运行功能测试包
.
加强安全
如下是D语言
提供的一些安全增强
功能.用来在D中实现和构建
新实现的内核模块
.
1)
变量
初化
为类型的默认值
,从而消除初化
错误.
2)
隐式转换
禁止空
指针转换为其它类型
指针.D
需要显式
转换,来转换不同类型
指针.
D中禁止使用C隐式
开关降落
行为.D
还使用final switch
语句,其中不必也不应有default
(默认
语句无用时很有用),在枚举类型
时特别有用,因为在case
语句中强制
使用的所有枚举成员
.
3)
静态数组,默认,检查边界.
4)
切片
通过引用和长度信息
指定数组
的一部分.用来检查
动态分配数组边界
.请注意,要了解动态分配
数组的初始大小.
5)
模板
模板编程
可替代的C空针
和宏定义
,从而启用
类型系统检查.
6)
安全函数
(用@safe
注解),静态验证未定义行为
.在安全
函数中,不能破坏类型系统
的转换或指针算术
.
域,中域
和中域
函数参数,确保参数不会出域
,不会超过匹配参数生命期
,并且即使通过指针间接寻址
也能正确跟踪.
7)
信任函数
(用@trusted
注解),提供与安全
函数相同的保证,但必须人工检查.
8)
安全函数
只能调用其他安全
函数和信任
函数.
结论
在本文中,提出了一种使用D语言
提高Linux
内核模块安全性的方法.选择了virtio_net
作为目标驱动,这是Linux
内核中一个中等大小且积极维护
的组件.用D语言
移植了该驱动,并强调
了与原始C驱动
的功能和性能
等价,并讨论了安全优势
.详细
阐述了一种可对其他类型
驱动达到相同目的
的方法.
添加到驱动
的安全功能
表明,D
语言可在内核模块
中提升安全
,检查
数组边界和编译时
多态性是最重要
的.
重要的是要注意内核内部
的不安全
是事实
.尽管可用使用语言不同机制
来提高
开发人员编写的代码的安全性
,但某一时刻,开发人员被迫执行不安全
的操作.
这些可能来自同底层硬件
细节交互的需要,或需要与内核API
交互.大多数内核API
核心都使用原始指针
;因此,即使安全
代码,可能实现了合理
的对象生命期算法
,强制传递原始指针
给内核
,赌使所有安全注和假设
无效.
尽管如此,有两个
强有力的论据可使用安全语言:
1)
受益于30
年的开发和错误修复,内核非常稳定和健壮
.
2)
内核API
明确定义了由谁,内核或驱动
来释放分配的资源.
另一个重要
观察结果是,语言
必须可遵守Linux
内核中实现的约束和设计模式
.正如LinusTorvalds
所说,内核
需要的超过
语言需求.因此,认为D语言
非常适合,因为,证明它很容易的对接
,C和内核基础设施
.
可根据模块
实现的独立
程度改进
内核安全性.模块使用
外部特征越多,可行的安全增强
就越少.
对virtio_net
驱动的性能求值
表明,该驱动的D版本
与原始C变体
相比,几乎没有增加开销
.可持续添加
安全功能,不会引入开销
,因此,认为性能
结果令人鼓舞.
由于创建的方法,相信其他驱动
可合理的努力移植
到D
.由于与C语言
的相似性,对驱动
开发人员,习惯D语言
的影响
最小.这与Rust
语言形成鲜明对比,后者的语法和功能
,与C语言
非常不同.
相信,在Linux
内核中添加安全语言
的兴趣日益浓厚,这是向前
迈出的一大步,因为它为内核
开发人员提供了替代方案和灵活性
,使他们可根据自己的需求和目标
取得适当的平衡.
通过这些方法
,可用本文中描述
方法移植
更多驱动.稍后,这可扩展到Linux
内核中的整个
内置组件和子系统.用受欢迎的类似C的语言
,为整个内核安全性
,几乎无成本的带来
急需改进
.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现