Skip to content

Commit 00a38c0

Browse files
committed
Merge pull request #12902 from shayonj:s/export-gofer-helpers
PiperOrigin-RevId: 897959963
2 parents 8b592e2 + 9a8e0ed commit 00a38c0

12 files changed

Lines changed: 491 additions & 363 deletions

File tree

runsc/cmd/BUILD

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ go_library(
3535
srcs = [
3636
"boot.go",
3737
"boot_impl.go",
38-
"capability.go",
3938
"checkpoint.go",
4039
"checkpoint_impl.go",
4140
"chroot.go",
@@ -113,6 +112,7 @@ go_library(
113112
"//pkg/urpc",
114113
"//runsc/boot",
115114
"//runsc/cmd/metricserver/metricservercmd",
115+
"//runsc/cmd/sandboxsetup",
116116
"//runsc/cmd/util",
117117
"//runsc/config",
118118
"//runsc/console",
@@ -165,6 +165,7 @@ go_test(
165165
"//pkg/sentry/control",
166166
"//pkg/sentry/kernel/auth",
167167
"//pkg/test/testutil",
168+
"//runsc/cmd/sandboxsetup",
168169
"//runsc/cmd/util",
169170
"//runsc/config",
170171
"//runsc/container",

runsc/cmd/boot.go

Lines changed: 13 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"context"
1919
"fmt"
2020
"os"
21-
"os/exec"
2221
"path/filepath"
2322
"runtime"
2423
"runtime/debug"
@@ -44,6 +43,7 @@ import (
4443
"gvisor.dev/gvisor/pkg/sentry/syscalls/linux"
4544
"gvisor.dev/gvisor/pkg/tcpip/nftables"
4645
"gvisor.dev/gvisor/runsc/boot"
46+
"gvisor.dev/gvisor/runsc/cmd/sandboxsetup"
4747
"gvisor.dev/gvisor/runsc/cmd/util"
4848
"gvisor.dev/gvisor/runsc/config"
4949
"gvisor.dev/gvisor/runsc/flag"
@@ -96,14 +96,14 @@ type Boot struct {
9696
deviceFD int
9797

9898
// ioFDs is the list of FDs used to connect to FS gofers.
99-
ioFDs intFlags
99+
ioFDs sandboxsetup.IntFlags
100100

101101
// devIoFD is the FD to connect to dev gofer.
102102
devIoFD int
103103

104104
// goferFilestoreFDs are FDs to the regular files that will back the tmpfs or
105105
// overlayfs mount for certain gofer mounts.
106-
goferFilestoreFDs intFlags
106+
goferFilestoreFDs sandboxsetup.IntFlags
107107

108108
// goferMountConfs contains information about how the gofer mounts have been
109109
// configured. The first entry is for rootfs and the following entries are
@@ -112,7 +112,7 @@ type Boot struct {
112112

113113
// stdioFDs are the fds for stdin, stdout, and stderr. They must be
114114
// provided in that order.
115-
stdioFDs intFlags
115+
stdioFDs sandboxsetup.IntFlags
116116

117117
// passFDs are mappings of user-supplied host to guest file descriptors.
118118
passFDs fdMappings
@@ -152,11 +152,11 @@ type Boot struct {
152152

153153
podInitConfigFD int
154154

155-
sinkFDs intFlags
155+
sinkFDs sandboxsetup.IntFlags
156156

157-
saveFDs intFlags
157+
saveFDs sandboxsetup.IntFlags
158158

159-
fsRestoreFDs intFlags
159+
fsRestoreFDs sandboxsetup.IntFlags
160160

161161
// attached is set to true to kill the sandbox process when the parent process
162162
// terminates. This flag is set when the command execve's itself because
@@ -385,7 +385,7 @@ func (b *Boot) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcomma
385385
// /proc is umounted from a forked process, because the
386386
// current one is going to re-execute itself without
387387
// capabilities.
388-
cmd, w := execProcUmounter()
388+
cmd, w := sandboxsetup.ExecProcUmounter()
389389
defer cmd.Wait()
390390
defer w.Close()
391391
if b.procMountSyncFD != -1 {
@@ -402,13 +402,13 @@ func (b *Boot) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcomma
402402

403403
if !b.applyCaps {
404404
// Remove the args that have already been done before calling self.
405-
args := prepareArgs(b.Name(), f, argOverride)
405+
args := sandboxsetup.PrepareArgs(b.Name(), f, argOverride)
406406

407407
// Note that we've already read the spec from the spec FD, and
408408
// we will read it again after the exec call. This works
409409
// because the ReadSpecFromFile function seeks to the beginning
410410
// of the file before reading.
411-
util.Fatalf("callSelfAsNobody(%v): %v", args, callSelfAsNobody(args))
411+
util.Fatalf("callSelfAsNobody(%v): %v", args, sandboxsetup.CallSelfAsNobody(args))
412412

413413
// This prevents the specFile finalizer from running and closed
414414
// the specFD, which we have passed to ourselves when
@@ -467,13 +467,13 @@ func (b *Boot) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcomma
467467
argOverride["apply-caps"] = "false"
468468

469469
// Remove the args that have already been done before calling self.
470-
args := prepareArgs(b.Name(), f, argOverride)
470+
args := sandboxsetup.PrepareArgs(b.Name(), f, argOverride)
471471

472472
// Note that we've already read the spec from the spec FD, and
473473
// we will read it again after the exec call. This works
474474
// because the ReadSpecFromFile function seeks to the beginning
475475
// of the file before reading.
476-
util.Fatalf("setCapsAndCallSelf(%v, %v): %v", args, caps, setCapsAndCallSelf(args, caps))
476+
util.Fatalf("setCapsAndCallSelf(%v, %v): %v", args, caps, sandboxsetup.SetCapsAndCallSelf(args, caps))
477477

478478
// This prevents the specFile finalizer from running and closed
479479
// the specFD, which we have passed to ourselves when
@@ -609,7 +609,7 @@ func (b *Boot) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcomma
609609
// Call validateOpenFDs() before umounting /proc.
610610
validateOpenFDs(bootArgs.PassFDs)
611611
// Umount /proc right before installing seccomp filters.
612-
umountProc(b.procMountSyncFD)
612+
sandboxsetup.UmountProc(b.procMountSyncFD)
613613
}
614614
}
615615

@@ -671,84 +671,6 @@ func (b *Boot) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcomma
671671
return subcommands.ExitSuccess
672672
}
673673

674-
// prepareArgs returns the args that can be used to re-execute the current
675-
// program. It manipulates the flags of the subcommands.Command identified by
676-
// subCmdName and fSet is the flag.FlagSet of this subcommand. It applies the
677-
// flags specified by override map. In case of conflict, flag is overridden.
678-
//
679-
// Postcondition: prepareArgs() takes ownership of override map.
680-
func prepareArgs(subCmdName string, fSet *flag.FlagSet, override map[string]string) []string {
681-
var args []string
682-
// Add all args up until (and including) the sub command.
683-
for _, arg := range os.Args {
684-
args = append(args, arg)
685-
if arg == subCmdName {
686-
break
687-
}
688-
}
689-
// Set sub command flags. Iterate through all the explicitly set flags.
690-
fSet.Visit(func(gf *flag.Flag) {
691-
// If a conflict is found with override, then prefer override flag.
692-
if ov, ok := override[gf.Name]; ok {
693-
args = append(args, fmt.Sprintf("--%s=%s", gf.Name, ov))
694-
delete(override, gf.Name)
695-
return
696-
}
697-
// Otherwise pass through the original flag.
698-
args = append(args, fmt.Sprintf("--%s=%s", gf.Name, gf.Value))
699-
})
700-
// Apply remaining override flags (that didn't conflict above).
701-
for of, ov := range override {
702-
args = append(args, fmt.Sprintf("--%s=%s", of, ov))
703-
}
704-
// Add the non-flag arguments at the end.
705-
args = append(args, fSet.Args()...)
706-
return args
707-
}
708-
709-
// execProcUmounter execute a child process that umounts /proc when the
710-
// returned pipe is closed.
711-
func execProcUmounter() (*exec.Cmd, *os.File) {
712-
r, w, err := os.Pipe()
713-
if err != nil {
714-
util.Fatalf("error creating a pipe: %v", err)
715-
}
716-
defer r.Close()
717-
718-
cmd := exec.Command(specutils.ExePath)
719-
cmd.Args = append(cmd.Args, "umount", "--sync-fd=3", "/proc")
720-
cmd.ExtraFiles = append(cmd.ExtraFiles, r)
721-
cmd.Stdin = os.Stdin
722-
cmd.Stdout = os.Stdout
723-
cmd.Stderr = os.Stderr
724-
if err := cmd.Start(); err != nil {
725-
util.Fatalf("error executing umounter: %v", err)
726-
}
727-
return cmd, w
728-
}
729-
730-
// umountProc writes to syncFD signalling the process started by
731-
// execProcUmounter() to umount /proc.
732-
func umountProc(syncFD int) {
733-
syncFile := os.NewFile(uintptr(syncFD), "procfs umount sync FD")
734-
buf := make([]byte, 1)
735-
if w, err := syncFile.Write(buf); err != nil || w != 1 {
736-
util.Fatalf("unable to write into the proc umounter descriptor: %v", err)
737-
}
738-
syncFile.Close()
739-
740-
var waitStatus unix.WaitStatus
741-
if _, err := unix.Wait4(0, &waitStatus, 0, nil); err != nil {
742-
util.Fatalf("error waiting for the proc umounter process: %v", err)
743-
}
744-
if !waitStatus.Exited() || waitStatus.ExitStatus() != 0 {
745-
util.Fatalf("the proc umounter process failed: %v", waitStatus)
746-
}
747-
if err := unix.Access("/proc/self", unix.F_OK); err != unix.ENOENT {
748-
util.Fatalf("/proc is still accessible")
749-
}
750-
}
751-
752674
// validateOpenFDs checks that the sandbox process does not have any open
753675
// directory FDs.
754676
func validateOpenFDs(passFDs []boot.FDMapping) {

runsc/cmd/capability_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
specs "github.com/opencontainers/runtime-spec/specs-go"
2626
"gvisor.dev/gvisor/pkg/log"
2727
"gvisor.dev/gvisor/pkg/test/testutil"
28+
"gvisor.dev/gvisor/runsc/cmd/sandboxsetup"
2829
"gvisor.dev/gvisor/runsc/config"
2930
"gvisor.dev/gvisor/runsc/container"
3031
"gvisor.dev/gvisor/runsc/specutils"
@@ -47,7 +48,7 @@ func checkProcessCaps(pid int, wantCaps *specs.LinuxCapabilities) error {
4748
}
4849
fmt.Printf("Capabilities (PID: %d): %v\n", pid, curCaps)
4950

50-
for _, c := range allCapTypes {
51+
for _, c := range sandboxsetup.AllCapTypes {
5152
if err := checkCaps(c, curCaps, wantCaps); err != nil {
5253
return err
5354
}
@@ -56,8 +57,8 @@ func checkProcessCaps(pid int, wantCaps *specs.LinuxCapabilities) error {
5657
}
5758

5859
func checkCaps(which capability.CapType, curCaps capability.Capabilities, wantCaps *specs.LinuxCapabilities) error {
59-
wantNames := getCaps(which, wantCaps)
60-
for name, c := range capFromName {
60+
wantNames := sandboxsetup.GetCaps(which, wantCaps)
61+
for name, c := range sandboxsetup.CapFromName {
6162
want := slices.Contains(wantNames, name)
6263
got := curCaps.Get(which, c)
6364
if want != got {

runsc/cmd/chroot.go

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"golang.org/x/sys/unix"
2626
"gvisor.dev/gvisor/pkg/abi/tpu"
2727
"gvisor.dev/gvisor/pkg/log"
28+
"gvisor.dev/gvisor/runsc/cmd/sandboxsetup"
2829
"gvisor.dev/gvisor/runsc/cmd/util"
2930
"gvisor.dev/gvisor/runsc/config"
3031
"gvisor.dev/gvisor/runsc/specutils"
@@ -42,46 +43,6 @@ func mountInChroot(chroot, src, dst, typ string, flags uint32) error {
4243
return nil
4344
}
4445

45-
func pivotRoot(root string) error {
46-
if err := os.Chdir(root); err != nil {
47-
return fmt.Errorf("error changing working directory: %v", err)
48-
}
49-
// pivot_root(new_root, put_old) moves the root filesystem (old_root)
50-
// of the calling process to the directory put_old and makes new_root
51-
// the new root filesystem of the calling process.
52-
//
53-
// pivot_root(".", ".") makes a mount of the working directory the new
54-
// root filesystem, so it will be moved in "/" and then the old_root
55-
// will be moved to "/" too. The parent mount of the old_root will be
56-
// new_root, so after umounting the old_root, we will see only
57-
// the new_root in "/".
58-
if err := unix.PivotRoot(".", "."); err != nil {
59-
return fmt.Errorf("pivot_root failed, make sure that the root mount has a parent: %v", err)
60-
}
61-
62-
if err := unix.Unmount(".", unix.MNT_DETACH); err != nil {
63-
return fmt.Errorf("error umounting the old root file system: %v", err)
64-
}
65-
return nil
66-
}
67-
68-
func copyFile(dst, src string) error {
69-
in, err := os.Open(src)
70-
if err != nil {
71-
return err
72-
}
73-
defer in.Close()
74-
75-
out, err := os.Create(dst)
76-
if err != nil {
77-
return err
78-
}
79-
defer out.Close()
80-
81-
_, err = out.ReadFrom(in)
82-
return err
83-
}
84-
8546
// setupMinimalProcfs creates a minimal procfs-like tree at `${chroot}/proc`.
8647
func setupMinimalProcfs(chroot string) error {
8748
// We can't always directly mount procfs because it may be obstructed
@@ -135,7 +96,7 @@ func setupMinimalProcfs(chroot string) error {
13596
"/proc/sys/vm/mmap_min_addr",
13697
"/proc/sys/kernel/cap_last_cap",
13798
} {
138-
if err := copyFile(filepath.Join(chroot, f), f); err != nil {
99+
if err := sandboxsetup.CopyFile(filepath.Join(chroot, f), f); err != nil {
139100
return fmt.Errorf("failed to copy %q -> %q: %w", f, filepath.Join(chroot, f), err)
140101
}
141102
}
@@ -175,7 +136,7 @@ func setUpChroot(spec *specs.Spec, conf *config.Config) error {
175136
return fmt.Errorf("error creating /etc in chroot: %v", err)
176137
}
177138

178-
if err := copyFile(filepath.Join(chroot, "etc/localtime"), "/etc/localtime"); err != nil {
139+
if err := sandboxsetup.CopyFile(filepath.Join(chroot, "etc/localtime"), "/etc/localtime"); err != nil {
179140
log.Warningf("Failed to copy /etc/localtime: %v. UTC timezone will be used.", err)
180141
}
181142

@@ -191,7 +152,7 @@ func setUpChroot(spec *specs.Spec, conf *config.Config) error {
191152
return fmt.Errorf("error remounting chroot in read-only: %v", err)
192153
}
193154

194-
return pivotRoot(chroot)
155+
return sandboxsetup.PivotRoot(chroot)
195156
}
196157

197158
func tpuProxyUpdateChroot(hostRoot, chroot string, spec *specs.Spec, conf *config.Config) error {

0 commit comments

Comments
 (0)