所以我創建了一個 BPF_MAP_TYPE_ARRAY 型別的地圖。
struct share_me
{
struct iphdr dest_ip;
};
struct bpf_map_def SEC("maps") ip_map = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(struct share_me),
.max_entries = 64, /* Assume netdev has no more than 64 queues */
};
所以 ip_map 是我的地圖,它的定義和 SEC elf 部分用于在上述定義中創建地圖
在我的 ebpf 程式功能中,我正在做
SEC("xdp_sock")
int xdp_sock_prog(struct xdp_md *ctx)
{
int index = ctx->rx_queue_index;
__u32 *pkt_count;
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
struct share_me me;
if ((void *)eth sizeof(*eth) <= data_end)
{
struct iphdr *ip = data sizeof(*eth);
//me.dest_ip=ip;
memcpy(&me.dest_ip,ip,sizeof(struct iphdr));
bpf_map_lookup_elem(&ip_map, &index);
bpf_map_update_elem(&ip_map,&index,&me,0);
所以我用我的結構物件更新 ip_map 鍵的當前值
這就是我在使用空間程式中所做的
bpf_obj = load_bpf_and_xdp_attach(&cfg);
if (!bpf_obj) {
/* Error handling done in load_bpf_and_xdp_attach() */
exit(EXIT_FAILURE);
}
/* We also need to load the xsks_map */
map1 = bpf_object__find_map_by_name(bpf_obj, "ip_map");
xsks_map_fd = bpf_map__fd(map);
map_fd = bpf_map__fd(map1);
if(map_fd<0)
{
printf("map_fd <0\n");
exit(0);
}
if (xsks_map_fd < 0) {
fprintf(stderr, "ERROR: no xsks map found: %s\n",
strerror(xsks_map_fd));
exit(EXIT_FAILURE);
}
這是 load_bpf_and_xdp_attach 函式只是 bpf/libbpf 的包裝器,因此呼叫 load_bpf_object_file 等,
struct bpf_object *load_bpf_and_xdp_attach(struct config *cfg)
{
struct bpf_program *bpf_prog;
struct bpf_object *bpf_obj;
int offload_ifindex = 0;
int prog_fd = -1;
int err;
/* If flags indicate hardware offload, supply ifindex */
if (cfg->xdp_flags & XDP_FLAGS_HW_MODE)
offload_ifindex = cfg->ifindex;
/* Load the BPF-ELF object file and get back libbpf bpf_object */
if (cfg->reuse_maps)
bpf_obj = load_bpf_object_file_reuse_maps(cfg->filename,
offload_ifindex,
cfg->pin_dir);
else
bpf_obj = load_bpf_object_file(cfg->filename, offload_ifindex);
if (!bpf_obj) {
fprintf(stderr, "ERR: loading file: %s\n", cfg->filename);
exit(EXIT_FAIL_BPF);
}
/* At this point: All XDP/BPF programs from the cfg->filename have been
* loaded into the kernel, and evaluated by the verifier. Only one of
* these gets attached to XDP hook, the others will get freed once this
* process exit.
*/
if (cfg->progsec[0])
/* Find a matching BPF prog section name */
bpf_prog = bpf_object__find_program_by_title(bpf_obj, cfg->progsec);
else
/* Find the first program */
bpf_prog = bpf_program__next(NULL, bpf_obj);
if (!bpf_prog) {
fprintf(stderr, "ERR: couldn't find a program in ELF section '%s'\n", cfg->progsec);
exit(EXIT_FAIL_BPF);
}
strncpy(cfg->progsec, bpf_program__title(bpf_prog, false), sizeof(cfg->progsec));
prog_fd = bpf_program__fd(bpf_prog);
if (prog_fd <= 0) {
fprintf(stderr, "ERR: bpf_program__fd failed\n");
exit(EXIT_FAIL_BPF);
}
/* At this point: BPF-progs are (only) loaded by the kernel, and prog_fd
* is our select file-descriptor handle. Next step is attaching this FD
* to a kernel hook point, in this case XDP net_device link-level hook.
*/
err = xdp_link_attach(cfg->ifindex, cfg->xdp_flags, prog_fd);
if (err)
exit(err);
return bpf_obj;
}
但我收到錯誤
libbpf: load bpf program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
; int index = ctx->rx_queue_index;
0: (61) r2 = *(u32 *)(r1 16)
; int index = ctx->rx_queue_index;
1: (63) *(u32 *)(r10 -4) = r2
; void *data_end = (void *)(long)ctx->data_end;
2: (61) r2 = *(u32 *)(r1 4)
; void *data = (void *)(long)ctx->data;
3: (61) r1 = *(u32 *)(r1 0)
; if ((void *)eth sizeof(*eth) <= data_end)
4: (07) r1 = 14
; if ((void *)eth sizeof(*eth) <= data_end)
5: (2d) if r1 > r2 goto pc 25
R1_w=pkt(id=0,off=14,r=14,imm=0) R2_w=pkt_end(id=0,off=0,imm=0) R10=fp0 fp-8=mmmm????
; memcpy(&me.dest_ip,ip,sizeof(struct iphdr));
6: (61) r2 = *(u32 *)(r1 16)
invalid access to packet, off=30 size=4, R1(id=0,off=30,r=14)
R1 offset is outside of the packet
processed 7 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
libbpf: -- END LOG --
libbpf: failed to load program 'xdp_sock'
libbpf: failed to load object 'af_xdp_kern.o'
ERR: loading BPF-OBJ file(af_xdp_kern.o) (-22): Invalid argument
ERR: loading file: af_xdp_kern.o
所以我invalid access to packet, off=30 size=4, R1(id=0,off=30,r=14) R1 offset is outside of the packet在加載我的 ebpf 程式時得到了我有點確定由于我使用結構值作為 BPF_MAP_TYPE_ARRY 值型別的映射而導致的錯誤
所以我想知道如果我使用允許 struct 作為映射鍵值的 libbpf 那里還有其他 MAP 型別
uj5u.com熱心網友回復:
TL;博士。問題是您正在從驗證者的角度對資料包進行越界訪問。您需要首先檢查資料包是否足夠長以實際包含 IP 標頭。
讀取驗證器錯誤訊息。
; memcpy(&me.dest_ip,ip,sizeof(struct iphdr));
6: (61) r2 = *(u32 *)(r1 16)
invalid access to packet, off=30 size=4, R1(id=0,off=30,r=14)
R1 offset is outside of the packet
驗證程式在指令 6 上出錯,該指令對應于memcpy陳述句。它表明您正在對資料包進行無效訪問,偏移量保持在R1資料包的已知范圍之外。
您檢查了資料包是否至少足夠長以容納以太網標頭,但您從未檢查過它是否足夠長以容納 IP 標頭。因此,驗證器會看到您嘗試訪問以太網標頭之外的位元組(最多偏移 30)和錯誤。
更新資料包邊界檢查。
如果您從一開始就知道您需要同時讀取以太網和 IP 標頭,您可以從以下位置更新您的檢查:
if ((void *)eth sizeof(*eth) <= data_end)
到:
if ((void *)eth sizeof(*eth) sizeof(struct iphdr) <= data_end)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/413770.html
標籤:
上一篇:使用awk只列印一次不可用的記錄
下一篇:LTTNG:與流行的庫一起使用
