diff --git a/runsc/cmd/boot.go b/runsc/cmd/boot.go index af25bccb1..140ee5b64 100644 --- a/runsc/cmd/boot.go +++ b/runsc/cmd/boot.go @@ -171,7 +171,7 @@ func (b *Boot) SetFlags(f *flag.FlagSet) { f.IntVar(&b.deviceFD, "device-fd", -1, "FD for the platform device file") f.Var(&b.ioFDs, "io-fds", "list of FDs to connect gofer clients. They must follow this order: root first, then mounts as defined in the spec") f.Var(&b.stdioFDs, "stdio-fds", "list of FDs containing sandbox stdin, stdout, and stderr in that order") - f.Var(&b.passFDs, "custom-fds", "mapping of host to guest FDs. They must be in M:N format. M is the host and N the guest descriptor.") + f.Var(&b.passFDs, "pass-fd", "mapping of host to guest FDs. They must be in M:N format. M is the host and N the guest descriptor.") f.Var(&b.overlayFilestoreFDs, "overlay-filestore-fds", "FDs to the regular files that will back the tmpfs upper mount in the overlay mounts.") f.IntVar(&b.userLogFD, "user-log-fd", 0, "file descriptor to write user logs to. 0 means no logging.") f.IntVar(&b.startSyncFD, "start-sync-fd", -1, "required FD to used to synchronize sandbox startup") diff --git a/runsc/cmd/exec.go b/runsc/cmd/exec.go index 6d32edf98..6da5e96a5 100644 --- a/runsc/cmd/exec.go +++ b/runsc/cmd/exec.go @@ -60,7 +60,7 @@ type Exec struct { // passFDs are user-supplied FDs from the host to be exposed to the // sandboxed app. - passFDs intFlags + passFDs fdMappings } // Name implements subcommands.Command.Name. @@ -104,7 +104,7 @@ func (ex *Exec) SetFlags(f *flag.FlagSet) { f.StringVar(&ex.pidFile, "pid-file", "", "filename that the container pid will be written to") f.StringVar(&ex.internalPidFile, "internal-pid-file", "", "filename that the container-internal pid will be written to") f.StringVar(&ex.consoleSocket, "console-socket", "", "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal") - f.Var(&ex.passFDs, "pass-fd", "file descriptors passed to the container. Can be supplied multiple times.") + f.Var(&ex.passFDs, "pass-fd", "file descriptor passed to the container in M:N format, where M is the host and N is the guest descriptor (can be supplied multiple times)") } // Execute implements subcommands.Command.Execute. It starts a process in an @@ -152,18 +152,17 @@ func (ex *Exec) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcomm } // Add custom file descriptors to the map. - var files []*os.File - for _, fd := range ex.passFDs { - file := os.NewFile(uintptr(fd), "") + for _, mapping := range ex.passFDs { + file := os.NewFile(uintptr(mapping.Host), "") if file == nil { - util.Fatalf("failed to create file from file descriptor %d", fd) + util.Fatalf("failed to create file from file descriptor %d", mapping.Host) } - fdMap[int(file.Fd())] = file + fdMap[mapping.Guest] = file } // Close the underlying file descriptors after we have passed them. defer func() { - for _, file := range files { + for _, file := range fdMap { fd := file.Fd() if file.Close() != nil { log.Debugf("Failed to close FD %d", fd) diff --git a/runsc/cmd/fd_mapping.go b/runsc/cmd/fd_mapping.go index 48a76f63e..fe704a256 100644 --- a/runsc/cmd/fd_mapping.go +++ b/runsc/cmd/fd_mapping.go @@ -45,7 +45,19 @@ func (i *fdMappings) GetArray() []boot.FDMapping { func (i *fdMappings) Set(s string) error { split := strings.Split(s, ":") if len(split) != 2 { - return fmt.Errorf("invalid flag value: must be of format M:N") + // Split returns a slice of length 1 if its first argument does not + // contain the separator. An additional length check is not necessary. + // In case no separator is used and the argument is a valid integer, we + // assume that host FD and guest FD should be identical. + fd, err := strconv.Atoi(split[0]) + if err != nil { + return fmt.Errorf("invalid flag value: must be an integer or a mapping of format M:N") + } + *i = append(*i, boot.FDMapping{ + Host: fd, + Guest: fd, + }) + return nil } fdHost, err := strconv.Atoi(split[0]) diff --git a/runsc/cmd/run.go b/runsc/cmd/run.go index 48eaf9f00..1e6dbe90c 100644 --- a/runsc/cmd/run.go +++ b/runsc/cmd/run.go @@ -38,7 +38,7 @@ type Run struct { // passFDs are user-supplied FDs from the host to be exposed to the // sandboxed app. - passFDs intFlags + passFDs fdMappings } // Name implements subcommands.Command.Name. @@ -60,7 +60,7 @@ func (*Run) Usage() string { // SetFlags implements subcommands.Command.SetFlags. func (r *Run) SetFlags(f *flag.FlagSet) { f.BoolVar(&r.detach, "detach", false, "detach from the container's process") - f.Var(&r.passFDs, "pass-fd", "file descriptors passed to the container. Can be supplied multiple times.") + f.Var(&r.passFDs, "pass-fd", "file descriptor passed to the container in M:N format, where M is the host and N is the guest descriptor (can be supplied multiple times)") r.Create.SetFlags(f) } @@ -98,12 +98,12 @@ func (r *Run) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcomman // Create files from file descriptors. fdMap := make(map[int]*os.File) - for _, fd := range r.passFDs { - file := os.NewFile(uintptr(fd), "") + for _, mapping := range r.passFDs { + file := os.NewFile(uintptr(mapping.Host), "") if file == nil { - return util.Errorf("Failed to create file from file descriptor %d", fd) + return util.Errorf("Failed to create file from file descriptor %d", mapping.Host) } - fdMap[fd] = file + fdMap[mapping.Guest] = file } // Close the underlying file descriptors after we have passed them. diff --git a/runsc/donation/donation.go b/runsc/donation/donation.go index cdf0340d5..f128eafed 100644 --- a/runsc/donation/donation.go +++ b/runsc/donation/donation.go @@ -110,7 +110,7 @@ func (f *Agency) Transfer(cmd *exec.Cmd, nextFD int) int { // host to the sandbox. Making use of the agency is not necessary, func DonateAndTransferCustomFiles(cmd *exec.Cmd, nextFD int, files map[int]*os.File) int { for fd, file := range files { - cmd.Args = append(cmd.Args, fmt.Sprintf("--custom-fds=%d:%d", nextFD, fd)) + cmd.Args = append(cmd.Args, fmt.Sprintf("--pass-fd=%d:%d", nextFD, fd)) cmd.ExtraFiles = append(cmd.ExtraFiles, file) nextFD++ }