netlink学习笔记


Netlink是linux提供的用于内核和用户态进程之间的通信方式。

但是注意虽然Netlink主要用于用户空间和内核空间的通信,但是也能用于用户空间的两个进程通信。

sendmsg

用一个nf_tables的例子来理解:

  1. sockaddr_nl中的nl_pid是0,表示发送给内核;nlmsg_hdr中的pid则用getpid()来获取,表示发送方是当前进程;
  2. begin_msg的type是NFNL_MSG_BATCH_BEGIN,关于这两个type看这篇文章:https://196082.github.io/2024/08/17/nftables/ ,在nfnetlink_rev_batch函数中会根据不同的type修改调status,所以正常结束时会进入到status == NFNL_BATCH_DONE分支中,并执行ss->commit

继续对照这个https://github.com/randorisec/CVE-2022-34918-LPE-PoC/blob/main/src/nf_tables.c 代码来体会netlink是怎么在内核中工作的。

我们先来理解一下attr是干什么的:

可以看到attr的位置就是前面图中的消息体;

有几个问题:

  1. 如何约定的这些属性?🤔
  2. 内核收到这个消息之后如何转发给nf_tables?🤔

参考这篇文章:https://www.secrss.com/articles/44817

总结一下主要过程就是:

  1. 在nfnetlink_rcv_batch()函数中对netlink消息进行操作。从netlink消息中剥离出nftable载荷,并依次进行对应处理。进入nfnetlink_rcv_batch()函数,首先根据subsys_id获得nfnetlink_subsystem。
  2. 获得subsystem后,然后拿到子系统对应的回调客户端。通过nfnetlink_find_client()实现该功能。
  3. 然后再从netlink消息中剥离出netlink载荷,根据不同的消息类型进行不同的分发处理。

而我们snedmsg的时候会指定type:

所以,应该是指定好了type就会发送到特定的模块,然后对应模块会recv到,然后再进行处理?🤔

如何构造netlink的消息体

首先看笔者对nested_attr的理解的图:

然后再看一下某个内核cve的exp中是如何构造消息体的:

首先预算并分配空间:

然后把这个长度放到第二个iov上:

最后构造消息体本身,首先要有一个struct nfgenmsg作为头:

下面来看看struct nfgenmsg结构体定义:

其实就是一个attr的头。

再看看set_str8_attr干了啥:

前4个字节搞长度和类型,然后后边紧跟的是内容;

经过实测+分析,发现我们传进去的消息体并不是一个“规范的nested_attr”,其头部4字节是一个struct nfgenmsg结构体,这个结构体目前最有用的字段就是family了,因此我们在构造netlink消息体的时候可以先假模假式地构造一个nested_attr,然后把前4个字节替换成struct nfgenmsg,也就是\x01\x00\x00\x00,至于这个family字段以后再分析,这里消息体的拆解应该是看了nlmsghdr中的长度字段还有type字段,然后拆解过程类似于普通的nested_attr🤔

此外笔者实测还发现一个问题,就是int类型的attr似乎是大端序存放的,😓

参考

https://zhuanlan.zhihu.com/p/85431412

https://blog.csdn.net/weixin_39094034/article/details/110432380

https://196082.github.io/2024/08/17/nftables/

https://github.com/randorisec/CVE-2022-34918-LPE-PoC/blob/main/src/nf_tables.c

https://www.secrss.com/articles/44817


文章作者: q1ming
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 q1ming !
  目录