Don't provide IO when it's not set

This makes sure that runc does not get any valid IO for the pipe.  Some
builds and other containers will be stuck if they inspect stdin
expecially and its a pipe but not connected to any user input.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby
2018-09-07 17:05:33 -04:00
parent b5274fe48a
commit 906acb18b6
10 changed files with 174 additions and 58 deletions

View File

@@ -34,6 +34,24 @@ type StartCloser interface {
CloseAfterStart() error
}
// IOOpt sets I/O creation options
type IOOpt func(*IOOption)
// IOOption holds I/O creation options
type IOOption struct {
OpenStdin bool
OpenStdout bool
OpenStderr bool
}
func defaultIOOption() *IOOption {
return &IOOption{
OpenStdin: true,
OpenStdout: true,
OpenStderr: true,
}
}
func newPipe() (*pipe, error) {
r, w, err := os.Pipe()
if err != nil {
@@ -65,14 +83,23 @@ type pipeIO struct {
}
func (i *pipeIO) Stdin() io.WriteCloser {
if i.in == nil {
return nil
}
return i.in.w
}
func (i *pipeIO) Stdout() io.ReadCloser {
if i.out == nil {
return nil
}
return i.out.r
}
func (i *pipeIO) Stderr() io.ReadCloser {
if i.err == nil {
return nil
}
return i.err.r
}
@@ -83,28 +110,38 @@ func (i *pipeIO) Close() error {
i.out,
i.err,
} {
if cerr := v.Close(); err == nil {
err = cerr
if v != nil {
if cerr := v.Close(); err == nil {
err = cerr
}
}
}
return err
}
func (i *pipeIO) CloseAfterStart() error {
for _, f := range []*os.File{
i.out.w,
i.err.w,
for _, f := range []*pipe{
i.out,
i.err,
} {
f.Close()
if f != nil {
f.w.Close()
}
}
return nil
}
// Set sets the io to the exec.Cmd
func (i *pipeIO) Set(cmd *exec.Cmd) {
cmd.Stdin = i.in.r
cmd.Stdout = i.out.w
cmd.Stderr = i.err.w
if i.in != nil {
cmd.Stdin = i.in.r
}
if i.out != nil {
cmd.Stdout = i.out.w
}
if i.err != nil {
cmd.Stderr = i.err.w
}
}
func NewSTDIO() (IO, error) {

View File

@@ -24,8 +24,15 @@ import (
)
// NewPipeIO creates pipe pairs to be used with runc
func NewPipeIO(uid, gid int) (i IO, err error) {
var pipes []*pipe
func NewPipeIO(uid, gid int, opts ...IOOpt) (i IO, err error) {
option := defaultIOOption()
for _, o := range opts {
o(option)
}
var (
pipes []*pipe
stdin, stdout, stderr *pipe
)
// cleanup in case of an error
defer func() {
if err != nil {
@@ -34,33 +41,33 @@ func NewPipeIO(uid, gid int) (i IO, err error) {
}
}
}()
stdin, err := newPipe()
if err != nil {
return nil, err
if option.OpenStdin {
if stdin, err = newPipe(); err != nil {
return nil, err
}
pipes = append(pipes, stdin)
if err = unix.Fchown(int(stdin.r.Fd()), uid, gid); err != nil {
return nil, errors.Wrap(err, "failed to chown stdin")
}
}
pipes = append(pipes, stdin)
if err = unix.Fchown(int(stdin.r.Fd()), uid, gid); err != nil {
return nil, errors.Wrap(err, "failed to chown stdin")
if option.OpenStdout {
if stdout, err = newPipe(); err != nil {
return nil, err
}
pipes = append(pipes, stdout)
if err = unix.Fchown(int(stdout.w.Fd()), uid, gid); err != nil {
return nil, errors.Wrap(err, "failed to chown stdout")
}
}
stdout, err := newPipe()
if err != nil {
return nil, err
if option.OpenStderr {
if stderr, err = newPipe(); err != nil {
return nil, err
}
pipes = append(pipes, stderr)
if err = unix.Fchown(int(stderr.w.Fd()), uid, gid); err != nil {
return nil, errors.Wrap(err, "failed to chown stderr")
}
}
pipes = append(pipes, stdout)
if err = unix.Fchown(int(stdout.w.Fd()), uid, gid); err != nil {
return nil, errors.Wrap(err, "failed to chown stdout")
}
stderr, err := newPipe()
if err != nil {
return nil, err
}
pipes = append(pipes, stderr)
if err = unix.Fchown(int(stderr.w.Fd()), uid, gid); err != nil {
return nil, errors.Wrap(err, "failed to chown stderr")
}
return &pipeIO{
in: stdin,
out: stdout,

View File

@@ -19,8 +19,15 @@
package runc
// NewPipeIO creates pipe pairs to be used with runc
func NewPipeIO() (i IO, err error) {
var pipes []*pipe
func NewPipeIO(opts ...IOOpt) (i IO, err error) {
option := defaultIOOption()
for _, o := range opts {
o(option)
}
var (
pipes []*pipe
stdin, stdout, stderr *pipe
)
// cleanup in case of an error
defer func() {
if err != nil {
@@ -29,24 +36,24 @@ func NewPipeIO() (i IO, err error) {
}
}
}()
stdin, err := newPipe()
if err != nil {
return nil, err
if option.OpenStdin {
if stdin, err = newPipe(); err != nil {
return nil, err
}
pipes = append(pipes, stdin)
}
pipes = append(pipes, stdin)
stdout, err := newPipe()
if err != nil {
return nil, err
if option.OpenStdout {
if stdout, err = newPipe(); err != nil {
return nil, err
}
pipes = append(pipes, stdout)
}
pipes = append(pipes, stdout)
stderr, err := newPipe()
if err != nil {
return nil, err
if option.OpenStderr {
if stderr, err = newPipe(); err != nil {
return nil, err
}
pipes = append(pipes, stderr)
}
pipes = append(pipes, stderr)
return &pipeIO{
in: stdin,
out: stdout,

View File

@@ -608,9 +608,8 @@ func parseVersion(data []byte) (Version, error) {
var v Version
parts := strings.Split(strings.TrimSpace(string(data)), "\n")
if len(parts) != 3 {
return v, ErrParseRuncVersion
return v, nil
}
for i, p := range []struct {
dest *string
split string