Add an option to prevent putting the shim in a new mount namespace
This is needed for users on kernel older than 3.18 so they can avoid EBUSY errors when trying to unlink, rename or remove a mountpoint that is present in a shim namespace. Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
This commit is contained in:
parent
6b9aafdab1
commit
26d4c2c217
@ -1216,9 +1216,9 @@ func TestContainerExitedAtSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
status := <-statusC
|
status := <-statusC
|
||||||
code, _, _ := status.Result()
|
code, _, err := status.Result()
|
||||||
if code != 0 {
|
if code != 0 {
|
||||||
t.Errorf("expected status 0 but received %d", code)
|
t.Errorf("expected status 0 but received %d (err: %v)", code, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s, err := task.Status(ctx); err != nil {
|
if s, err := task.Status(ctx); err != nil {
|
||||||
|
@ -212,4 +212,7 @@ The linux runtime allows a few options to be set to configure the shim and the r
|
|||||||
no_shim = false
|
no_shim = false
|
||||||
# display shim logs in the containerd daemon's log output
|
# display shim logs in the containerd daemon's log output
|
||||||
shim_debug = true
|
shim_debug = true
|
||||||
|
# do not put the shim in its own mount namespace
|
||||||
|
# (this only need to be set on kernel < 3.18)
|
||||||
|
shim_no_newns = true
|
||||||
```
|
```
|
||||||
|
@ -73,10 +73,10 @@ type bundle struct {
|
|||||||
type shimOpt func(*bundle, string, *runcopts.RuncOptions) (client.Config, client.ClientOpt)
|
type shimOpt func(*bundle, string, *runcopts.RuncOptions) (client.Config, client.ClientOpt)
|
||||||
|
|
||||||
// ShimRemote is a shimOpt for connecting and starting a remote shim
|
// ShimRemote is a shimOpt for connecting and starting a remote shim
|
||||||
func ShimRemote(shim, daemonAddress, cgroup string, debug bool, exitHandler func()) shimOpt {
|
func ShimRemote(shim, daemonAddress, cgroup string, nonewns, debug bool, exitHandler func()) shimOpt {
|
||||||
return func(b *bundle, ns string, ropts *runcopts.RuncOptions) (client.Config, client.ClientOpt) {
|
return func(b *bundle, ns string, ropts *runcopts.RuncOptions) (client.Config, client.ClientOpt) {
|
||||||
return b.shimConfig(ns, ropts),
|
return b.shimConfig(ns, ropts),
|
||||||
client.WithStart(shim, b.shimAddress(ns), daemonAddress, cgroup, debug, exitHandler)
|
client.WithStart(shim, b.shimAddress(ns), daemonAddress, cgroup, nonewns, debug, exitHandler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,17 @@ type Config struct {
|
|||||||
NoShim bool `toml:"no_shim"`
|
NoShim bool `toml:"no_shim"`
|
||||||
// Debug enable debug on the shim
|
// Debug enable debug on the shim
|
||||||
ShimDebug bool `toml:"shim_debug"`
|
ShimDebug bool `toml:"shim_debug"`
|
||||||
|
// ShimNoMountNS prevents the runtime from putting shims into their own mount namespace.
|
||||||
|
//
|
||||||
|
// Putting the shim in its own mount namespace ensure that any mounts made
|
||||||
|
// by it in order to get the task rootfs ready will be undone regardless
|
||||||
|
// on how the shim dies.
|
||||||
|
//
|
||||||
|
// NOTE: This should only be used in kernel older than 3.18 to avoid shims
|
||||||
|
// from causing a DoS in their parent namespace due to having a copy of
|
||||||
|
// mounts previously there which would prevent unlink, rename and remove
|
||||||
|
// operations on those mountpoints.
|
||||||
|
ShimNoMountNS bool `toml:"shim_no_newns"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a configured runtime
|
// New returns a configured runtime
|
||||||
@ -180,7 +191,8 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
|
|||||||
}
|
}
|
||||||
cgroup = v.(*runcopts.CreateOptions).ShimCgroup
|
cgroup = v.(*runcopts.CreateOptions).ShimCgroup
|
||||||
}
|
}
|
||||||
shimopt = ShimRemote(r.config.Shim, r.address, cgroup, r.config.ShimDebug, func() {
|
exitHandler := func() {
|
||||||
|
log.G(ctx).WithField("id", id).Info("shim reaped")
|
||||||
t, err := r.tasks.Get(ctx, id)
|
t, err := r.tasks.Get(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Task was never started or was already sucessfully deleted
|
// Task was never started or was already sucessfully deleted
|
||||||
@ -209,7 +221,9 @@ func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts
|
|||||||
"namespace": namespace,
|
"namespace": namespace,
|
||||||
}).Warn("failed to clen up after killed shim")
|
}).Warn("failed to clen up after killed shim")
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
shimopt = ShimRemote(r.config.Shim, r.address, cgroup,
|
||||||
|
r.config.ShimNoMountNS, r.config.ShimDebug, exitHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := bundle.NewShimClient(ctx, namespace, shimopt, ropts)
|
s, err := bundle.NewShimClient(ctx, namespace, shimopt, ropts)
|
||||||
|
@ -31,7 +31,7 @@ import (
|
|||||||
type ClientOpt func(context.Context, Config) (shim.ShimClient, io.Closer, error)
|
type ClientOpt func(context.Context, Config) (shim.ShimClient, io.Closer, error)
|
||||||
|
|
||||||
// WithStart executes a new shim process
|
// WithStart executes a new shim process
|
||||||
func WithStart(binary, address, daemonAddress, cgroup string, debug bool, exitHandler func()) ClientOpt {
|
func WithStart(binary, address, daemonAddress, cgroup string, nonewns, debug bool, exitHandler func()) ClientOpt {
|
||||||
return func(ctx context.Context, config Config) (_ shim.ShimClient, _ io.Closer, err error) {
|
return func(ctx context.Context, config Config) (_ shim.ShimClient, _ io.Closer, err error) {
|
||||||
socket, err := newSocket(address)
|
socket, err := newSocket(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -44,7 +44,7 @@ func WithStart(binary, address, daemonAddress, cgroup string, debug bool, exitHa
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
cmd := newCommand(binary, daemonAddress, debug, config, f)
|
cmd := newCommand(binary, daemonAddress, nonewns, debug, config, f)
|
||||||
ec, err := reaper.Default.Start(cmd)
|
ec, err := reaper.Default.Start(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.Wrapf(err, "failed to start shim")
|
return nil, nil, errors.Wrapf(err, "failed to start shim")
|
||||||
@ -84,7 +84,7 @@ func WithStart(binary, address, daemonAddress, cgroup string, debug bool, exitHa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCommand(binary, daemonAddress string, debug bool, config Config, socket *os.File) *exec.Cmd {
|
func newCommand(binary, daemonAddress string, nonewns, debug bool, config Config, socket *os.File) *exec.Cmd {
|
||||||
args := []string{
|
args := []string{
|
||||||
"--namespace", config.Namespace,
|
"--namespace", config.Namespace,
|
||||||
"--workdir", config.WorkDir,
|
"--workdir", config.WorkDir,
|
||||||
@ -109,7 +109,7 @@ func newCommand(binary, daemonAddress string, debug bool, config Config, socket
|
|||||||
// make sure the shim can be re-parented to system init
|
// make sure the shim can be re-parented to system init
|
||||||
// and is cloned in a new mount namespace because the overlay/filesystems
|
// and is cloned in a new mount namespace because the overlay/filesystems
|
||||||
// will be mounted by the shim
|
// will be mounted by the shim
|
||||||
cmd.SysProcAttr = &atter
|
cmd.SysProcAttr = getSysProcAttr(nonewns)
|
||||||
cmd.ExtraFiles = append(cmd.ExtraFiles, socket)
|
cmd.ExtraFiles = append(cmd.ExtraFiles, socket)
|
||||||
if debug {
|
if debug {
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
|
@ -10,9 +10,14 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var atter = syscall.SysProcAttr{
|
func getSysProcAttr(nonewns bool) *syscall.SysProcAttr {
|
||||||
Cloneflags: syscall.CLONE_NEWNS,
|
attr := syscall.SysProcAttr{
|
||||||
Setpgid: true,
|
Setpgid: true,
|
||||||
|
}
|
||||||
|
if !nonewns {
|
||||||
|
attr.Cloneflags = syscall.CLONE_NEWNS
|
||||||
|
}
|
||||||
|
return &attr
|
||||||
}
|
}
|
||||||
|
|
||||||
func setCgroup(cgroupPath string, cmd *exec.Cmd) error {
|
func setCgroup(cgroupPath string, cmd *exec.Cmd) error {
|
||||||
|
@ -7,8 +7,10 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
var atter = syscall.SysProcAttr{
|
func getSysProcAttr(nonewns bool) *syscall.SysProcAttr {
|
||||||
|
return &syscall.SysProcAttr{
|
||||||
Setpgid: true,
|
Setpgid: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setCgroup(cgroupPath string, cmd *exec.Cmd) error {
|
func setCgroup(cgroupPath string, cmd *exec.Cmd) error {
|
||||||
|
Loading…
Reference in New Issue
Block a user