Repository: opencontainers/runc
File: libcontainer/container_linux.go (Go)

Code before:

	// Idmap mount sources to open.
	if it == initStandard && c.shouldSendIdmapSources() {
		var mounts []byte
		for _, m := range c.config.Mounts {
			if m.IsBind() && m.IsIDMapped() {
				// While other parts of the code check this too (like
				// libcontainer/specconv/spec_linux.go) we do it here also because some libcontainer
				// users don't use those functions.
				if strings.IndexByte(m.Source, 0) >= 0 {
					return nil, fmt.Errorf("mount source string contains null byte: %q", m.Source)
				}

				mounts = append(mounts, []byte(m.Source)...)
			}
			mounts = append(mounts, byte(0))
		}

		r.AddData(&Bytemsg{
			Type:  IdmapSourcesAttr,
			Value: mounts,
		})
	}

	return bytes.NewReader(r.Serialize()), nil
}

// ignoreTerminateErrors returns nil if the given err matches an error known
// to indicate that the terminate occurred successfully or err was nil, otherwise
// err is returned unaltered.
func ignoreTerminateErrors(err error) error {
	if err == nil {
		return nil
	}
	// terminate() might return an error from either Kill or Wait.
	// The (*Cmd).Wait documentation says: "If the command fails to run
	// or doesn't complete successfully, the error is of type *ExitError".
	// Filter out such errors (like "exit status 1" or "signal: killed").
	var exitErr *exec.ExitError
	if errors.As(err, &exitErr) {
		return nil
	}
	if errors.Is(err, os.ErrProcessDone) {
		return nil
	}
	s := err.Error()
	if strings.Contains(s, "Wait was already called") {
		return nil
	}
	return err
}

Review comment (suggestion):
I suspect we want this check to be done in the validator (at is stands, the code will silently ignore `timensOffsets` being configured without `CLONE_NEWTIME` enabled). But I can do this in a separate PR when I add the necessary integration tests for this feature.

Code after:

	// Idmap mount sources to open.
	if it == initStandard && c.shouldSendIdmapSources() {
		var mounts []byte
		for _, m := range c.config.Mounts {
			if m.IsBind() && m.IsIDMapped() {
				// While other parts of the code check this too (like
				// libcontainer/specconv/spec_linux.go) we do it here also because some libcontainer
				// users don't use those functions.
				if strings.IndexByte(m.Source, 0) >= 0 {
					return nil, fmt.Errorf("mount source string contains null byte: %q", m.Source)
				}

				mounts = append(mounts, []byte(m.Source)...)
			}
			mounts = append(mounts, byte(0))
		}

		r.AddData(&Bytemsg{
			Type:  IdmapSourcesAttr,
			Value: mounts,
		})
	}

	// write boottime and monotonic time ns offsets.
	if c.config.Namespaces.Contains(configs.NEWTIME) && c.config.TimeOffsets != nil {
		var offsetSpec bytes.Buffer
		for clock, offset := range c.config.TimeOffsets {
			fmt.Fprintf(&offsetSpec, "%s %d %d\n", clock, offset.Secs, offset.Nanosecs)
		}
		r.AddData(&Bytemsg{
			Type:  TimeOffsetsAttr,
			Value: offsetSpec.Bytes(),
		})
	}

	return bytes.NewReader(r.Serialize()), nil
}

// ignoreTerminateErrors returns nil if the given err matches an error known
// to indicate that the terminate occurred successfully or err was nil, otherwise
// err is returned unaltered.
func ignoreTerminateErrors(err error) error {
	if err == nil {
		return nil
	}
	// terminate() might return an error from either Kill or Wait.
	// The (*Cmd).Wait documentation says: "If the command fails to run
	// or doesn't complete successfully, the error is of type *ExitError".
	// Filter out such errors (like "exit status 1" or "signal: killed").
	var exitErr *exec.ExitError