From 1e0768511901467c3dced0d3e7a5eb0a09102ce9 Mon Sep 17 00:00:00 2001 From: Rafael David Tinoco Date: Wed, 1 Sep 2021 17:52:52 -0300 Subject: [PATCH] helpers/kernel_features: allow kconfig override Reference: https://github.com/aquasecurity/libbpfgo/issues/60 Reference: https://github.com/aquasecurity/libbpfgo/issues/61 --- helpers/kernel_features.go | 27 +++++++++++++--- libbpfgo.go | 63 +++++++++++++++++++++++++++----------- 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/helpers/kernel_features.go b/helpers/kernel_features.go index b32e8775..5f9073ca 100644 --- a/helpers/kernel_features.go +++ b/helpers/kernel_features.go @@ -175,17 +175,33 @@ var KernelConfigKeyIDToString = map[KernelConfigOption]string{ // KernelConfig is a set of kernel configuration options (currently for running OS only) type KernelConfig struct { - configs map[KernelConfigOption]interface{} // predominantly KernelConfigOptionValue, sometimes string - needed map[KernelConfigOption]interface{} + configs map[KernelConfigOption]interface{} // predominantly KernelConfigOptionValue, sometimes string + needed map[KernelConfigOption]interface{} + KConfigFilePath string } // InitKernelConfig inits external KernelConfig object -func InitKernelConfig() (*KernelConfig, error) { +func InitKernelConfig(OSKConfigFilePath string) (*KernelConfig, error) { config := KernelConfig{} + // special case: user provided kconfig file (it MUST exist) + if len(OSKConfigFilePath) > 2 { + if _, err := os.Stat(OSKConfigFilePath); err != nil { + return nil, err + } + config.KConfigFilePath = OSKConfigFilePath // user might need to know used KConfig file in order to override kconfig for libbpf (example) + if err := config.initKernelConfig(OSKConfigFilePath); err != nil { + return nil, err + } + + return &config, nil + } + // fastpath: check config.gz in procfs first - if _, err1 := os.Stat("/proc/config.gz"); err1 == nil { - if err2 := config.initKernelConfig("/proc/config.gz"); err2 != nil { + configGZ := "/proc/config.gz" + if _, err1 := os.Stat(configGZ); err1 == nil { + config.KConfigFilePath = configGZ // same thing here + if err2 := config.initKernelConfig(configGZ); err2 != nil { return nil, err2 } @@ -200,6 +216,7 @@ func InitKernelConfig() (*KernelConfig, error) { releaseVersion := bytes.TrimRight(x.Release[:], "\x00") releaseFilePath := fmt.Sprintf("/boot/config-%s", releaseVersion) + config.KConfigFilePath = releaseFilePath // and here if err := config.initKernelConfig(releaseFilePath); err != nil { return nil, err diff --git a/libbpfgo.go b/libbpfgo.go index d724502a..2f0c2669 100644 --- a/libbpfgo.go +++ b/libbpfgo.go @@ -296,28 +296,45 @@ func errptrError(ptr unsafe.Pointer, format string, args ...interface{}) error { return fmt.Errorf(format+": %v", args...) } +type NewModuleArgs struct { + KConfigFilePath string + BTFObjPath string + BPFObjName string + BPFObjPath string + BPFObjBuff []byte +} + func NewModuleFromFile(bpfObjPath string) (*Module, error) { - return NewModuleFromFileBTF("", bpfObjPath) + + return NewModuleFromFileArgs(NewModuleArgs{ + BPFObjPath: bpfObjPath, + }) } -func NewModuleFromFileBTF(btfObjPath string, bpfObjPath string) (*Module, error) { +func NewModuleFromFileArgs(args NewModuleArgs) (*Module, error) { C.set_print_fn() if err := bumpMemlockRlimit(); err != nil { return nil, err } - if btfObjPath == "" { - btfObjPath = "/sys/kernel/btf/vmlinux" + if args.BTFObjPath == "" { + args.BTFObjPath = "/sys/kernel/btf/vmlinux" } - btfFile := C.CString(btfObjPath) - bpfFile := C.CString(bpfObjPath) + btfFile := C.CString(args.BTFObjPath) + bpfFile := C.CString(args.BPFObjPath) opts := C.struct_bpf_object_open_opts{} opts.sz = C.sizeof_struct_bpf_object_open_opts - opts.btf_custom_path = btfFile + opts.btf_custom_path = btfFile // instruct libbpf to use user provided kernel BTF file + + if strings.Compare(args.KConfigFilePath, "") != 0 { + kConfigFile := C.CString(args.KConfigFilePath) + opts.kconfig = kConfigFile // instruct libbpf to use user provided KConfigFile + defer C.free(unsafe.Pointer(kConfigFile)) + } obj := C.bpf_object__open_file(bpfFile, &opts) if C.IS_ERR_OR_NULL(unsafe.Pointer(obj)) { - return nil, errptrError(unsafe.Pointer(obj), "failed to open BPF object %s", bpfObjPath) + return nil, errptrError(unsafe.Pointer(obj), "failed to open BPF object %s", args.BPFObjPath) } C.free(unsafe.Pointer(bpfFile)) @@ -329,30 +346,40 @@ func NewModuleFromFileBTF(btfObjPath string, bpfObjPath string) (*Module, error) } func NewModuleFromBuffer(bpfObjBuff []byte, bpfObjName string) (*Module, error) { - return NewModuleFromBufferBtf("", bpfObjBuff, bpfObjName) + + return NewModuleFromFileArgs(NewModuleArgs{ + BPFObjBuff: bpfObjBuff, + BPFObjName: bpfObjName, + }) } -func NewModuleFromBufferBtf(btfObjPath string, bpfObjBuff []byte, bpfObjName string) (*Module, error) { +func NewModuleFromBufferArgs(args NewModuleArgs) (*Module, error) { C.set_print_fn() if err := bumpMemlockRlimit(); err != nil { return nil, err } - if btfObjPath == "" { - btfObjPath = "/sys/kernel/btf/vmlinux" + if args.BTFObjPath == "" { + args.BTFObjPath = "/sys/kernel/btf/vmlinux" } - btfFile := C.CString(btfObjPath) - bpfName := C.CString(bpfObjName) - bpfBuff := unsafe.Pointer(C.CBytes(bpfObjBuff)) - bpfBuffSize := C.size_t(len(bpfObjBuff)) + btfFile := C.CString(args.BTFObjPath) + bpfName := C.CString(args.BPFObjName) + bpfBuff := unsafe.Pointer(C.CBytes(args.BPFObjBuff)) + bpfBuffSize := C.size_t(len(args.BPFObjBuff)) opts := C.struct_bpf_object_open_opts{} opts.object_name = bpfName opts.sz = C.sizeof_struct_bpf_object_open_opts - opts.btf_custom_path = btfFile + opts.btf_custom_path = btfFile // instruct libbpf to use user provided kernel BTF file + + if len(args.KConfigFilePath) > 2 { + kConfigFile := C.CString(args.KConfigFilePath) + opts.kconfig = kConfigFile // instruct libbpf to use user provided KConfigFile + defer C.free(unsafe.Pointer(kConfigFile)) + } obj := C.bpf_object__open_mem(bpfBuff, bpfBuffSize, &opts) if C.IS_ERR_OR_NULL(unsafe.Pointer(obj)) { - return nil, errptrError(unsafe.Pointer(obj), "failed to open BPF object %s: %v", bpfObjName, bpfObjBuff[:20]) + return nil, errptrError(unsafe.Pointer(obj), "failed to open BPF object %s: %v", args.BPFObjName, args.BPFObjBuff[:20]) } C.free(bpfBuff)