Не удалось скомпилировать код bindsnoop eBPF c вне дерева ядра.

Я пытаюсь создать программу BPF, написанную на C, в байт-код bpf. Код программы на C взят с https://github.com/iovisor/bcc/blob/master/tools/bindsnoop.py (я использовал код C из bpf_text с некоторыми настройками). Я не хотел использовать инструменты bcc python, моя цель - написать код ядра и пользовательского пространства на C, и я хотел бы построить программу ядра вне дерева ядра.

Я использую Ubuntu 20.10, и вот вывод uname -a: Linux bb-VirtualBox 5.8.0-63-generic #71-Ubuntu SMP Вт, 13 июля, 15:59:12 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

Заголовки Linux установлены, но почему-то у меня есть две директории, содержащие заголовки Linux для 5.8.0-63: /usr/src/linux-headers-5.8.0-63 и /usr/src/linux-headers-5.8.0 -63-универсальный

Я использовал этот пост, чтобы создать make-файл для своей программы: https://blogs.oracle.com/linux/post/bpf-in-depth-building-bpf-programs, поэтому make-файл выглядит следующим образом:

OBJS = kprobe_bindsnoop_kern.o

LLC ?= llc
CLANG ?= clang
INC_FLAGS = -nostdinc -isystem `$(CLANG) -print-file-name=include`
EXTRA_CFLAGS ?= -O2 -emit-llvm

linuxhdrsgen ?= /usr/src/linux-headers-5.8.0-63-generic

LINUXINCLUDE =  -I$(linuxhdrsgen)/arch/x86/include \
                -I$(linuxhdrsgen)/arch/x86/include/generated/uapi \
                -I$(linuxhdrsgen)/arch/x86/include/generated \
                -I$(linuxhdrsgen)/arch/x86/include/uapi \
                -I$(linuxhdrsgen)/arch/x86/include/generated/uapi \
                -I$(linuxhdrsgen)/include/uapi \
                -I$(linuxhdrsgen)/include/generated/uapi \
                -I$(linuxhdrsgen)/include \
                -include ${linuxhdrsgen}/include/linux/kconfig.h

all: $(OBJS)

.PHONY: clean

clean:
    rm -f $(OBJS)

INC_FLAGS = -nostdinc -isystem `$(CLANG) -print-file-name=include`

$(OBJS):  %.o:%.c
    $(CLANG) $(INC_FLAGS) \
        -D__KERNEL__ -D__ASM_SYSREG_H \
        -Wno-unused-value -Wno-pointer-sign \
        -Wno-compare-distinct-pointer-types \
        -Wno-gnu-variable-sized-type-not-at-end \
        -Wno-address-of-packed-member -Wno-tautological-compare \
        -Wno-unknown-warning-option \
        -I../include $(LINUXINCLUDE) \
        $(EXTRA_CFLAGS) -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@

А kprobe_bindsnoop_kern.c запускается из следующего набора включаемых файлов:

#include <uapi/linux/ptrace.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-compare"
#include <net/sock.h>
#pragma clang diagnostic pop
#include <net/inet_sock.h>
#include <net/net_namespace.h>
#include <bcc/proto.h>

Ниже вы можете увидеть результат компиляции:

clang -nostdinc -isystem `clang -print-file-name=include` \
    -D__KERNEL__ -D__ASM_SYSREG_H \
    -Wno-unused-value -Wno-pointer-sign \
    -Wno-compare-distinct-pointer-types \
    -Wno-gnu-variable-sized-type-not-at-end \
    -Wno-address-of-packed-member -Wno-tautological-compare \
    -Wno-unknown-warning-option \
    -I../include -I/usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/ -I/usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/generated/uapi -I/usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/generated/ -I/usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/uapi -I/usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/generated/uapi -I/usr/src/linux-headers-5.8.0-63-generic/include/uapi -I/usr/src/linux-headers-5.8.0-63-generic/include/generated/uapi -I/usr/src/linux-headers-5.8.0-63-generic/include -include /usr/src/linux-headers-5.8.0-63-generic/include/linux/kconfig.h \
    -O2 -emit-llvm -c kprobe_bindsnoop_kern.c -o -| llc -march=bpf -filetype=obj -o kprobe_bindsnoop_kern.o
In file included from kprobe_bindsnoop_kern.c:22:
In file included from /usr/src/linux-headers-5.8.0-63-generic/include/uapi/linux/ptrace.h:143:
In file included from /usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/ptrace.h:5:
In file included from /usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/segment.h:6:
/usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/alternative.h:59:2: error: unknown type name 's32'
        s32 instr_offset;       /* original instruction */
        ^
/usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/alternative.h:60:2: error: unknown type name 's32'
        s32 repl_offset;        /* offset to replacement instruction */
        ^
/usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/alternative.h:61:2: error: unknown type name 'u16'
        u16 cpuid;              /* cpuid bit set for replacement */
        ^
/usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/alternative.h:62:2: error: unknown type name 'u8'
        u8  instrlen;           /* length of original instruction */
        ^
/usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/alternative.h:63:2: error: unknown type name 'u8'
        u8  replacementlen;     /* length of new instruction */
        ^
/usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/alternative.h:64:2: error: unknown type name 'u8'
        u8  padlen;             /* length of build-time padding */
        ^
/usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/alternative.h:85:8: error: unknown type name 'bool'
extern bool skip_smp_alternatives;
       ^
In file included from kprobe_bindsnoop_kern.c:22:
In file included from /usr/src/linux-headers-5.8.0-63-generic/include/uapi/linux/ptrace.h:143:
In file included from /usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/ptrace.h:5:
In file included from /usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/segment.h:169:
In file included from /usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/cache.h:5:
In file included from /usr/src/linux-headers-5.8.0-63-generic/include/linux/linkage.h:7:
In file included from /usr/src/linux-headers-5.8.0-63-generic/include/linux/export.h:43:
In file included from /usr/src/linux-headers-5.8.0-63-generic/include/linux/compiler.h:266:
/usr/src/linux-headers-5.8.0-63-generic/include/linux/kasan-checks.h:16:15: error: unknown type name 'bool'
static inline bool __kasan_check_read(const volatile void *p, unsigned int size)
              ^
/usr/src/linux-headers-5.8.0-63-generic/include/linux/kasan-checks.h:18:9: error: use of undeclared identifier 'true'
        return true;
               ^
/usr/src/linux-headers-5.8.0-63-generic/include/linux/kasan-checks.h:20:15: error: unknown type name 'bool'
static inline bool __kasan_check_write(const volatile void *p, unsigned int size)
              ^
/usr/src/linux-headers-5.8.0-63-generic/include/linux/kasan-checks.h:22:9: error: use of undeclared identifier 'true'
        return true;
               ^
/usr/src/linux-headers-5.8.0-63-generic/include/linux/kasan-checks.h:34:15: error: unknown type name 'bool'
static inline bool kasan_check_read(const volatile void *p, unsigned int size)
              ^
/usr/src/linux-headers-5.8.0-63-generic/include/linux/kasan-checks.h:36:9: error: use of undeclared identifier 'true'
        return true;
               ^
/usr/src/linux-headers-5.8.0-63-generic/include/linux/kasan-checks.h:38:15: error: unknown type name 'bool'
static inline bool kasan_check_write(const volatile void *p, unsigned int size)
              ^
/usr/src/linux-headers-5.8.0-63-generic/include/linux/kasan-checks.h:40:9: error: use of undeclared identifier 'true'
        return true;
               ^
In file included from kprobe_bindsnoop_kern.c:22:
In file included from /usr/src/linux-headers-5.8.0-63-generic/include/uapi/linux/ptrace.h:143:
In file included from /usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/ptrace.h:5:
In file included from /usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/segment.h:169:
In file included from /usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/cache.h:5:
In file included from /usr/src/linux-headers-5.8.0-63-generic/include/linux/linkage.h:7:
In file included from /usr/src/linux-headers-5.8.0-63-generic/include/linux/export.h:43:
In file included from /usr/src/linux-headers-5.8.0-63-generic/include/linux/compiler.h:267:
/usr/src/linux-headers-5.8.0-63-generic/include/linux/kcsan-checks.h:148:67: error: unknown type name 'size_t'
static inline void __kcsan_check_access(const volatile void *ptr, size_t size,
                                                                  ^
/usr/src/linux-headers-5.8.0-63-generic/include/linux/kcsan-checks.h:164:53: error: unknown type name 'size_t'
kcsan_begin_scoped_access(const volatile void *ptr, size_t size, int type,
                                                    ^
/usr/src/linux-headers-5.8.0-63-generic/include/linux/kcsan-checks.h:184:65: error: unknown type name 'size_t'
static inline void kcsan_check_access(const volatile void *ptr, size_t size,
                                                                ^
In file included from kprobe_bindsnoop_kern.c:22:
In file included from /usr/src/linux-headers-5.8.0-63-generic/include/uapi/linux/ptrace.h:143:
In file included from /usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/ptrace.h:6:
In file included from /usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/page_types.h:7:
In file included from /usr/src/linux-headers-5.8.0-63-generic/include/linux/mem_encrypt.h:17:
In file included from /usr/src/linux-headers-5.8.0-63-generic/arch/x86/include/asm/mem_encrypt.h:15:
/usr/src/linux-headers-5.8.0-63-generic/include/linux/init.h:155:8: error: unknown type name 'bool'
extern bool rodata_enabled;
       ^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.

Я пытался добавить #include ‹linux/types.h› или #include ‹asm/types.h›, но это не помогает. Я проверил множество сообщений, таких как Ошибка компиляции кода eBPF C из дерево ядра и это как собрать BPF программа из дерева ядра, но так и не смогла получить ответ. Что мне не хватает? Любая помощь будет оценена ))


person Sheifa    schedule 28.07.2021    source источник
comment
What am I missing? Несколько определений типов.   -  person wildplasser    schedule 28.07.2021
comment
Эти s32 и u8 и так далее, скорее всего, определены где-то в каком-то заголовке скрытой копии. Вы можете заменить их на __s32, __u8 и т.п., которые вы, вероятно, извлекаете из заголовков, которые вы уже включили.   -  person Qeole    schedule 28.07.2021
comment
@wildplasser спасибо! Вы имеете в виду, что мне нужно вручную добавить все определения типов для bool, size_t, u8, u16 и т. д.? я не думаю, что это хорошая идея   -  person Sheifa    schedule 28.07.2021
comment
@Qeole Я добавил typedefs, но это не помогает - похоже, мне нужно переписать все typedefs из linux/types.h и других. Теперь он жалуется на atomic_t, phys_addr_t, bool, true/false и так далее. Кажется, это бесконечная история...   -  person Sheifa    schedule 28.07.2021
comment
Вероятно, вам не хватает включаемого файла. Может условно. Если вы действительно не можете его найти и исправить, единственный способ — написать его самостоятельно. (что не слишком сложно)   -  person wildplasser    schedule 28.07.2021
comment
@wildplasser Я уверен, что мне не хватает включаемого файла или включаемого каталога, просто интересно, что это может быть. Я согласен, что написание включаемого файла обычно не имеет большого значения, но не в этом случае. Как только я определяю отсутствующие определения типов, я сразу же получаю следующую группу недостающих определений... И мне интересно, почему это может быть скомпилировано как часть bcc и не может сделать то же самое снаружи.   -  person Sheifa    schedule 28.07.2021
comment
BPF происходит от BSD, поэтому предполагается, что хост/ядро — BSD. Перенос его на Linux — нетривиальная операция. (IIRC, вам нужно будет найти интерфейс (ы) и перевести их, например, в неразборчивый режим)   -  person wildplasser    schedule 28.07.2021
comment
Какая? Нет. Упомянутый здесь BPF — это eBPF, специфичный для Linux. Ничего общего с BSD больше нет.   -  person pchaigno    schedule 28.07.2021
comment
@wildplasser вот результат после решения проблемы u8/u16/etc: В файле, включенном из /usr/src/linux-headers-5.8.0-63-generic/include/net/sock.h:38: /usr/src /linux-headers-5.8.0-63-generic/include/linux/list.h:33:42: предупреждение: объявление 'struct list_head' не будет отображаться вне этой функции [-Wvisibility] static inline void INIT_LIST_HEAD( struct list_head *list) /usr/src/linux-headers-5.8.0-63-generic/include/linux/list.h:35:17: ошибка: неполное определение типа 'struct list_head' WRITE_ONCE(list-›next , список);   -  person Sheifa    schedule 28.07.2021
comment
@pchaigno, конечно, это eBPF, и он специфичен для Linux.   -  person Sheifa    schedule 28.07.2021
comment
Я не понимаю, почему это так сложно. Проблема не связана с тем, что я хочу использовать код из скрытой копии. Предположим, я просто хочу создать свою собственную программу, которая подключается к системному вызову привязки. В него все равно нужно включить #include ‹uapi/linux/ptrace.h› #include ‹net/sock.h› #include ‹net/inet_sock.h› Но я почему-то не могу его скомпилировать и не нахожу подсказок   -  person Sheifa    schedule 28.07.2021
comment
Вы видели более новую версию в libbpf-tools/bindsnoop.bpf.c? Вместо этого он использует libbpf, и его может быть проще портировать из bcc.   -  person Qeole    schedule 28.07.2021
comment
@Qeole спасибо, я проверю   -  person Sheifa    schedule 28.07.2021
comment
Привет @Qeole, спасибо за идею, код bindsnoop.bpf.c очень полезен   -  person Sheifa    schedule 29.07.2021


Ответы (1)


Спасибо всем, кто пытался мне помочь! Наконец, проблема оказалась оооочень простой — нужно было просто изменить порядок включаемых каталогов, указанный в make-файле.

Просто переместил -I$(linuxhdrsgen)/include на первое место в списке, и это решило проблему. Это означает, что теперь список подключаемых каталогов выглядит следующим образом:

LINUXINCLUDE = -I$(linuxhdrsgen)/include
-I$(linuxhdrsgen)/arch/x86/include
-I$(linuxhdrsgen)/arch/x86/include/generated/uapi
-I$(linuxhdrsgen)/arch/x86/include/generated
-I$(linuxhdrsgen)/arch/x86/include/uapi
-I$(linuxhdrsgen)/arch/x86/include/generated /uapi
-I$(linuxhdrsgen)/include/uapi
-I$(linuxhdrsgen)/include/generated/uapi
-include ${linuxhdrsgen}/include/linux/kconfig.h

person Sheifa    schedule 29.07.2021
comment
Рад видеть, что у вас все получилось, молодцы! - person Qeole; 29.07.2021