1
votes

I am trying to load a BPF program using the bpf syscall but I am receiving invalid argument (EINVAL) on return. From the man page, the possible reasons for this are:

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.

So it seems there is something wrong with my BPF program. My BPF program is as follows:

#include <uapi/linux/bpf.h>

int prog(struct pt_regs *ctx)
{
    return 0;
}

Which surely cannot have anything wrong with it.

I am compiling with the Makefile here (I removed most of the code from test_overhead_kprobe_kern.c to give a very simple program for testing).

What could be wrong with my program that caused it to get rejected?

uname -a: Linux ubuntu1710 4.13.0-32-generic #35-Ubuntu SMP Thu Jan 25 09:13:46 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

My full userspace code (in Go) is as follows:

package main

/*
#include <stdio.h>
#include <stdlib.h>

void print(char* s) {
 printf("%s\n", 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("%s\n", 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("%s\n", logBuf)
    //cs := C.CString("XXXXXXXXXX")
    C.print(logStr)
    //fmt.Printf("%c\n", *logStr)

    if ret != 0 || err != 0 {
        //fmt.Printf("%#v %d\n", logBuf, unsafe.Sizeof(lba))
        return fmt.Errorf("Unable to load program: ret: %d: %s", int(ret), err)
    }

    return nil
}
1
Does it work if you add SEC("kprobe/__set_task_comm") back?pchaigno
I had to add #include "bpf_helpers.h" but no it still doesn't work, with the same error :/dippynark
Ok. You had no warning during compilation? It should complain about the missing #include <linux/ptrace.h> for struct pt_regs AFAIK.pchaigno
Yeah I had a warning, but it still compiled without an error. I added back #include <linux/ptrace.h> and it compiled without warnings or errors but I received the same error from the bpf syscalldippynark
Ok. What about the two last lines you removed, about the version and the license? Have you tried with those?pchaigno

1 Answers

1
votes

As Qeole pointed out in your previous question, your userspace Go program needs to extract the BPF instructions (.text section) from the object file. Otherwise, the kernel will try to interpret the binary content as BPF instructions and inevitably fail.