mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Gate FUSE behind a runsc flag
This change gates all FUSE commands (by gating /dev/fuse) behind a runsc flag. In order to use FUSE commands, use the --fuse flag with the --vfs2 flag. Check if FUSE is enabled by running dmesg in the sandbox.
This commit is contained in:
@@ -12,6 +12,7 @@ go_library(
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/context",
|
||||
"//pkg/sentry/fsimpl/devtmpfs",
|
||||
"//pkg/sentry/kernel",
|
||||
"//pkg/sentry/vfs",
|
||||
"//pkg/syserror",
|
||||
"//pkg/usermem",
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/devtmpfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
@@ -30,6 +31,10 @@ type fuseDevice struct{}
|
||||
|
||||
// Open implements vfs.Device.Open.
|
||||
func (fuseDevice) Open(ctx context.Context, mnt *vfs.Mount, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
if !kernel.FUSEEnabled {
|
||||
return nil, syserror.ENOENT
|
||||
}
|
||||
|
||||
var fd DeviceFD
|
||||
if err := fd.vfsfd.Init(&fd, opts.Flags, mnt, vfsd, &vfs.FileDescriptionOptions{
|
||||
UseDentryMetadata: true,
|
||||
|
||||
@@ -81,6 +81,10 @@ import (
|
||||
// easy access everywhere. To be removed once VFS2 becomes the default.
|
||||
var VFS2Enabled = false
|
||||
|
||||
// FUSEEnabled is set to true when FUSE is enabled. Added as a global for allow
|
||||
// easy access everywhere. To be removed once FUSE is completed.
|
||||
var FUSEEnabled = false
|
||||
|
||||
// Kernel represents an emulated Linux kernel. It must be initialized by calling
|
||||
// Init() or LoadFrom().
|
||||
//
|
||||
|
||||
@@ -98,6 +98,15 @@ func (s *syslog) Log() []byte {
|
||||
s.msg = append(s.msg, []byte(fmt.Sprintf(format, time, selectMessage()))...)
|
||||
}
|
||||
|
||||
if VFS2Enabled {
|
||||
time += rand.Float64() / 2
|
||||
s.msg = append(s.msg, []byte(fmt.Sprintf(format, time, "Setting up VFS2..."))...)
|
||||
if FUSEEnabled {
|
||||
time += rand.Float64() / 2
|
||||
s.msg = append(s.msg, []byte(fmt.Sprintf(format, time, "Setting up FUSE..."))...)
|
||||
}
|
||||
}
|
||||
|
||||
time += rand.Float64() / 2
|
||||
s.msg = append(s.msg, []byte(fmt.Sprintf(format, time, "Ready!"))...)
|
||||
|
||||
|
||||
@@ -274,6 +274,9 @@ type Config struct {
|
||||
|
||||
// Enables VFS2 (not plumbled through yet).
|
||||
VFS2 bool
|
||||
|
||||
// Enables FUSE usage (not plumbled through yet).
|
||||
FUSE bool
|
||||
}
|
||||
|
||||
// ToFlags returns a slice of flags that correspond to the given Config.
|
||||
@@ -325,5 +328,9 @@ func (c *Config) ToFlags() []string {
|
||||
f = append(f, "--vfs2=true")
|
||||
}
|
||||
|
||||
if c.FUSE {
|
||||
f = append(f, "--fuse=true")
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
@@ -205,6 +205,10 @@ func New(args Args) (*Loader, error) {
|
||||
// Is this a VFSv2 kernel?
|
||||
if args.Conf.VFS2 {
|
||||
kernel.VFS2Enabled = true
|
||||
if args.Conf.FUSE {
|
||||
kernel.FUSEEnabled = true
|
||||
}
|
||||
|
||||
vfs2.Override()
|
||||
}
|
||||
|
||||
|
||||
+10
-4
@@ -86,9 +86,12 @@ func registerFilesystems(k *kernel.Kernel) error {
|
||||
return fmt.Errorf("registering ttydev: %w", err)
|
||||
}
|
||||
|
||||
if err := fuse.Register(vfsObj); err != nil {
|
||||
return fmt.Errorf("registering fusedev: %w", err)
|
||||
if kernel.FUSEEnabled {
|
||||
if err := fuse.Register(vfsObj); err != nil {
|
||||
return fmt.Errorf("registering fusedev: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := tundev.Register(vfsObj); err != nil {
|
||||
return fmt.Errorf("registering tundev: %v", err)
|
||||
}
|
||||
@@ -110,8 +113,11 @@ func registerFilesystems(k *kernel.Kernel) error {
|
||||
if err := tundev.CreateDevtmpfsFiles(ctx, a); err != nil {
|
||||
return fmt.Errorf("creating tundev devtmpfs files: %v", err)
|
||||
}
|
||||
if err := fuse.CreateDevtmpfsFile(ctx, a); err != nil {
|
||||
return fmt.Errorf("creating fusedev devtmpfs files: %w", err)
|
||||
|
||||
if kernel.FUSEEnabled {
|
||||
if err := fuse.CreateDevtmpfsFile(ctx, a); err != nil {
|
||||
return fmt.Errorf("creating fusedev devtmpfs files: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ var (
|
||||
referenceLeakMode = flag.String("ref-leak-mode", "disabled", "sets reference leak check mode: disabled (default), log-names, log-traces.")
|
||||
cpuNumFromQuota = flag.Bool("cpu-num-from-quota", false, "set cpu number to cpu quota (least integer greater or equal to quota value, but not less than 2)")
|
||||
vfs2Enabled = flag.Bool("vfs2", false, "TEST ONLY; use while VFSv2 is landing. This uses the new experimental VFS layer.")
|
||||
fuseEnabled = flag.Bool("fuse", false, "TEST ONLY; use while FUSE in VFSv2 is landing. This allows the use of the new experimental FUSE filesystem.")
|
||||
|
||||
// Test flags, not to be used outside tests, ever.
|
||||
testOnlyAllowRunAsCurrentUserWithoutChroot = flag.Bool("TESTONLY-unsafe-nonroot", false, "TEST ONLY; do not ever use! This skips many security measures that isolate the host from the sandbox.")
|
||||
@@ -242,6 +243,7 @@ func main() {
|
||||
OverlayfsStaleRead: *overlayfsStaleRead,
|
||||
CPUNumFromQuota: *cpuNumFromQuota,
|
||||
VFS2: *vfs2Enabled,
|
||||
FUSE: *fuseEnabled,
|
||||
QDisc: queueingDiscipline,
|
||||
TestOnlyAllowRunAsCurrentUserWithoutChroot: *testOnlyAllowRunAsCurrentUserWithoutChroot,
|
||||
TestOnlyTestNameEnv: *testOnlyTestNameEnv,
|
||||
|
||||
+19
-1
@@ -61,7 +61,8 @@ def _syscall_test(
|
||||
file_access = "exclusive",
|
||||
overlay = False,
|
||||
add_uds_tree = False,
|
||||
vfs2 = False):
|
||||
vfs2 = False,
|
||||
fuse = False):
|
||||
# Prepend "runsc" to non-native platform names.
|
||||
full_platform = platform if platform == "native" else "runsc_" + platform
|
||||
|
||||
@@ -73,6 +74,8 @@ def _syscall_test(
|
||||
name += "_overlay"
|
||||
if vfs2:
|
||||
name += "_vfs2"
|
||||
if fuse:
|
||||
name += "_fuse"
|
||||
if network != "none":
|
||||
name += "_" + network + "net"
|
||||
|
||||
@@ -107,6 +110,7 @@ def _syscall_test(
|
||||
"--overlay=" + str(overlay),
|
||||
"--add-uds-tree=" + str(add_uds_tree),
|
||||
"--vfs2=" + str(vfs2),
|
||||
"--fuse=" + str(fuse),
|
||||
]
|
||||
|
||||
# Call the rule above.
|
||||
@@ -129,6 +133,7 @@ def syscall_test(
|
||||
add_uds_tree = False,
|
||||
add_hostinet = False,
|
||||
vfs2 = False,
|
||||
fuse = False,
|
||||
tags = None):
|
||||
"""syscall_test is a macro that will create targets for all platforms.
|
||||
|
||||
@@ -188,6 +193,19 @@ def syscall_test(
|
||||
vfs2 = True,
|
||||
)
|
||||
|
||||
if vfs2 and fuse:
|
||||
_syscall_test(
|
||||
test = test,
|
||||
shard_count = shard_count,
|
||||
size = size,
|
||||
platform = default_platform,
|
||||
use_tmpfs = use_tmpfs,
|
||||
add_uds_tree = add_uds_tree,
|
||||
tags = platforms[default_platform] + vfs2_tags,
|
||||
vfs2 = True,
|
||||
fuse = True,
|
||||
)
|
||||
|
||||
# TODO(gvisor.dev/issue/1487): Enable VFS2 overlay tests.
|
||||
if add_overlay:
|
||||
_syscall_test(
|
||||
|
||||
@@ -47,6 +47,7 @@ var (
|
||||
fileAccess = flag.String("file-access", "exclusive", "mounts root in exclusive or shared mode")
|
||||
overlay = flag.Bool("overlay", false, "wrap filesystem mounts with writable tmpfs overlay")
|
||||
vfs2 = flag.Bool("vfs2", false, "enable VFS2")
|
||||
fuse = flag.Bool("fuse", false, "enable FUSE")
|
||||
parallel = flag.Bool("parallel", false, "run tests in parallel")
|
||||
runscPath = flag.String("runsc", "", "path to runsc binary")
|
||||
|
||||
@@ -149,6 +150,9 @@ func runRunsc(tc gtest.TestCase, spec *specs.Spec) error {
|
||||
}
|
||||
if *vfs2 {
|
||||
args = append(args, "-vfs2")
|
||||
if *fuse {
|
||||
args = append(args, "-fuse")
|
||||
}
|
||||
}
|
||||
if *debug {
|
||||
args = append(args, "-debug", "-log-packets=true")
|
||||
@@ -358,6 +362,12 @@ func runTestCaseRunsc(testBin string, tc gtest.TestCase, t *testing.T) {
|
||||
vfsVar := "GVISOR_VFS"
|
||||
if *vfs2 {
|
||||
env = append(env, vfsVar+"=VFS2")
|
||||
fuseVar := "FUSE_ENABLED"
|
||||
if *fuse {
|
||||
env = append(env, fuseVar+"=TRUE")
|
||||
} else {
|
||||
env = append(env, fuseVar+"=FALSE")
|
||||
}
|
||||
} else {
|
||||
env = append(env, vfsVar+"=VFS1")
|
||||
}
|
||||
|
||||
@@ -146,6 +146,7 @@ syscall_test(
|
||||
)
|
||||
|
||||
syscall_test(
|
||||
fuse = "True",
|
||||
test = "//test/syscalls/linux:dev_test",
|
||||
vfs2 = "True",
|
||||
)
|
||||
|
||||
@@ -156,7 +156,7 @@ TEST(DevTest, TTYExists) {
|
||||
TEST(DevTest, OpenDevFuse) {
|
||||
// Note(gvisor.dev/issue/3076) This won't work in the sentry until the new
|
||||
// device registration is complete.
|
||||
SKIP_IF(IsRunningWithVFS1() || IsRunningOnGvisor());
|
||||
SKIP_IF(IsRunningWithVFS1() || IsRunningOnGvisor() || !IsFUSEEnabled());
|
||||
|
||||
ASSERT_NO_ERRNO_AND_VALUE(Open("/dev/fuse", O_RDONLY));
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace testing {
|
||||
|
||||
constexpr char kGvisorNetwork[] = "GVISOR_NETWORK";
|
||||
constexpr char kGvisorVfs[] = "GVISOR_VFS";
|
||||
constexpr char kFuseEnabled[] = "FUSE_ENABLED";
|
||||
|
||||
bool IsRunningOnGvisor() { return GvisorPlatform() != Platform::kNative; }
|
||||
|
||||
@@ -68,6 +69,11 @@ bool IsRunningWithVFS1() {
|
||||
return strcmp(env, "VFS1") == 0;
|
||||
}
|
||||
|
||||
bool IsFUSEEnabled() {
|
||||
const char* env = getenv(kFuseEnabled);
|
||||
return env && strcmp(env, "TRUE") == 0;
|
||||
}
|
||||
|
||||
// Inline cpuid instruction. Preserve %ebx/%rbx register. In PIC compilations
|
||||
// %ebx contains the address of the global offset table. %rbx is occasionally
|
||||
// used to address stack variables in presence of dynamic allocas.
|
||||
|
||||
@@ -225,6 +225,7 @@ const std::string GvisorPlatform();
|
||||
bool IsRunningWithHostinet();
|
||||
// TODO(gvisor.dev/issue/1624): Delete once VFS1 is gone.
|
||||
bool IsRunningWithVFS1();
|
||||
bool IsFUSEEnabled();
|
||||
|
||||
#ifdef __linux__
|
||||
void SetupGvisorDeathTest();
|
||||
|
||||
Reference in New Issue
Block a user