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:
Ridwan Sharif
2020-07-09 02:01:29 -04:00
parent c4815af947
commit abffebde7b
14 changed files with 80 additions and 6 deletions
+1
View File
@@ -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",
+5
View File
@@ -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,
+4
View File
@@ -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().
//
+9
View File
@@ -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!"))...)
+7
View File
@@ -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
}
+4
View File
@@ -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
View File
@@ -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
}
+2
View File
@@ -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
View File
@@ -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(
+10
View File
@@ -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")
}
+1
View File
@@ -146,6 +146,7 @@ syscall_test(
)
syscall_test(
fuse = "True",
test = "//test/syscalls/linux:dev_test",
vfs2 = "True",
)
+1 -1
View File
@@ -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));
}
+6
View File
@@ -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.
+1
View File
@@ -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();