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:
Nicolas Lacasse
2023-03-01 20:17:37 -08:00
committed by gVisor bot
parent d12e5c3406
commit 6cc585c662
5 changed files with 74 additions and 7 deletions
+4
View File
@@ -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.
+2
View File
@@ -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",
],
)
+7
View File
@@ -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
+55 -6
View File
@@ -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
View File
@@ -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")
}