summaryrefslogtreecommitdiffhomepage
path: root/runsc/boot
diff options
context:
space:
mode:
authorFabricio Voznika <fvoznika@google.com>2018-09-27 15:00:03 -0700
committerShentubot <shentubot@google.com>2018-09-27 15:00:58 -0700
commit491faac03b2815ca1bc9b5425c1b3f6291468e20 (patch)
tree0a8f0c1ad99c3d8660f36802132ecd9386c54518 /runsc/boot
parent68ac2ad1e1f16e65d9d1318d6827edf8487578d0 (diff)
Implement 'runsc kill --all'
In order to implement kill --all correctly, the Sentry needs to track all tasks that belong to a given container. This change introduces ContainerID to the task, that gets inherited by all children. 'kill --all' then iterates over all tasks comparing the ContainerID field to find all processes that need to be signalled. PiperOrigin-RevId: 214841768 Change-Id: I693b2374be8692d88cc441ef13a0ae34abf73ac6
Diffstat (limited to 'runsc/boot')
-rw-r--r--runsc/boot/controller.go29
-rw-r--r--runsc/boot/loader.go26
2 files changed, 33 insertions, 22 deletions
diff --git a/runsc/boot/controller.go b/runsc/boot/controller.go
index bc33e028a..116a8369c 100644
--- a/runsc/boot/controller.go
+++ b/runsc/boot/controller.go
@@ -174,10 +174,17 @@ func (cm *containerManager) StartRoot(cid *string, _ *struct{}) error {
return nil
}
+// ProcessesArgs container arguments to Processes method.
+type ProcessesArgs struct {
+ // CID restricts the result to processes belonging to
+ // the given container. Empty means all.
+ CID string
+}
+
// Processes retrieves information about processes running in the sandbox.
-func (cm *containerManager) Processes(_, out *[]*control.Process) error {
+func (cm *containerManager) Processes(args *ProcessesArgs, out *[]*control.Process) error {
log.Debugf("containerManager.Processes")
- return control.Processes(cm.l.k, out)
+ return control.Processes(cm.l.k, args.CID, out)
}
// StartArgs contains arguments to the Start method.
@@ -326,19 +333,11 @@ func (cm *containerManager) Destroy(cid *string, _ *struct{}) error {
return nil
}
-// ExecArgs contains arguments to Execute.
-type ExecArgs struct {
- control.ExecArgs
-
- // CID is the ID of the container to exec in.
- CID string
-}
-
// ExecuteAsync starts running a command on a created or running sandbox. It
// returns the pid of the new process.
-func (cm *containerManager) ExecuteAsync(args *ExecArgs, pid *int32) error {
+func (cm *containerManager) ExecuteAsync(args *control.ExecArgs, pid *int32) error {
log.Debugf("containerManager.ExecuteAsync: %+v", args)
- tgid, err := cm.l.executeAsync(&args.ExecArgs, args.CID)
+ tgid, err := cm.l.executeAsync(args)
if err != nil {
return err
}
@@ -503,11 +502,15 @@ type SignalArgs struct {
// Signo is the signal to send to the process.
Signo int32
+
+ // All is set when signal should be sent to all processes in the container.
+ // When false, the signal is sent to the root container process only.
+ All bool
}
// Signal sends a signal to the init process of the container.
// TODO: Send signal to exec process.
func (cm *containerManager) Signal(args *SignalArgs, _ *struct{}) error {
log.Debugf("containerManager.Signal")
- return cm.l.signal(args.CID, args.Signo)
+ return cm.l.signal(args.CID, args.Signo, args.All)
}
diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go
index 9a5d649ab..bd6e146fc 100644
--- a/runsc/boot/loader.go
+++ b/runsc/boot/loader.go
@@ -270,7 +270,7 @@ func New(id string, spec *specs.Spec, conf *Config, controllerFD, deviceFD int,
log.Infof("Panic signal set to %v(%d)", ps, conf.PanicSignal)
}
- procArgs, err := newProcess(spec, creds, k)
+ procArgs, err := newProcess(id, spec, creds, k)
if err != nil {
return nil, fmt.Errorf("failed to create root process: %v", err)
}
@@ -295,7 +295,7 @@ func New(id string, spec *specs.Spec, conf *Config, controllerFD, deviceFD int,
}
// newProcess creates a process that can be run with kernel.CreateProcess.
-func newProcess(spec *specs.Spec, creds *auth.Credentials, k *kernel.Kernel) (kernel.CreateProcessArgs, error) {
+func newProcess(id string, spec *specs.Spec, creds *auth.Credentials, k *kernel.Kernel) (kernel.CreateProcessArgs, error) {
// Create initial limits.
ls, err := createLimitSet(spec)
if err != nil {
@@ -314,6 +314,7 @@ func newProcess(spec *specs.Spec, creds *auth.Credentials, k *kernel.Kernel) (ke
UTSNamespace: k.RootUTSNamespace(),
IPCNamespace: k.RootIPCNamespace(),
AbstractSocketNamespace: k.RootAbstractSocketNamespace(),
+ ContainerID: id,
}
return procArgs, nil
}
@@ -465,7 +466,7 @@ func (l *Loader) startContainer(k *kernel.Kernel, spec *specs.Spec, conf *Config
// TODO New containers should be started in new PID namespaces
// when indicated by the spec.
- procArgs, err := newProcess(spec, creds, l.k)
+ procArgs, err := newProcess(cid, spec, creds, l.k)
if err != nil {
return fmt.Errorf("failed to create new process: %v", err)
}
@@ -525,14 +526,14 @@ func (l *Loader) startContainer(k *kernel.Kernel, spec *specs.Spec, conf *Config
return nil
}
-func (l *Loader) executeAsync(args *control.ExecArgs, cid string) (kernel.ThreadID, error) {
+func (l *Loader) executeAsync(args *control.ExecArgs) (kernel.ThreadID, error) {
// Get the container Root Dirent from the Task, since we must run this
// process with the same Root.
l.mu.Lock()
- tg, ok := l.containerRootTGs[cid]
+ tg, ok := l.containerRootTGs[args.ContainerID]
l.mu.Unlock()
if !ok {
- return 0, fmt.Errorf("cannot exec in container %q: no such container", cid)
+ return 0, fmt.Errorf("cannot exec in container %q: no such container", args.ContainerID)
}
tg.Leader().WithMuLocked(func(t *kernel.Task) {
args.Root = t.FSContext().RootDirectory()
@@ -552,7 +553,7 @@ func (l *Loader) executeAsync(args *control.ExecArgs, cid string) (kernel.Thread
// later.
l.mu.Lock()
defer l.mu.Unlock()
- eid := execID{cid: cid, pid: tgid}
+ eid := execID{cid: args.ContainerID, pid: tgid}
l.execProcesses[eid] = tg
log.Debugf("updated execProcesses: %v", l.execProcesses)
@@ -671,8 +672,7 @@ func newEmptyNetworkStack(conf *Config, clock tcpip.Clock) (inet.Stack, error) {
}
}
-// TODO: Support sending signal to all.
-func (l *Loader) signal(cid string, signo int32) error {
+func (l *Loader) signal(cid string, signo int32, all bool) error {
l.mu.Lock()
tg, ok := l.containerRootTGs[cid]
l.mu.Unlock()
@@ -681,5 +681,13 @@ func (l *Loader) signal(cid string, signo int32) error {
}
si := arch.SignalInfo{Signo: signo}
+ if all {
+ // Pause the kernel to prevent new processes from being created while
+ // the signal is delivered. This prevents process leaks when SIGKILL is
+ // sent to the entire container.
+ l.k.Pause()
+ defer l.k.Unpause()
+ return l.k.SendContainerSignal(cid, &si)
+ }
return tg.Leader().SendSignal(&si)
}