【问题标题】:How to access a kernel variable using BPF?如何使用 BPF 访问内核变量?
【发布时间】:2017-05-29 16:54:16
【问题描述】:

例如,访问函数ip_rcv中的skb变量:

int ip_rcv(struct sk_buff *skb, struct net_device *dev,
           struct packet_type *pt, struct net_device *orig_dev)
{
...
}

我搜索了互联网,但没有找到任何示例。

【问题讨论】:

    标签: linux-kernel kernel bpf ebpf


    【解决方案1】:

    使用 BPF 拦截内核函数的最简单方法可能是使用bcc。它提供了一个更高级别的 Python API 来在内核中加载 BPF 程序并与之交互:

    #!/usr/bin/env python
    from bcc import BPF
    
    BPF(text="""
    int kprobe__ip_rcv(struct pt_regs *ctx, struct sk_buff *skb) {
        bpf_trace_printk("skb=%p!\\n", skb);
        return 0;
    }
    """).trace_print()
    

    返回:

          <idle>-0     [007] d.s.  1441.065248: : skb=ffff906b2bd53400!
          <idle>-0     [007] d.s.  1442.267325: : skb=ffff906b76c5b700!
          <idle>-0     [007] d.s.  1442.993894: : skb=ffff906b42b76800!
          <idle>-0     [007] d.s.  1443.194334: : skb=ffff906be925d300!
          <idle>-0     [007] d.s.  1444.616469: : skb=ffff906b67e6a200!
    

    有关详细信息,请参阅密件抄送存储库上的 the tutorial

    如果不想使用 bcc,可以在 Linux 内核中找到examples of BPF programs。特别是,我邀请您查看tracex1_kern/user.c

    【讨论】:

      【解决方案2】:

      您还可以通过将其附加到原始套接字来访问它,例如下面的程序,该程序尝试过滤和解析 HTTP 数据包。 C BPF 程序应如下所示:

      int http_filter(struct __sk_buff *skb) {

      u8 *cursor = 0;
      
      struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
      //filter IP packets (ethernet type = 0x0800)
      if (!(ethernet->type == 0x0800)) {
          goto DROP;
      }
      
      struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
      //filter TCP packets (ip next protocol = 0x06)
      if (ip->nextp != IP_TCP) {
          goto DROP;
      }
      
      u32  tcp_header_length = 0;
      u32  ip_header_length = 0;
      u32  payload_offset = 0;
      u32  payload_length = 0;
      struct Key  key;
      struct Leaf zero = {0};
      
          //calculate ip header length
          //value to multiply * 4
          //e.g. ip->hlen = 5 ; IP Header Length = 5 x 4 byte = 20 byte
          ip_header_length = ip->hlen << 2;    //SHL 2 -> *4 multiply
      
          //check ip header length against minimum
          if (ip_header_length < sizeof(*ip)) {
                  goto DROP;
          }
      
          //shift cursor forward for dynamic ip header size
          void *_ = cursor_advance(cursor, (ip_header_length-sizeof(*ip)));
      
      struct tcp_t *tcp = cursor_advance(cursor, sizeof(*tcp));
      
      //retrieve ip src/dest and port src/dest of current packet
      //and save it into struct Key
      key.dst_ip = ip->dst;
      key.src_ip = ip->src;
      key.dst_port = tcp->dst_port;
      key.src_port = tcp->src_port;
      
      //calculate tcp header length
      //value to multiply *4
      //e.g. tcp->offset = 5 ; TCP Header Length = 5 x 4 byte = 20 byte
      tcp_header_length = tcp->offset << 2; //SHL 2 -> *4 multiply
      
      //calculate payload offset and length
      payload_offset = ETH_HLEN + ip_header_length + tcp_header_length;
      payload_length = ip->tlen - ip_header_length - tcp_header_length;
      
      //http://stackoverflow.com/questions/25047905/http-request-minimum-size-in-bytes
      //minimum length of http request is always geater than 7 bytes
      //avoid invalid access memory
      //include empty payload
      if(payload_length < 7) {
          goto DROP;
      }
      
      //load first 7 byte of payload into p (payload_array)
      //direct access to skb not allowed
      unsigned long p[7];
      int i = 0;
      for (i = 0; i < 7; i++) {
          p[i] = load_byte(skb , payload_offset + i);
      }
      

      }

      附加程序的 Python 脚本应如下所示: 而1: #从套接字中获取原始数据包 packet_str = os.read(socket_fd,4096)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-29
        • 1970-01-01
        • 2016-12-04
        • 1970-01-01
        • 2015-11-28
        • 1970-01-01
        • 2019-12-27
        • 1970-01-01
        相关资源
        最近更新 更多