C-尝试加载BPF程序时无效的参数(Einval)



我正在尝试使用bpf SYSCALL加载BPF程序,但我将在返回时接收invalid argument(EINVAL(。从"人"页面中,可能的原因是:

EINVAL
For BPF_PROG_LOAD, indicates an attempt to load an invalid program. 
eBPF programs can be deemed invalid due to unrecognized instructions, 
the use of reserved fields, jumps out of range, infinite loops or calls 
of unknown functions.

因此,我的BPF程序似乎有问题。我的BPF程序如下:

#include <uapi/linux/bpf.h>
int prog(struct pt_regs *ctx)
{
    return 0;
}

肯定不会有任何问题。

我在此处使用Makefile编译(我从test_overhead_kprobe_kern.c中删除了大部分代码,以提供一个非常简单的测试程序(。

我的程序可能被拒绝了什么?

uname -a:linux ubuntu1710 4.13.0-32代基因#35-ubuntu smp thu thu Jan 25 09:13:13:46 UTC 2018 x86_64 x86_64 x86_64 x86_64 x86_64 gnu/linux/linux

我的完整用户空间代码(在GO中(如下:

package main
/*
#include <stdio.h>
#include <stdlib.h>
void print(char* s) {
 printf("%sn", s);
}
*/
import "C"
import (
    "unsafe"
    "golang.org/x/sys/unix"
    "github.com/cilium/cilium/pkg/bpf"
)
import (
    "fmt"
    "io/ioutil"
)
const (
    bufferSize           = 256
    sessionIDHTTPHeader  = "X-Session-ID"
    defaultServerAddress = "localhost"
    defaultPort          = 5050
)
const (
    BPF_PROG_TYPE_UNSPEC        = 0
    BPF_PROG_TYPE_SOCKET_FILTER = 1
    BPF_PROG_TYPE_KPROBE        = 2
    BPF_PROG_TYPE_SCHED_CLS     = 3
    BPF_PROG_TYPE_SCHED_ACT     = 4
)
type ttyWrite struct {
    Count     int32
    Buf       [bufferSize]byte
    SessionID int32
}
func main() { 
  //for i := 0; i < 6; i++ {
    //b, err := ioutil.ReadFile(fmt.Sprintf("bpf/test%d.o", i))
    b, err := ioutil.ReadFile("bpf/bpf_tty.o")
    if err != nil {
        fmt.Print(err)
    }
    err = loadProgram(BPF_PROG_TYPE_KPROBE, unsafe.Pointer(&b), len(b))
    if err != nil {
        fmt.Printf("%sn", err)
    }
    //}
}
func loadProgram(progType int, insns unsafe.Pointer, insnCnt int) error {
    licenseBuf := "GPL"
    licenseStr := C.CString(licenseBuf)
    defer C.free(unsafe.Pointer(licenseStr))
    logStr := C.CString("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
    defer C.free(unsafe.Pointer(logStr))
    lba := struct {
        progType uint32
        //pad0        [4]byte
        insnCnt uint32
        //pad1        [4]byte
        insns    uint64
        license  uint64
        logLevel uint32
        //pad2        [4]byte
        logSize uint32
        //pad3    [4]byte
        logBuf  uint64
        kernVersion uint32
        //pad4        [4]byte
    }{
        progType: uint32(progType),     
        insnCnt:  uint32(insnCnt),
        insns:    uint64(uintptr(insns)),
        license:  uint64(uintptr(unsafe.Pointer(licenseStr))),      
        logLevel: uint32(1),
        logSize:  uint32(50),
        logBuf:   uint64(uintptr(unsafe.Pointer(logStr))),
        //logBuf: uint64(uintptr(unsafe.Pointer(bufStr))),
        // /usr/src/linux-headers-4.13.0-32-generic/include/generated/uapi/linux/version.h
        kernVersion: uint32(265485),
    }
    ret, _, err := unix.Syscall(
        unix.SYS_BPF,
        bpf.BPF_PROG_LOAD,
        uintptr(unsafe.Pointer(&lba)),
        unsafe.Sizeof(lba),
    )
    //fmt.Printf("%sn", logBuf)
    //cs := C.CString("XXXXXXXXXX")
    C.print(logStr)
    //fmt.Printf("%cn", *logStr)
    if ret != 0 || err != 0 {
        //fmt.Printf("%#v %dn", logBuf, unsafe.Sizeof(lba))
        return fmt.Errorf("Unable to load program: ret: %d: %s", int(ret), err)
    }
    return nil
}

正如Qeole在您的上一个问题中指出的那样,您的用户空间GO程序需要从对象文件中提取BPF指令(.text部分(。否则,内核将尝试将二进制内容解释为BPF指令,而不可避免地会失败。

最新更新