Sparse
Sparse是内核代码静态分析工具, 能够帮助我们找出代码中的隐患.www.cnblogs.com/wang_yb/p/3…
| 宏名称 | 宏定义 | 检查点 |
|---|---|---|
| __bitwise | attribute((bitwise)) | 确保变量是相同的位方式(比如 bit-endian, little-endian等) |
| __user | attribute((noderef, address_space(1))) | 指针地址必须在用户地址空间 |
| __kernel | attribute((noderef, address_space(0))) | 指针地址必须在内核地址空间 |
| __iomem | attribute((noderef, address_space(2))) | 指针地址必须在设备地址空间 |
| __safe | attribute((safe)) | 变量可以为空 |
| __force | attribute((force)) | 变量可以进行强制转换 |
| __nocast | attribute((nocast)) | 参数类型与实际参数类型必须一致 |
| __acquires(x) | attribute((context(x, 0, 1))) | 参数x 在执行前引用计数必须是0,执行后,引用计数必须为1 |
| __releases(x) | attribute((context(x, 1, 0))) | 与 __acquires(x) 相反 |
| __acquire(x) | context(x, 1) | 参数x 的引用计数 + 1 |
| __release(x) | context(x, -1) | 与 __acquire(x) 相反 |
| __cond_lock(x,c) | ((c) ? ({ __acquire(x); 1; }) : 0) | 参数c 不为0时,引用计数 + 1, 并返回1 |
| __rcu | attribute((noderef, address_space(4))) | 读-复制-更新是一种算法,无需锁定结构即可同时访问数据结构的读取器 |
常用宏
1. SYSCALL_DEFINE(X)
Linux 内核中用于定义系统调用的宏,其中(X)可以是1~6,下是 SYSCALL_DEFINE6 宏的基本结构:
cCopy code
SYSCALL_DEFINE6(name, type1, name1, type2, name2, type3, name3,
type4, name4, type5, name5, type6, name6)
{
// 在这里实现系统调用的功能
}
其中:
name是系统调用函数的名称。type1,type2, ...,type6是系统调用函数的参数类型。name1,name2, ...,name6是系统调用函数的参数名称。
使用 SYSCALL_DEFINE6 宏可以使得定义系统调用函数更加简洁和清晰,同时确保了系统调用函数的正确性和安全性。
2. likely、unlikely
在 Linux 内核中,likely 是一个宏,用于提示编译器某个条件通常为真。它用于在编写代码时,帮助编译器优化分支预测,提高程序的执行效率。
likely 宏并不改变程序的逻辑行为,它只是一种提示,告诉编译器某个条件通常为真。
与 likely 宏类似,unlikely 宏也只是一种提示,告诉编译器某个条件通常为假,而不会改变程序的逻辑行为。
3. NF_HOOK_COND
NF_HOOK_COND 是 Linux 内核中用于注册和执行网络数据包处理钩子函数的一个宏。这个宏允许内核模块注册一个网络数据包处理钩子函数,并在网络数据包经过协议栈的特定点时执行该函数。
以下是 NF_HOOK_COND 宏的基本语法:
unsigned int NF_HOOK_COND(unsigned int pf, unsigned int hook, struct net_device *in,
struct sk_buff *skb, struct net_device *out,
int (*okfn)(struct net *, struct sock *, struct sk_buff *),
int thresh, int (*cond)(const struct nf_hook_ops *, struct sk_buff *,
struct net_device *, struct net_device *,
int (*okfn)(struct net *, struct sock *, struct sk_buff *)));
其中参数含义如下:
pf: 协议族(Protocol Family),如PF_INET、PF_INET6等。hook: 钩子函数类型,如NF_INET_PRE_ROUTING、NF_INET_LOCAL_IN等,表示数据包处理的不同阶段。in: 指向输入网络设备的指针。skb: 指向待处理的数据包的sk_buff结构体指针。out: 指向输出网络设备的指针。okfn: 一个函数指针,指向一个函数,用于表示数据包处理完成的回调函数。thresh: 钩子函数阈值,用于指定钩子函数执行的优先级。cond: 一个函数指针,指向一个函数,用于定义钩子函数执行的条件。
NF_HOOK_COND 宏将钩子函数注册到指定的钩子点,当满足指定的条件时,将执行该钩子函数。
内核方法
1. array_index_nospec
array_index_nospecx86/uaccess: Use pointer masking to limit uaccess speculation2018年的Spectre变种1(bounds-check bypass),借助边界检查时cpu会投机访问(speculate access),实现攻击。之前x86在 copy_from_user中使用LFENCE减缓这种攻击。但是LFENCE有点重了。
来自Redhat的Josh把LFENCE替换为 array_index_nospec,后者原本的用途是数组访问越界时,把index被钳位为0,从而避免攻击者访问原本不允许访问的超过数组范围的地址。由于64位内核中,用户空间地址为低地址(以一串0开头),内核为高地址(以一串1开头)。如果给 array_index_nospec传入0和用户地址的最大范围( user_addr_max()),当攻击者试图从用户空间传入内核地址(即大于 user_addr_max()的地址时,该地址会被 array_index_nospec设为0。从而避免了攻击者从用户空间“偷到”内核的数据。
2. atomic_read
对原子类型的变量v进行原子读操作,得到其值。
3. container_of
通过结构体成员变量地址获取这个结构体的地址
未完待续...