Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/containers: add oci-seccomp-bpf-hook #96761

Merged
merged 1 commit into from Sep 2, 2020
Merged

Conversation

saschagrunert
Copy link
Member

@saschagrunert saschagrunert commented Aug 31, 2020

Motivation for this change

Add the OCI seccomp bpf hook per default to the contianers.conf file. The hook will result in a no-op if the annotation is not present.

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS linux)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Ensured that relevant documentation is up to date
  • Fits CONTRIBUTING.md.

cc @NixOS/podman

Copy link
Contributor

@zowoq zowoq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes for now as this is a large dependency to add. (kernel, etc)

@zowoq
Copy link
Contributor

zowoq commented Aug 31, 2020

The 20.09 branch off is very soon, I'd like to leave this until after. We can backport it if we do go ahead with it.

@saschagrunert
Copy link
Member Author

The 20.09 branch off is very soon, I'd like to leave this until after. We can backport it if we do go ahead with it.

Sounds good. Do we wanna make it optional?

I'm still not sure if we need something like programs.bcc.enable = true;, but I tested it in nixos-shell and the current patch worked there.

@zowoq
Copy link
Contributor

zowoq commented Aug 31, 2020

programs.bcc uses config.boot.kernelPackages.bcc so it uses whatever the system kernel is set to, this hook will always depend on the default kernel, does that make a difference?

@saschagrunert
Copy link
Member Author

saschagrunert commented Sep 1, 2020

programs.bcc uses config.boot.kernelPackages.bcc so it uses whatever the system kernel is set to, this hook will always depend on the default kernel, does that make a difference?

Yes I think so. The hook has to choose the same kernel sources like present on the system. I switched to the latest 5.8 kernel and applied a small patch to the hook:

diff --git a/oci-seccomp-bpf-hook.go b/oci-seccomp-bpf-hook.go
index 416c6f6..6d075d9 100644
--- a/oci-seccomp-bpf-hook.go
+++ b/oci-seccomp-bpf-hook.go
@@ -10,7 +10,6 @@ import (
 	"io/ioutil"
 	"log/syslog"
 	"os"
-	"os/exec"
 	"os/signal"
 	"path/filepath"
 	"runtime"
@@ -20,6 +19,7 @@ import (
 	"sync"
 	"syscall"
 	"time"
+	"unsafe"
 
 	"github.com/iovisor/gobpf/bcc"
 	spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -30,6 +30,12 @@ import (
 	logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
 )
 
+/*
+#cgo LDFLAGS: -lbcc
+#include <bcc/bcc_common.h>
+*/
+import "C"
+
 const (
 	// BPFTimeout is the timeout in seconds to wait for the child process to signal
 	// that the eBPF program finished compiling and attached to the tracee.
@@ -95,23 +101,25 @@ func main() {
 	}
 }
 
-// modprobe the specified module.
-func modprobe(module string) error {
-	bin, err := exec.LookPath("modprobe")
-	if err != nil {
-		// Fallback to `/usr/sbin/modprobe`.  The environment may be
-		// empty.  If that doesn't exist either, we'll fail below.
-		bin = "/usr/sbin/modprobe"
+func initBPF() error {
+	logrus.Info("Initializing BFP")
+	cs := C.CString("")
+	defer C.free(unsafe.Pointer(cs))
+
+	c := C.bpf_module_create_c_from_string(cs, 2, nil, 0, true, nil)
+	if c == nil {
+		return errors.New("building BPF module from string failed")
+
 	}
-	return exec.Command(bin, module).Run()
+	logrus.Info("BFP up and running")
+	return nil
 }
 
 // detachAndTrace re-executes the current executable to "fork" in go-ish way and
 // traces the provided PID.
 func detachAndTrace() error {
-	logrus.Info("Trying to load `kheaders` module")
-	if err := modprobe("kheaders"); err != nil {
-		logrus.Infof("Loading `kheaders` failed, continuing in hope kernel headers reside on disk: %v", err)
+	if err := initBPF(); err != nil {
+		return errors.Wrap(err, "init BPF")
 	}
 
 	// Read the State spec from stdin and unmarshal it.

Then running the hook should build an example BPF module which automatically loads the kernel headers, but:

Error: chdir(/nix/store/6wccjk70rnw61jy2xfn357v6aljy394v-linux-5.7.18-dev/lib/modules/5.8.4/build):

The funny part is now, this issue only happens if the hook gets executed through Podman. If I run the hook manually (with sudo on my current user), then it seems to pick the right path and every further invocation of the hook (even through podman) will work from now on.

I applied a small patch

@zowoq
Copy link
Contributor

zowoq commented Sep 1, 2020

@saschagrunert Can you try #96892 please?

@saschagrunert
Copy link
Member Author

Requires now #96892

@zowoq
Copy link
Contributor

zowoq commented Sep 1, 2020

Sorry, I focused on the programs.bcc part and didn't comment on this:

Do we wanna make it optional?

I'd be in favour of making it optional.

@saschagrunert saschagrunert changed the title containers: add oci-seccomp-bpf-hook nixos/containers: add oci-seccomp-bpf-hook Sep 1, 2020
@saschagrunert
Copy link
Member Author

Sorry, I focused on the programs.bcc part and didn't comment on this:

Do we wanna make it optional?

I'd be in favour of making it optional.

Sounds good, changed the implementation to only modify the config if the hook is enabled.

@saschagrunert
Copy link
Member Author

Rebased on top of the latest master to resolve the issues.

@zowoq
Copy link
Contributor

zowoq commented Sep 2, 2020

Another nit, sorry. Could you flip the enable around please?

diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index b82f64ea05f..de97ba3f7bb 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -43,7 +43,7 @@ in
         '';
       };
 
-    enableOciSeccompBpfHook = mkOption {
+    ociSeccompBpfHook.enable = mkOption {
       type = types.bool;
       default = false;
       description = "Enable the OCI seccomp BPF hook";
@@ -122,7 +122,7 @@ in
       [network]
       cni_plugin_dirs = ["${pkgs.cni-plugins}/bin/"]
 
-      ${lib.optionalString (cfg.enableOciSeccompBpfHook == true) ''
+      ${lib.optionalString (cfg.ociSeccompBpfHook.enable == true) ''
       [engine]
       hooks_dir = [
         "${config.boot.kernelPackages.oci-seccomp-bpf-hook}",

Signed-off-by: Sascha Grunert <sgrunert@suse.com>
@saschagrunert
Copy link
Member Author

Another nit, sorry. Could you flip the enable around please?

Sure thing, fixed as suggested 👍

@zowoq
Copy link
Contributor

zowoq commented Sep 2, 2020

As it's now optional and using the system kernel I think it's fine to include in the next release.

Copy link
Contributor

@zowoq zowoq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@zowoq zowoq merged commit 27b0c4b into NixOS:master Sep 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants