BPF程序类型

💡 hello everyone !!!

BPF没有明确的分类,可以将其分为两类:

  • 跟踪

提供系统行为及系统硬件的直接信息。也可以访问特定程序的内存区域,从运行进程中提取执行跟踪信息,还可以访问进程分配的特定资源,文件描述符、cpu、内存。

  • 网络

检测和控制系统的网络流量。可以对网络接口数据包进行过滤,甚至可以完全拒绝数据包。

BPF程序可以附加到网络驱动程序接收数据包的网络事件中,也可以附加到数据包传递给用户空间的网络事件。

man bpf 获得更多知识:

BPF(2)                                                                                                  Linux Programmer's Manual                                                                                                 BPF(2)

NAME
       bpf - perform a command on an extended BPF map or program

SYNOPSIS
       #include <linux/bpf.h>

       int bpf(int cmd, union bpf_attr *attr, unsigned int size);

DESCRIPTION
       The  bpf()  system  call performs a range of operations related to extended Berkeley Packet Filters.  Extended BPF (or eBPF) is similar to the original ("classic") BPF (cBPF) used to filter network packets.  For both cBPF and
       eBPF programs, the kernel statically analyzes the programs before loading them, in order to ensure that they cannot harm the running system.

       eBPF extends cBPF in multiple ways, including the ability to call a fixed set of in-kernel helper functions (via the BPF_CALL opcode extension provided by eBPF) and access shared data structures such as eBPF maps.

   Extended BPF Design/Architecture
       eBPF maps are a generic data structure for storage of different data types.  Data types are generally treated as binary blobs, so a user just specifies the size of the key and the size of the value at map-creation  time.   In
       other words, a key/value for a given map can have an arbitrary structure.

       A  user  process can create multiple maps (with key/value-pairs being opaque bytes of data) and access them via file descriptors.  Different eBPF programs can access the same maps in parallel.  It's up to the user process and
       eBPF program to decide what they store inside maps.

       There's one special map type, called a program array.  This type of map stores file descriptors referring to other eBPF programs.  When a lookup in the map is performed, the program flow is redirected in-place to  the  begin‐
       ning  of  another  eBPF program and does not return back to the calling program.  The level of nesting has a fixed limit of 32, so that infinite loops cannot be crafted.  At runtime, the program file descriptors stored in the
       map can be modified, so program functionality can be altered based on specific requirements.  All programs referred to in a program-array map must have been previously loaded into the kernel via bpf().  If a map lookup fails,
       the current program continues its execution.  See BPF_MAP_TYPE_PROG_ARRAY below for further details.

       Generally,  eBPF  programs  are  loaded  by  the user process and automatically unloaded when the process exits.  In some cases, for example, tc-bpf(8), the program will continue to stay alive inside the kernel even after the
       process that loaded the program exits.  In that case, the tc subsystem holds a reference to the eBPF program after the file descriptor has been closed by the user-space program.  Thus, whether a specific program continues  to
       live inside the kernel depends on how it is further attached to a given kernel subsystem after it was loaded via bpf().

       Each  eBPF  program  is  a  set  of instructions that is safe to run until its completion.  An in-kernel verifier statically determines that the eBPF program terminates and is safe to execute.  During verification, the kernel
       increments reference counts for each of the maps that the eBPF program uses, so that the attached maps can't be removed until the program is unloaded.

       eBPF programs can be attached to different events.  These events can be the arrival of network packets, tracing events, classification events by network queueing  disciplines (for eBPF programs attached  to  a  tc(8)  classi‐
       fier),  and  other types that may be added in the future.  A new event triggers execution of the eBPF program, which may store information about the event in eBPF maps.  Beyond storing data, eBPF programs may call a fixed set
       of in-kernel helper functions.

       The same eBPF program can be attached to multiple events and different eBPF programs can access the same map:

           tracing     tracing    tracing    packet      packet     packet
           event A     event B    event C    on eth0     on eth1    on eth2
            |             |         |          |           |          ^
            |             |         |          |           v          |
            --> tracing <--     tracing      socket    tc ingress   tc egress
                 prog_1          prog_2      prog_3    classifier    action
                 |  |              |           |         prog_4      prog_5
              |---  -----|  |------|          map_3        |           |
            map_1       map_2                              --| map_4 |--

   Arguments
       The operation to be performed by the bpf() system call is determined by the cmd argument.  Each operation takes an accompanying argument, provided via attr, which is a pointer to a union of type  bpf_attr  (see  below).   The
       size argument is the size of the union pointed to by attr.

       The value provided in cmd is one of the following:

       BPF_MAP_CREATE
              Create a map and return a file descriptor that refers to the map.  The close-on-exec file descriptor flag (see fcntl(2)) is automatically enabled for the new file descriptor.

       BPF_MAP_LOOKUP_ELEM
              Look up an element by key in a specified map and return its value.

       BPF_MAP_UPDATE_ELEM

各种类型添加到内核的时间顺序来进行介绍:

  • 参考:https://github.com/DavadDi/bpf_study/blob/5d30702c6c1eb884326d933c401c162163d85936/bpf-prog-type.md#bpf-程序类型支持-helper-函数列表

1. 套接字过滤器程序

BPF_PROG_TYPE_SOCKET_FILTER类型用于访问所有套接字处理的数据包,只能用于观测,不能修改数据包的内容或者更改目的地。

BPF_PROG_TYPE_SOCKET_FILTER:

BPF_FUNC_skb_load_bytes()
BPF_FUNC_skb_load_bytes_relative()
BPF_FUNC_get_socket_cookie()
BPF_FUNC_get_socket_uid()
BPF_FUNC_perf_event_output()
Base functions

2. kprobe程序

kprobe是动态附加到内核调用点的函数。bpf虚拟机总是确kprobe能够安全的运行,但是内核kprobe被认为是不稳定的入口点,需要确定程序是否与内核相兼容。

BPF_PROG_TYPE_KPROBE:

BPF_FUNC_perf_event_output()
BPF_FUNC_get_stackid()
BPF_FUNC_get_stack()
BPF_FUNC_perf_event_read_value()
BPF_FUNC_override_return()
Tracing functions

如果需要检查exec系统调用的返回值,需要BPF程序设置sec头部,SEC("kretprobe/sys_exec")

3. 跟踪点程序

跟踪点程序会俯角到内核提供的跟踪点处理程序上。是内核代码的静态标记,允许注入跟踪和调试相关的任意代码。可以编写一个BPF程序来检查其他BPF程序的行为。

BPF_PROG_TYPE_TRACEPOINT:
BPF_FUNC_perf_event_output()
BPF_FUNC_get_stackid()
BPF_FUNC_get_stack()
Tracing functions

4. XDP程序

当网络包到达内核时,xdp程序会在早起被执行, 此时,内核还没有对数据包本身进行太多的处理,所以数据包的信息展示有限,但是具有更高级别的控制。

BPF_PROG_TYPE_XDP:

BPF_FUNC_perf_event_output()
BPF_FUNC_get_smp_processor_id()
BPF_FUNC_csum_diff()
BPF_FUNC_xdp_adjust_head()
BPF_FUNC_xdp_adjust_meta()
BPF_FUNC_redirect()
BPF_FUNC_redirect_map()
BPF_FUNC_xdp_adjust_tail()
BPF_FUNC_fib_lookup()
Base functions

5. perf 事件程序

将bpf代码附加到perf事件上,使用perf事件程序监控很多系统信息。

BPF_PROG_TYPE_PERF_EVENT:
BPF_FUNC_perf_event_output()
BPF_FUNC_get_stackid()
BPF_FUNC_get_stack()
BPF_FUNC_perf_prog_read_value()
Tracing functions

6. cgroup套接字程序

该程序允许cgroup在其包含的进程中控制网络流量。在传入cgroup控制之前,通过cgroup套接字程序,可以决定如何处理这些数据包。cilium使用cgroup套接字程序将策略应用进程组上,而不是在隔离的容器上。

BPF_PROG_TYPE_CGROUP_SKB:
BPF_FUNC_skb_load_bytes()
BPF_FUNC_skb_load_bytes_relative()
BPF_FUNC_get_socket_cookie()
BPF_FUNC_get_socket_uid()
Base functions

7. cgroup 打开套接字程序

允许cgroup内的任何进程打开网络套接字时执行代码。可以对打开套接字程序组提供安全性和访问控制,而不必单独限制每个进程的功能。

BPF_PROG_TYPE_CGROUP_SOCK :
BPF_FUNC_get_current_uid_gid()
Base functions

8. 套接字选项程序

允许运行时修改套接字链接选项,可以访网络IP地址和链接端口之类的数据,并且还可以修改链接选项,设置超时,以及更改给定数据包往返延迟时间。

BPF_PROG_TYPE_SOCK_OPS :
BPF_FUNC_setsockopt()
BPF_FUNC_getsockopt()
BPF_FUNC_sock_ops_cb_flags_set()
BPF_FUNC_sock_map_update()
BPF_FUNC_sock_hash_update()
BPF_FUNC_get_socket_cookie()
Base functions

9. 套接字映射程序

套接字映射可以保留对一些套接字的引用。使用这些引用和特性的帮助函数将套接字的数据包重定向到其他的套接字。以下两个项目是使用此功能,实现负载均衡等。

https://github.com/cilium/cilium.git

https://github.com/facebookincubator/katran.git

BPF_PROG_TYPE_SK_SKB :
BPF_FUNC_skb_store_bytes()
BPF_FUNC_skb_load_bytes()
BPF_FUNC_skb_pull_data()
BPF_FUNC_skb_change_tail()
BPF_FUNC_skb_change_head()
BPF_FUNC_get_socket_cookie()
BPF_FUNC_get_socket_uid()
BPF_FUNC_sk_redirect_map()
BPF_FUNC_sk_redirect_hash()
BPF_FUNC_sk_lookup_tcp()
BPF_FUNC_sk_lookup_udp()
BPF_FUNC_sk_release()
Base functions

10. cgroup 设备程序

决定是否能够给定设备上执行cgroup中的操作。cgroups(v1)的第一个实现允许为特定设备设置权限。但是第二个迭代中缺少了这个功能。

BPF_PROG_TYPE_CGROUP_DEVICE :
BPF_FUNC_map_lookup_elem()
BPF_FUNC_map_update_elem()
BPF_FUNC_map_delete_elem()
BPF_FUNC_get_current_uid_gid()
BPF_FUNC_trace_printk()

11. 套接字消息传递程序

控制是否将消息发送到套接字。

BPF_PROG_TYPE_SK_MSG :
BPF_FUNC_msg_redirect_map()
BPF_FUNC_msg_redirect_hash()
BPF_FUNC_msg_apply_bytes()
BPF_FUNC_msg_cork_bytes()
BPF_FUNC_msg_pull_data()
BPF_FUNC_msg_push_data()
BPF_FUNC_msg_pop_data()
Base functions

12. 原始跟踪点程序

程序能够提供内核执行任务的更多信息,但是会有少许性能开销。

BPF_PROG_TYPE_RAW_TRACEPOINT :
BPF_FUNC_perf_event_output()
BPF_FUNC_get_stackid()
BPF_FUNC_get_stack()
BPF_FUNC_skb_output()
Tracing functions

13. cgroup套接字地址程序

允许cgroup控制的用户控件程序的IP地址和端口号。当系统使用多个IP时,可以确保一组特定的用户控件程序使用相同的IP地址和端口。

BPF_PROG_TYPE_CGROUP_SOCK_ADDR :
BPF_FUNC_get_current_uid_gid()
BPF_FUNC_bind()
BPF_FUNC_get_socket_cookie()
Base functions

14. 套接字重用端口程序

允许相同的主机上多个进程绑定相同的端口。在高并发情况下,我们可以使用多个线程处理负载。

BPF_PROG_TYPE_SK_REUSEPORT :
BPF_FUNC_sk_select_reuseport()
BPF_FUNC_skb_load_bytes()
BPF_FUNC_load_bytes_relative()
Base functions

15.  流量解析程序

跟踪网络数据包经过不同的层,从网络数据包到达系统再到数据包发送给用户空间程序。将程序裸机挂钩到流量解析器的路径上,提供了内置解析器没有的安全保证。

BPF_PROG_TYPE_FLOW_DISSECTOR :
BPF_FUNC_skb_load_bytes()
Base functions

16. 其他

BPF_PROG_TYPE_LWT_SEG6LOCAL :
BPF_FUNC_lwt_seg6_store_bytes()
BPF_FUNC_lwt_seg6_action()
BPF_FUNC_lwt_seg6_adjust_srh()
LWT functions

BPF_PROG_TYPE_LIRC_MODE2 : 
BPF_FUNC_rc_repeat()
BPF_FUNC_rc_keydown()
BPF_FUNC_rc_pointer_rel()
BPF_FUNC_map_lookup_elem()
BPF_FUNC_map_update_elem()
BPF_FUNC_map_delete_elem()
BPF_FUNC_ktime_get_ns()
BPF_FUNC_tail_call()
BPF_FUNC_get_prandom_u32()
BPF_FUNC_trace_printk()

BPF_PROG_TYPE_LWT_IN :
BPF_FUNC_lwt_push_encap()
LWT functions
Base functions
BPF_PROG_TYPE_LWT_OUT : 
LWT functions
Base functions

BPF_PROG_TYPE_LWT_XMIT : 
BPF_FUNC_skb_get_tunnel_key()
BPF_FUNC_skb_set_tunnel_key()
BPF_FUNC_skb_get_tunnel_opt()
BPF_FUNC_skb_set_tunnel_opt()
BPF_FUNC_redirect()
BPF_FUNC_clone_redirect()
BPF_FUNC_skb_change_tail()
BPF_FUNC_skb_change_head()
BPF_FUNC_skb_store_bytes()
BPF_FUNC_csum_update()
BPF_FUNC_l3_csum_replace()
BPF_FUNC_l4_csum_replace()
BPF_FUNC_set_hash_invalid()
LWT functions

BPF_PROG_TYPE_SCHED_CLS 、 BPF_PROG_TYPE_SCHED_ACT :

BPF_FUNC_skb_store_bytes()
BPF_FUNC_skb_load_bytes()
BPF_FUNC_skb_load_bytes_relative()
BPF_FUNC_skb_pull_data()
BPF_FUNC_csum_diff()
BPF_FUNC_csum_update()
BPF_FUNC_l3_csum_replace()
BPF_FUNC_l4_csum_replace()
BPF_FUNC_clone_redirect()
BPF_FUNC_get_cgroup_classid()
BPF_FUNC_skb_vlan_push()
BPF_FUNC_skb_vlan_pop()
BPF_FUNC_skb_change_proto()
BPF_FUNC_skb_change_type()
BPF_FUNC_skb_adjust_room()
BPF_FUNC_skb_change_tail()
BPF_FUNC_skb_get_tunnel_key()
BPF_FUNC_skb_set_tunnel_key()
BPF_FUNC_skb_get_tunnel_opt()
BPF_FUNC_skb_set_tunnel_opt()
BPF_FUNC_redirect()
BPF_FUNC_get_route_realm()
BPF_FUNC_get_hash_recalc()
BPF_FUNC_set_hash_invalid()
BPF_FUNC_set_hash()
BPF_FUNC_perf_event_output()
BPF_FUNC_get_smp_processor_id()
BPF_FUNC_skb_under_cgroup()
BPF_FUNC_get_socket_cookie()
BPF_FUNC_get_socket_uid()
BPF_FUNC_fib_lookup()
BPF_FUNC_skb_get_xfrm_state()
BPF_FUNC_skb_cgroup_id()
Base functions

BPF能够允许任何人在linux内核中执行任意代码,那么安全性怎么保证呢?

CVE-2017-16995 https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-16995

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值