расшифровка "недопустимый доступ к карте памяти_ptr" при загрузке программы BPF - PullRequest
0 голосов
/ 03 июня 2018

Я пишу специальное приложение, которое читает код C, вызывает LLVM для генерации байтового кода BPF из этого кода C, затем перемещает любые символы карты bpf и загружает его в ядро.Я могу успешно загружать и запускать программы, которые не используют карты BPF, но как только я переместил программу для использования карты BPF, я получаю следующую ошибку:

invalid mem access 'map_ptr'

Подробности следуют:

Следующие входные данные передаются в LLVM:

// Placeholder values for user-requested maps
void *a;

#include <linux/ptrace.h>
#include <uapi/linux/bpf.h>
#include "bpf_helpers.h"

int kprobe__blk_start_request(struct pt_regs *ctx) {
  long rq = PT_REGS_PARM1(ctx);
  u64 val = bpf_ktime_get_ns();
  bpf_map_update_elem(a, &rq, &val, BPF_ANY);
  return 0;
}

, который генерирует следующий байт-код

Found function: kprobe__blk_start_request
  size: 120 bytes
  addr: 0
relocate: a @ 32

/tmp/bpf7990/bpf.o: file format ELF64-BPF

Disassembly of section .text:
kprobe__blk_start_request:
       0:   79 11 70 00 00 00 00 00     r1 = *(u64 *)(r1 + 112)
       1:   7b 1a f8 ff 00 00 00 00     *(u64 *)(r10 - 8) = r1
       2:   85 00 00 00 05 00 00 00     call 5
       3:   7b 0a f0 ff 00 00 00 00     *(u64 *)(r10 - 16) = r0
       4:   18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00     r1 = 0ll
       6:   79 11 00 00 00 00 00 00     r1 = *(u64 *)(r1 + 0)
       7:   bf a2 00 00 00 00 00 00     r2 = r10
       8:   07 02 00 00 f8 ff ff ff     r2 += -8
       9:   bf a3 00 00 00 00 00 00     r3 = r10
      10:   07 03 00 00 f0 ff ff ff     r3 += -16
      11:   b7 04 00 00 00 00 00 00     r4 = 0
      12:   85 00 00 00 02 00 00 00     call 2
      13:   b7 00 00 00 00 00 00 00     r0 = 0
      14:   95 00 00 00 00 00 00 00     exit

, и символ "a" перемещается в инструкции # 4 следующим образом:

Relocating instruction 4
    from code:0x18 dst_reg:1 src_reg:0 off:0x0 imm:0x0
      to code:0x18 dst_reg:1 src_reg:1 off:0x0 imm:0x4
kprobe__blk_start_request:
       0:   79 11 70 00 00 00 00 00 
       1:   7b 1a f8 ff 00 00 00 00 
       2:   85 00 00 00 05 00 00 00 
       3:   7b 0a f0 ff 00 00 00 00 
       4:   18 11 00 00 04 00 00 00 
       5:   00 00 00 00 00 00 00 00 
       6:   79 11 00 00 00 00 00 00 
       7:   bf a2 00 00 00 00 00 00 
       8:   07 02 00 00 f8 ff ff ff 
       9:   bf a3 00 00 00 00 00 00 
      10:   07 03 00 00 f0 ff ff ff 
      11:   b7 04 00 00 00 00 00 00 
      12:   85 00 00 00 02 00 00 00 
      13:   b7 00 00 00 00 00 00 00 
      14:   95 00 00 00 00 00 00 00

"04" в инструкции # 4 является FD карты для символа "a".После вызова BPF_PROG_LOAD в журнале ошибок я получаю следующее:

Failed to load kprobe__blk_start_request BPF code
0: R1=ctx(id=0,off=0,imm=0) R10=fp0
0: (79) r1 = *(u64 *)(r1 +112)
1: R1=inv(id=0) R10=fp0
1: (7b) *(u64 *)(r10 -8) = r1
2: R1=inv(id=0) R10=fp0
2: (85) call bpf_ktime_get_ns#5
3: R0=inv(id=0) R10=fp0
3: (7b) *(u64 *)(r10 -16) = r0
4: R0=inv(id=0) R10=fp0
4: (18) r1 = 0xffff88042be0b000
6: R0=inv(id=0) R1=map_ptr(id=0,off=0,ks=8,vs=8) R10=fp0
6: (79) r1 = *(u64 *)(r1 +0)
R1 invalid mem access 'map_ptr'

Errno: 13 (Permission denied)

У меня проблемы с расшифровкой этого журнала ошибок.Что пытается сказать мне ядро?

1 Ответ

0 голосов
/ 03 июня 2018

Объяснение ошибки

invalid mem access 'map_ptr' означает, что вы пытаетесь прочитать данные из недействительной ячейки памяти, в частности, той, на которую указывает указатель карты.

Действительно, ссылаясь на ваш байт-код:

   4:   18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00     r1 = 0ll
   6:   79 11 00 00 00 00 00 00     r1 = *(u64 *)(r1 + 0)

сначала вы загружаете непосредственное значение в r1, а затем читаете ячейку памяти, на которую указывает r1.Однако верификатор ядра идентифицирует инструкции BPF_LD_IMM как загрузку указателя карты.Так, это помечает r1 с типом map_ptr . Затем верификатор отклоняет инструкцию # 6 , потому что он пытается прочитать ячейку памяти, на которую указывает указатель карты (вы должны передавать ее только помощникам карты, а не использовать ее иначев программах BPF).

По сути, инструкция № 6 является недействительной и ненужной.Без него ваша программа должна пройти верификатор.


Вероятное исправление

У меня нет вашего кода перемещения, поэтому я не могу воспроизвести, но я бы предположил, что этот недействительный байт-кодкак делать с тем, как вы объявляете карту.Если вы посмотрите на образцы BPF в ядре Linux , вы увидите, что карты обычно объявляются как глобальная структура, на которую указывает аргумент первого помощника карты :

// Placeholder values for user-requested maps
struct bpf_map_def a = {
    .type = BPF_MAP_TYPE_ARRAY,
    .key_size = sizeof(u32),
    .value_size = sizeof(int),
    .max_entries = 1024,
};

#include <linux/ptrace.h>
#include <uapi/linux/bpf.h>
#include "bpf_helpers.h"

int kprobe__blk_start_request(struct pt_regs *ctx) {
  long rq = PT_REGS_PARM1(ctx);
  u64 val = bpf_ktime_get_ns();
  bpf_map_update_elem(&a, &rq, &val, BPF_ANY);
  return 0;
}
...