mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
runsc requires CAP_NET_RAW with network=host and raw sockets enabled.
We must have CAP_NET_RAW to create raw sockets with hostinet. This change makes the runsc Loader fail if hostinet+raw sockets are configured but we do not have the necessary capability. PiperOrigin-RevId: 513417124
This commit is contained in:
committed by
gVisor bot
parent
d12e5c3406
commit
6cc585c662
@@ -56,6 +56,10 @@ var (
|
||||
runscPath = flag.String("runsc", os.Getenv("RUNTIME"), "path to runsc binary")
|
||||
// Note: flag overlay is already taken by runsc.
|
||||
isRunningWithOverlay = flag.Bool("test-overlay", BoolFromEnv("TEST_OVERLAY", false), "whether test is running with --overlay2")
|
||||
|
||||
// TestEnvSupportsRawSockets indicates whether a test sandbox can
|
||||
// create raw sockets.
|
||||
TestEnvSupportsRawSockets = true
|
||||
)
|
||||
|
||||
// StringFromEnv returns the value of the named environment variable, or `def` if unset/empty.
|
||||
|
||||
@@ -117,6 +117,7 @@ go_library(
|
||||
"//runsc/specutils",
|
||||
"//runsc/specutils/seccomp",
|
||||
"@com_github_opencontainers_runtime_spec//specs-go:go_default_library",
|
||||
"@com_github_syndtr_gocapability//capability:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_x_sys//unix:go_default_library",
|
||||
],
|
||||
@@ -143,6 +144,7 @@ go_test(
|
||||
"//runsc/flag",
|
||||
"//runsc/fsgofer",
|
||||
"@com_github_opencontainers_runtime_spec//specs-go:go_default_library",
|
||||
"@com_github_syndtr_gocapability//capability:go_default_library",
|
||||
"@org_golang_x_sys//unix:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
gtime "time"
|
||||
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/bpf"
|
||||
@@ -1116,6 +1117,12 @@ func newRootNetworkNamespace(conf *config.Config, clock tcpip.Clock, uniqueID st
|
||||
// Run().
|
||||
switch conf.Network {
|
||||
case config.NetworkHost:
|
||||
// If configured for raw socket support with host network
|
||||
// stack, make sure that we have CAP_NET_RAW the host,
|
||||
// otherwise we can't make raw sockets.
|
||||
if conf.EnableRaw && !specutils.HasCapabilities(capability.CAP_NET_RAW) {
|
||||
return nil, fmt.Errorf("configuring network=host with raw sockets requires CAP_NET_RAW capability")
|
||||
}
|
||||
// No network namespacing support for hostinet yet, hence creator is nil.
|
||||
return inet.NewRootNamespace(hostinet.NewStack(), nil), nil
|
||||
|
||||
|
||||
@@ -18,10 +18,12 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/control/server"
|
||||
"gvisor.dev/gvisor/pkg/fspath"
|
||||
@@ -103,12 +105,12 @@ func startGofer(root string) (int, func(), error) {
|
||||
return sandboxEnd, cleanup, nil
|
||||
}
|
||||
|
||||
func createLoader(spec *specs.Spec) (*Loader, func(), error) {
|
||||
fd, err := server.CreateSocket(fmt.Sprintf("\x00loader-test.%010d", rand.Int())[:10])
|
||||
func createLoader(conf *config.Config, spec *specs.Spec) (*Loader, func(), error) {
|
||||
sock := fmt.Sprintf("\x00loader-test.%010d", rand.Int())
|
||||
fd, err := server.CreateSocket(sock)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
conf := testConfig()
|
||||
sandEnd, cleanup, err := startGofer(spec.Root.Path)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -143,7 +145,7 @@ func createLoader(spec *specs.Spec) (*Loader, func(), error) {
|
||||
|
||||
// TestRun runs a simple application in a sandbox and checks that it succeeds.
|
||||
func TestRun(t *testing.T) {
|
||||
l, cleanup, err := createLoader(testSpec())
|
||||
l, cleanup, err := createLoader(testConfig(), testSpec())
|
||||
if err != nil {
|
||||
t.Fatalf("error creating loader: %v", err)
|
||||
}
|
||||
@@ -181,7 +183,7 @@ func TestRun(t *testing.T) {
|
||||
// TestStartSignal tests that the controller Start message will cause
|
||||
// WaitForStartSignal to return.
|
||||
func TestStartSignal(t *testing.T) {
|
||||
l, cleanup, err := createLoader(testSpec())
|
||||
l, cleanup, err := createLoader(testConfig(), testSpec())
|
||||
if err != nil {
|
||||
t.Fatalf("error creating loader: %v", err)
|
||||
}
|
||||
@@ -228,6 +230,53 @@ func TestStartSignal(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test that network=host with raw sockets enabled requires CAP_NET_RAW on the
|
||||
// host.
|
||||
func TestHostnetWithRawSockets(t *testing.T) {
|
||||
// Drop CAP_NET_RAW from effective capabilities, if we have it.
|
||||
pid := os.Getpid()
|
||||
caps, err := capability.NewPid2(os.Getpid())
|
||||
if err != nil {
|
||||
t.Fatalf("error getting capabilities for pid %d: %v", pid, err)
|
||||
}
|
||||
if err := caps.Load(); err != nil {
|
||||
t.Fatalf("error loading capabilities: %v", err)
|
||||
}
|
||||
if caps.Get(capability.EFFECTIVE, capability.CAP_NET_RAW) {
|
||||
caps.Unset(capability.EFFECTIVE, capability.CAP_NET_RAW)
|
||||
if err := caps.Apply(capability.EFFECTIVE); err != nil {
|
||||
t.Fatalf("error applying capabilities")
|
||||
}
|
||||
// Be nice and add it back when we are done.
|
||||
defer func() {
|
||||
caps.Set(capability.EFFECTIVE, capability.CAP_NET_RAW)
|
||||
if err := caps.Apply(capability.EFFECTIVE); err != nil {
|
||||
t.Fatalf("error restoring capabilities")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Configure host network with raw sockets.
|
||||
conf := testConfig()
|
||||
conf.Network = config.NetworkHost
|
||||
conf.EnableRaw = true
|
||||
|
||||
// Creating loader should fail.
|
||||
l, err := New(Args{
|
||||
ID: "should-fail",
|
||||
Spec: testSpec(),
|
||||
Conf: conf,
|
||||
})
|
||||
if err == nil {
|
||||
l.Destroy()
|
||||
t.Fatalf("expected loader.New() to fail but it did not")
|
||||
}
|
||||
// Error message must be about CAP_NET_RAW.
|
||||
if !strings.Contains(err.Error(), "CAP_NET_RAW") {
|
||||
t.Errorf("expected error to contain CAP_NET_RAW but got %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
type CreateMountTestcase struct {
|
||||
name string
|
||||
// Spec that will be used to create the mount manager. Note
|
||||
@@ -410,7 +459,7 @@ func TestCreateMountNamespace(t *testing.T) {
|
||||
spec.Root = tc.spec.Root
|
||||
|
||||
t.Logf("Using root: %q", spec.Root.Path)
|
||||
l, loaderCleanup, err := createLoader(spec)
|
||||
l, loaderCleanup, err := createLoader(testConfig(), spec)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create loader: %v", err)
|
||||
}
|
||||
|
||||
+6
-1
@@ -223,13 +223,18 @@ func runRunsc(tc *gtest.TestCase, spec *specs.Spec) error {
|
||||
"-log-format=text",
|
||||
"-TESTONLY-unsafe-nonroot=true",
|
||||
"-TESTONLY-allow-packet-endpoint-write=true",
|
||||
"-net-raw=true",
|
||||
fmt.Sprintf("-panic-signal=%d", unix.SIGTERM),
|
||||
fmt.Sprintf("-iouring=%t", *ioUring),
|
||||
"-watchdog-action=panic",
|
||||
"-platform", *platform,
|
||||
"-file-access", *fileAccess,
|
||||
}
|
||||
|
||||
if *network == "host" && !testutil.TestEnvSupportsRawSockets {
|
||||
log.Warningf("Testing with network=host but test environment does not support raw sockets. Raw socket support will be disabled.")
|
||||
} else {
|
||||
args = append(args, "-net-raw")
|
||||
}
|
||||
if *overlay {
|
||||
args = append(args, "-overlay2=all:dir=/tmp")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user