Rebuild Kernel 生成 BTF 文件

在测试 golang + libbpf + ebpf 的时候发现一个问题,load ebpf object时,报错说找不到 BTF 文件。这个很奇怪,我已经 include 了 vmlinux.h, 按说不应该再依赖于 BTF 文件。看了下 libbpf 的代码,大概出错的地方在: /* * Probe few well-known locations for vmlinux kernel image and try to load BTF * data out of it to use for target BTF. */ struct btf *btf__load_vmlinux_btf(void) { struct { const char *path_fmt; bool raw_btf; } locations[] = { /* try canonical vmlinux BTF through sysfs first */ { "/sys/kernel/btf/vmlinux", true /* raw BTF */ }, /* fall back to trying to find vmlinux ELF on disk otherwise */ { "/boot/vmlinux-%1$s" }, { "/lib/modules/%1$s/vmlinux-%1$s" }, { "/lib/modules/%1$s/build/vmlinux" }, { "/usr/lib/modules/%1$s/kernel/vmlinux" }, { "/usr/lib/debug/boot/vmlinux-%1$s" }, { "/usr/lib/debug/boot/vmlinux-%1$s.debug" }, { "/usr/lib/debug/lib/modules/%1$s/vmlinux" }, }; char path[PATH_MAX + 1]; struct utsname buf; struct btf *btf; int i, err; uname(&buf); for (i = 0; i < ARRAY_SIZE(locations); i++) { snprintf(path, PATH_MAX, locations[i].path_fmt, buf.release); if (access(path, R_OK)) continue; if (locations[i].raw_btf) btf = btf__parse_raw(path); else btf = btf__parse_elf(path, NULL); err = libbpf_get_error(btf); pr_debug("loading kernel BTF '%s': %d\n", path, err); if (err) continue; return btf; } pr_warn("failed to find valid kernel BTF\n"); return libbpf_err_ptr(-ESRCH); } 猜测是用到了 CO-RE 相关的功能,走到了这块逻辑。奇怪的是我已经通过 ddeb repo安装了相关的 vmlinux 文件。但还是不行。这个后续还是要查查,比较快的解决方案就是 rebuild kernel 带上 BTF 先跑通。 ...

2021-09-01 · 2 分钟 · 289 字 · 涯余

eBPF系列2 - XDP

XDP是指 eXpress data path, 基于 ebpf 技术上的 高性能 data path. 其主要的意图是在网络 packet 处理的早期(网卡驱动处, 在数据包到达RX queue之后, 用hook的方式),让用户可以编写 ebpf 程序来进行一些决策。 这个hook的位置早于所有的内存分配时期(sk_buffer),也没有上下文切换,系统调用等开销, 所以对于性能的提升是很明显的。测试数据表明,在普通的硬件上, XDP 可以 dop 大概 2600w packets per cpu. 一个网络包的处理流程大致如下: 网络包到达网卡 从 NIC queue 拷贝到内存(DMA-backed ring buffer)中 网卡驱动使用 NAPI look 触发 soft IRQs per cpu 特定线程处理网络包 分配 socket_buffer(sk_buffer), 作为网络包的基本数据结构 kernel 填充 metadata, clone sk_buffer 并且交给上层网络处理层 IP layer 做校验, netfilter hook 处理 如果 netfilter 未 drop 此包,交给更上层网络层处理 …. 最终数据被 copy 到 userspace (recv,read,poll等网络调用获取) 其中, XDP hook 在数据到达 NIC RX queue 之后即触发(上面第二步之后).而 iptables 等的处理(上面第八步之后)非常靠后, 需要分配大量资源来处理网络包. ...

2020-11-17 · 3 分钟 · 475 字 · 涯余

ARM指针的一些安全功能

伴随着 ARM 平台的越来越普及,Linux 内核对其的支持也逐渐丰富。而且 ARM 的设计也有很多独特的优点,本文将介绍在 ARM 平台关于指针操作的一些安全方面的设计。 Pointer Authentication 很多攻击都是通过骇客设计的不安全指针进行的。比如 buffer-overflow 和 return-oriented programming, 都是通过在返回地址放置一个指针来进行的。内核已经针对这个问题做了很多改善,ARM 提供了 pointer authentication 来检测和拒绝这种插入的非法指针。 简单来说,就是在指针上附加一个签名,要想使用一个指针,先得签名验证通过。如果是外部的攻击者,它没法伪造这种签名,那么自己就不能制造指针来进行攻击了。 目前一般指针都是64位,但一般都不是所有bit都是用了。ARM64的系统,如果是三级页表,那么只有低位的40bit用来存放地址,那么其他的bit就可以用来干其他事情。 签名一般是通过以下几个参数确定: pointer 本身 process context 里的一个 secret key, kernel生成 这个肯定是攻击者无法获取到的 current stack pointer。防止签名过的pointer泄露被复用 使用的话,需要先重新计算一下签名,确保二者对的上,然后把签名部署的数据清理掉,这时候就是一个正常的指针了。不然的话,就认为其非法。 Memory Tagging Memory Tagging的做法与Pointer Authentication类似,都是利用指针里未利用的 bits 去存储一些信息。Memory Tagging 是利用 4bit 的信息存储了一个 key, 同时在 pointer 指向的内存地址里也存储了同样的 key. 当对指针进行解引用操作时,需要对比 pointer 里的 key 与实际内存地址里的 key 是否一致。如果不一致将会报错。这个功能有以下用处: 被释放的内存可以修改其 key, 防止被二次引用 每个 stack frame 分配一个 key, 越界访问也会报错 野指针也能检测到 …. 这些 keys 可以用应用层来管理,也可以用 CPU 来随机生成。当用应用层来管理的时候,可以提前检测出内存方便的 bug. ...

2020-10-19 · 1 分钟 · 103 字 · 涯余

KARL, ASLR, KASLR

前段时间在零星地看一些关于 unikerel 的文章。里面提到的一些安全相关的技术非常有趣,就又开始转向 kernel 安全这部分。本文主要探讨的是 KARL, KASLR 以及 ASLR 相关的技术。 安全相关的实现技术很多,但想了想,大体的分类可以归为以下几类: RWX 权限检查 随机化: 尽量不用确定性的内存地址 暴露最少的信息: 日志,输出里尽量不暴露相关信息 KARL, KASLR 以及 ASLR 都属于第二类。尽量让应用程序以及内核在内存中的地址随机化,这样攻击者就难以猜出相关的地址。 简单来讲, ASLR(Address-space layout randomization) 主要是指内存中用户层的地址随机化,KASLR 是指内存中内核的地址随机化, 而 KARL(kernel adress randomized link)是指内核本身的地址随机化。ASLR出现的时间更早一些,更成熟一些。 注意有一个区别, 三者中都有一个 L,但意义不一样。 ASLR/KASLR 中的 L 是指 layout,是说内存中的布局。你不可能要求大量的应用程序自己去考虑随机化,而是在应用程序无感知的情况下,由内核来选择一个随机的位置来运行应用程序。而 KARL 中的 L 是指 link ,是在链接阶段就做好了地址的随机化处理,这样就不需要再内存中在做了。 ASLR ASLR 理解起来相对更为简单,本身不需要再重复介绍。 RNG 不管是 KARL / ASLR / KASLR,其核心都是一个随机的概念。明显它依赖于随机数的生成算法。当然随机程度越高越安全,但是又要考内核的性能。这个平衡很难掌握,选择哪个 RNG(random number generation) 也经过了很多讨论。 一开始用的是 get_random_int(),一个性能比较好但安全性不够好的方法,后来有人提出用 get_random_bytes(),安全性大大提高,但是性能下降也比较多。再后来 Linux 自己对get_random_int()做了一些改进, 增加了一些噪音进去,在不影响性能的情况下改进了随机性。这也是目前在用的方法。 ...

2019-08-27 · 1 分钟 · 171 字 · 涯余