diff options
Diffstat (limited to 'runsc/cmd')
-rw-r--r-- | runsc/cmd/gofer.go | 120 |
1 files changed, 96 insertions, 24 deletions
diff --git a/runsc/cmd/gofer.go b/runsc/cmd/gofer.go index 2193e9040..c65e0267a 100644 --- a/runsc/cmd/gofer.go +++ b/runsc/cmd/gofer.go @@ -71,8 +71,8 @@ func (*Gofer) Name() string { } // Synopsis implements subcommands.Command. -func (*Gofer) Synopsis() string { - return "launch a gofer process that serves files over 9P protocol (internal use only)" +func (g *Gofer) Synopsis() string { + return fmt.Sprintf("launch a gofer process that serves files over the protocol (9P or lisafs) defined in the config (internal use only)") } // Usage implements subcommands.Command. @@ -83,7 +83,7 @@ func (*Gofer) Usage() string { // SetFlags implements subcommands.Command. func (g *Gofer) SetFlags(f *flag.FlagSet) { f.StringVar(&g.bundleDir, "bundle", "", "path to the root of the bundle directory, defaults to the current directory") - f.Var(&g.ioFDs, "io-fds", "list of FDs to connect 9P servers. They must follow this order: root first, then mounts as defined in the spec") + f.Var(&g.ioFDs, "io-fds", "list of FDs to connect gofer servers. They must follow this order: root first, then mounts as defined in the spec") f.BoolVar(&g.applyCaps, "apply-caps", true, "if true, apply capabilities to restrict what the Gofer process can do") f.BoolVar(&g.setUpRoot, "setup-root", true, "if true, set up an empty root for the process") f.IntVar(&g.specFD, "spec-fd", -1, "required fd with the container spec") @@ -160,10 +160,98 @@ func (g *Gofer) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) } log.Infof("Process chroot'd to %q", root) + // Initialize filters. + if conf.FSGoferHostUDS { + filter.InstallUDSFilters() + } + + if conf.Verity { + filter.InstallXattrFilters() + } + + if err := filter.Install(); err != nil { + Fatalf("installing seccomp filters: %v", err) + } + + if conf.Lisafs { + return g.serveLisafs(spec, conf, root) + } + return g.serve9P(spec, conf, root) +} + +func newSocket(ioFD int) *unet.Socket { + socket, err := unet.NewSocket(ioFD) + if err != nil { + Fatalf("creating server on FD %d: %v", ioFD, err) + } + return socket +} + +func (g *Gofer) serveLisafs(spec *specs.Spec, conf *config.Config, root string) subcommands.ExitStatus { + type connectionConfig struct { + sock *unet.Socket + readonly bool + } + cfgs := make([]connectionConfig, 0, len(spec.Mounts)+1) + server := fsgofer.NewLisafsServer(fsgofer.Config{ + // These are global options. Ignore readonly configuration, that is set on + // a per connection basis. + HostUDS: conf.FSGoferHostUDS, + EnableVerityXattr: conf.Verity, + }) + + // Start with root mount, then add any other additional mount as needed. + cfgs = append(cfgs, connectionConfig{ + sock: newSocket(g.ioFDs[0]), + readonly: spec.Root.Readonly || conf.Overlay, + }) + log.Infof("Serving %q mapped to %q on FD %d (ro: %t)", "/", root, g.ioFDs[0], cfgs[0].readonly) + + mountIdx := 1 // first one is the root + for _, m := range spec.Mounts { + if !specutils.IsGoferMount(m, conf.VFS2) { + continue + } + + if !filepath.IsAbs(m.Destination) { + Fatalf("mount destination must be absolute: %q", m.Destination) + } + if mountIdx >= len(g.ioFDs) { + Fatalf("no FD found for mount. Did you forget --io-fd? FDs: %d, Mount: %+v", len(g.ioFDs), m) + } + + cfgs = append(cfgs, connectionConfig{ + sock: newSocket(g.ioFDs[mountIdx]), + readonly: isReadonlyMount(m.Options) || conf.Overlay, + }) + + log.Infof("Serving %q mapped on FD %d (ro: %t)", m.Destination, g.ioFDs[mountIdx], cfgs[mountIdx].readonly) + mountIdx++ + } + + if mountIdx != len(g.ioFDs) { + Fatalf("too many FDs passed for mounts. mounts: %d, FDs: %d", mountIdx, len(g.ioFDs)) + } + cfgs = cfgs[:mountIdx] + + for _, cfg := range cfgs { + conn, err := server.CreateConnection(cfg.sock, cfg.readonly) + if err != nil { + Fatalf("starting connection on FD %d for gofer mount failed: %v", cfg.sock.FD(), err) + } + server.StartConnection(conn) + } + server.Wait() + log.Infof("All lisafs servers exited.") + return subcommands.ExitSuccess +} + +func (g *Gofer) serve9P(spec *specs.Spec, conf *config.Config, root string) subcommands.ExitStatus { // Start with root mount, then add any other additional mount as needed. ats := make([]p9.Attacher, 0, len(spec.Mounts)+1) ap, err := fsgofer.NewAttachPoint("/", fsgofer.Config{ ROMount: spec.Root.Readonly || conf.Overlay, + HostUDS: conf.FSGoferHostUDS, EnableVerityXattr: conf.Verity, }) if err != nil { @@ -174,7 +262,7 @@ func (g *Gofer) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) mountIdx := 1 // first one is the root for _, m := range spec.Mounts { - if specutils.Is9PMount(m, conf.VFS2) { + if specutils.IsGoferMount(m, conf.VFS2) { cfg := fsgofer.Config{ ROMount: isReadonlyMount(m.Options) || conf.Overlay, HostUDS: conf.FSGoferHostUDS, @@ -197,26 +285,9 @@ func (g *Gofer) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) Fatalf("too many FDs passed for mounts. mounts: %d, FDs: %d", mountIdx, len(g.ioFDs)) } - if conf.FSGoferHostUDS { - filter.InstallUDSFilters() - } - - if conf.Verity { - filter.InstallXattrFilters() - } - - if err := filter.Install(); err != nil { - Fatalf("installing seccomp filters: %v", err) - } - - runServers(ats, g.ioFDs) - return subcommands.ExitSuccess -} - -func runServers(ats []p9.Attacher, ioFDs []int) { // Run the loops and wait for all to exit. var wg sync.WaitGroup - for i, ioFD := range ioFDs { + for i, ioFD := range g.ioFDs { wg.Add(1) go func(ioFD int, at p9.Attacher) { socket, err := unet.NewSocket(ioFD) @@ -232,6 +303,7 @@ func runServers(ats []p9.Attacher, ioFDs []int) { } wg.Wait() log.Infof("All 9P servers exited.") + return subcommands.ExitSuccess } func (g *Gofer) writeMounts(mounts []specs.Mount) error { @@ -362,7 +434,7 @@ func setupRootFS(spec *specs.Spec, conf *config.Config) error { // creates directories as needed. func setupMounts(conf *config.Config, mounts []specs.Mount, root, procPath string) error { for _, m := range mounts { - if !specutils.Is9PMount(m, conf.VFS2) { + if !specutils.IsGoferMount(m, conf.VFS2) { continue } @@ -402,7 +474,7 @@ func setupMounts(conf *config.Config, mounts []specs.Mount, root, procPath strin func resolveMounts(conf *config.Config, mounts []specs.Mount, root string) ([]specs.Mount, error) { cleanMounts := make([]specs.Mount, 0, len(mounts)) for _, m := range mounts { - if !specutils.Is9PMount(m, conf.VFS2) { + if !specutils.IsGoferMount(m, conf.VFS2) { cleanMounts = append(cleanMounts, m) continue } |