mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
libct: initProcess.start: fix sync logic
The code in this function became quite complicated and not entirely correct over time. As a result, if an error is returned from parseSync, it might end up stuck waiting for the child to finish. 1. Let's not wait() for the child twice. We already do it in the defer statement (call p.terminate()) when we are returning an error. 2. Remove sentResume and sentRun since we do not want to check if these were sent or not. Instead, introduce and check seenProcReady, as procReady is always expected from runc init. 3. Eliminate the possibility to wrap nil as an error. 4. Make sure we always call shutdown on the sync socket, and do not let shutdown error shadow the ierr. This fixes the issue of stuck `runc runc` with the optimization patch (sending procSeccompDone earlier) applied. Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
@@ -451,11 +451,8 @@ func (p *initProcess) start() (retErr error) {
|
|||||||
if err := p.sendConfig(); err != nil {
|
if err := p.sendConfig(); err != nil {
|
||||||
return fmt.Errorf("error sending config to init process: %w", err)
|
return fmt.Errorf("error sending config to init process: %w", err)
|
||||||
}
|
}
|
||||||
var (
|
|
||||||
sentRun bool
|
|
||||||
sentResume bool
|
|
||||||
)
|
|
||||||
|
|
||||||
|
var seenProcReady bool
|
||||||
ierr := parseSync(p.messageSockPair.parent, func(sync *syncT) error {
|
ierr := parseSync(p.messageSockPair.parent, func(sync *syncT) error {
|
||||||
switch sync.Type {
|
switch sync.Type {
|
||||||
case procSeccomp:
|
case procSeccomp:
|
||||||
@@ -494,6 +491,7 @@ func (p *initProcess) start() (retErr error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case procReady:
|
case procReady:
|
||||||
|
seenProcReady = true
|
||||||
// set rlimits, this has to be done here because we lose permissions
|
// set rlimits, this has to be done here because we lose permissions
|
||||||
// to raise the limits once we enter a user-namespace
|
// to raise the limits once we enter a user-namespace
|
||||||
if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil {
|
if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil {
|
||||||
@@ -555,7 +553,6 @@ func (p *initProcess) start() (retErr error) {
|
|||||||
if err := writeSync(p.messageSockPair.parent, procRun); err != nil {
|
if err := writeSync(p.messageSockPair.parent, procRun); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
sentRun = true
|
|
||||||
case procHooks:
|
case procHooks:
|
||||||
// Setup cgroup before prestart hook, so that the prestart hook could apply cgroup permissions.
|
// Setup cgroup before prestart hook, so that the prestart hook could apply cgroup permissions.
|
||||||
if err := p.manager.Set(p.config.Config.Cgroups.Resources); err != nil {
|
if err := p.manager.Set(p.config.Config.Cgroups.Resources); err != nil {
|
||||||
@@ -587,7 +584,6 @@ func (p *initProcess) start() (retErr error) {
|
|||||||
if err := writeSync(p.messageSockPair.parent, procResume); err != nil {
|
if err := writeSync(p.messageSockPair.parent, procResume); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
sentResume = true
|
|
||||||
default:
|
default:
|
||||||
return errors.New("invalid JSON payload from child")
|
return errors.New("invalid JSON payload from child")
|
||||||
}
|
}
|
||||||
@@ -595,20 +591,14 @@ func (p *initProcess) start() (retErr error) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if !sentRun {
|
if err := unix.Shutdown(int(p.messageSockPair.parent.Fd()), unix.SHUT_WR); err != nil && ierr == nil {
|
||||||
return fmt.Errorf("error during container init: %w", ierr)
|
|
||||||
}
|
|
||||||
if p.config.Config.Namespaces.Contains(configs.NEWNS) && !sentResume {
|
|
||||||
return errors.New("could not synchronise after executing prestart and CreateRuntime hooks with container process")
|
|
||||||
}
|
|
||||||
if err := unix.Shutdown(int(p.messageSockPair.parent.Fd()), unix.SHUT_WR); err != nil {
|
|
||||||
return &os.PathError{Op: "shutdown", Path: "(init pipe)", Err: err}
|
return &os.PathError{Op: "shutdown", Path: "(init pipe)", Err: err}
|
||||||
}
|
}
|
||||||
|
if !seenProcReady && ierr == nil {
|
||||||
// Must be done after Shutdown so the child will exit and we can wait for it.
|
ierr = errors.New("procReady not received")
|
||||||
|
}
|
||||||
if ierr != nil {
|
if ierr != nil {
|
||||||
_, _ = p.wait()
|
return fmt.Errorf("error during container init: %w", ierr)
|
||||||
return ierr
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user