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

Code before:
			}
		}
	}
	return nil
}

// Signal sends a specified signal to container's init.
//
// When s is SIGKILL and the container does not have its own PID namespace, all
// the container's processes are killed. In this scenario, the libcontainer
// user may be required to implement a proper child reaper.
func (c *Container) Signal(s os.Signal) error {
	c.m.Lock()
	defer c.m.Unlock()

	// When a container has its own PID namespace, inside it the init PID
	// is 1, and thus it is handled specially by the kernel. In particular,
	// killing init with SIGKILL from an ancestor namespace will also kill
	// all other processes in that PID namespace (see pid_namespaces(7)).
	//
	// OTOH, if PID namespace is shared, we should kill all pids to avoid
	// leftover processes. Handle this special case here.
	if s == unix.SIGKILL && !c.config.Namespaces.IsPrivate(configs.NEWPID) {
		if err := signalAllProcesses(c.cgroupManager, unix.SIGKILL); err != nil {
			return fmt.Errorf("unable to kill all processes: %w", err)
		}
		return nil
	}

	// To avoid a PID reuse attack, don't kill non-running container.
	if !c.hasInit() {
		return ErrNotRunning
	}
	if err := c.initProcess.signal(s); err != nil {
		return fmt.Errorf("unable to signal init: %w", err)
	}
	if s == unix.SIGKILL {
		// For cgroup v1, killing a process in a frozen cgroup
		// does nothing until it's thawed. Only thaw the cgroup
		// for SIGKILL.
		if paused, _ := c.isPaused(); paused {
			_ = c.cgroupManager.Freeze(configs.Thawed)
		}
	}
	return nil
}

func (c *Container) createExecFifo() (retErr error) {
	rootuid, err := c.Config().HostRootUID()
	if err != nil {
		return err

Review comment (bug):
Shuold we remove `.WithError(err)` here? Because for kill a such type running container, it will log with an error: `failed to kill all processes, possibly due to lack of cgroup (Hint: enable cgroup v2 delegation)    error=container not running". It will make the user confused.

(I'm sorry to say it after merged, because I'm in a busy state these days.)

Code after:
			}
		}
	}
	return nil
}

// Signal sends a specified signal to container's init.
//
// When s is SIGKILL and the container does not have its own PID namespace, all
// the container's processes are killed. In this scenario, the libcontainer
// user may be required to implement a proper child reaper.
func (c *Container) Signal(s os.Signal) error {
	c.m.Lock()
	defer c.m.Unlock()

	// When a container has its own PID namespace, inside it the init PID
	// is 1, and thus it is handled specially by the kernel. In particular,
	// killing init with SIGKILL from an ancestor namespace will also kill
	// all other processes in that PID namespace (see pid_namespaces(7)).
	//
	// OTOH, if PID namespace is shared, we should kill all pids to avoid
	// leftover processes. Handle this special case here.
	if s == unix.SIGKILL && !c.config.Namespaces.IsPrivate(configs.NEWPID) {
		if err := signalAllProcesses(c.cgroupManager, unix.SIGKILL); err != nil {
			if c.config.RootlessCgroups { // may not have an access to cgroup
				logrus.WithError(err).Warn("failed to kill all processes, possibly due to lack of cgroup (Hint: enable cgroup v2 delegation)")
				// Some processes may leak when cgroup is not delegated
				// https://github.com/opencontainers/runc/pull/4395#pullrequestreview-2291179652
				return c.signal(s)
			}
			return fmt.Errorf("unable to kill all processes: %w", err)
		}
		return nil
	}

	return c.signal(s)
}

func (c *Container) signal(s os.Signal) error {
	// To avoid a PID reuse attack, don't kill non-running container.
	if !c.hasInit() {
		return ErrNotRunning
	}
	if err := c.initProcess.signal(s); err != nil {
		return fmt.Errorf("unable to signal init: %w", err)
	}
	if s == unix.SIGKILL {
		// For cgroup v1, killing a process in a frozen cgroup
		// does nothing until it's thawed. Only thaw the cgroup
		// for SIGKILL.
		if paused, _ := c.isPaused(); paused {