@@ -21,6 +21,7 @@ import (
2121	"golang.org/x/sys/unix" 
2222
2323	"github.com/opencontainers/cgroups" 
24+ 	"github.com/opencontainers/runc/internal/linux" 
2425	"github.com/opencontainers/runc/libcontainer/configs" 
2526	"github.com/opencontainers/runc/libcontainer/exeseal" 
2627	"github.com/opencontainers/runc/libcontainer/intelrdt" 
@@ -377,9 +378,13 @@ func (c *Container) start(process *Process) (retErr error) {
377378
378379// Signal sends a specified signal to container's init. 
379380// 
380- // When s is SIGKILL and the container does not have its own PID namespace, all 
381- // the container's processes are killed. In this scenario, the libcontainer 
381+ // When s is SIGKILL: 
382+ // 1. If the container does not have its own PID namespace, all the 
383+ // container's processes are killed. In this scenario, the libcontainer 
382384// user may be required to implement a proper child reaper. 
385+ // 2. Otherwise, we just send the SIGKILL signal to the init process, 
386+ // but we don't wait for the init process to disappear. If you want to 
387+ // wait, please use c.EnsureKilled instead. 
383388func  (c  * Container ) Signal (s  os.Signal ) error  {
384389	c .m .Lock ()
385390	defer  c .m .Unlock ()
@@ -431,6 +436,74 @@ func (c *Container) signal(s os.Signal) error {
431436	return  nil 
432437}
433438
439+ func  (c  * Container ) killViaPidfd () error  {
440+ 	pidfd , err  :=  unix .PidfdOpen (c .initProcess .pid (), 0 )
441+ 	if  err  !=  nil  {
442+ 		return  err 
443+ 	}
444+ 	defer  unix .Close (pidfd )
445+ 
446+ 	epollfd , err  :=  unix .EpollCreate1 (unix .EPOLL_CLOEXEC )
447+ 	if  err  !=  nil  {
448+ 		return  err 
449+ 	}
450+ 	defer  unix .Close (epollfd )
451+ 
452+ 	event  :=  unix.EpollEvent {
453+ 		Events : unix .EPOLLIN ,
454+ 		Fd :     int32 (pidfd ),
455+ 	}
456+ 	if  err  :=  unix .EpollCtl (epollfd , unix .EPOLL_CTL_ADD , pidfd , & event ); err  !=  nil  {
457+ 		return  err 
458+ 	}
459+ 
460+ 	if  err  :=  unix .PidfdSendSignal (pidfd , unix .SIGKILL , nil , 0 ); err  !=  nil  {
461+ 		return  err 
462+ 	}
463+ 
464+ 	events  :=  make ([]unix.EpollEvent , 1 )
465+ 	// Set the timeout to 10s, the same as in kill below. 
466+ 	n , err  :=  linux .EpollWait (epollfd , events , 10000 )
467+ 	if  err  !=  nil  {
468+ 		return  err 
469+ 	}
470+ 	if  n  >  0  {
471+ 		for  i  :=  range  n  {
472+ 			event  :=  events [i ]
473+ 			if  event .Fd  ==  int32 (pidfd ) {
474+ 				return  nil 
475+ 			}
476+ 		}
477+ 	}
478+ 	return  errors .New ("container init still running" )
479+ }
480+ 
481+ func  (c  * Container ) kill () error  {
482+ 	_  =  c .Signal (unix .SIGKILL )
483+ 	for  i  :=  0 ; i  <  100 ; i ++  {
484+ 		time .Sleep (100  *  time .Millisecond )
485+ 		if  err  :=  c .Signal (unix .Signal (0 )); err  !=  nil  {
486+ 			return  nil 
487+ 		}
488+ 	}
489+ 	return  errors .New ("container init still running" )
490+ }
491+ 
492+ // EnsureKilled kills the container and waits for the kernel to finish killing it. 
493+ func  (c  * Container ) EnsureKilled () error  {
494+ 	// When a container doesn't have a private pidns, we have to kill all processes 
495+ 	// in the cgroup, it's more simpler to use `cgroup.kill` or `unix.Kill`. 
496+ 	if  c .config .Namespaces .IsPrivate (configs .NEWPID ) {
497+ 		err  :=  c .killViaPidfd ()
498+ 		if  err  ==  nil  {
499+ 			return  nil 
500+ 		}
501+ 
502+ 		logrus .Debugf ("pidfd & epoll failed, falling back to unix.Signal: %v" , err )
503+ 	}
504+ 	return  c .kill ()
505+ }
506+ 
434507func  (c  * Container ) createExecFifo () (retErr  error ) {
435508	rootuid , err  :=  c .config .HostRootUID ()
436509	if  err  !=  nil  {
0 commit comments