diff --git a/cmd/ctr/commands/run/run_unix.go b/cmd/ctr/commands/run/run_unix.go index 2ba015cd0..ebc71031d 100644 --- a/cmd/ctr/commands/run/run_unix.go +++ b/cmd/ctr/commands/run/run_unix.go @@ -125,7 +125,7 @@ func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli opts = append(opts, oci.WithTTY) } if context.Bool("privileged") { - opts = append(opts, oci.WithPrivileged) + opts = append(opts, oci.WithPrivileged, oci.WithAllDevicesAllowed, oci.WithHostDevices) } if context.Bool("net-host") { opts = append(opts, oci.WithHostNamespace(specs.NetworkNamespace), oci.WithHostHostsFile, oci.WithHostResolvconf) diff --git a/oci/spec_opts.go b/oci/spec_opts.go index b3ccc389f..51818acbc 100644 --- a/oci/spec_opts.go +++ b/oci/spec_opts.go @@ -1115,7 +1115,6 @@ func WithDefaultUnixDevices(_ context.Context, _ Client, _ *containers.Container } // WithPrivileged sets up options for a privileged container -// TODO(justincormack) device handling var WithPrivileged = Compose( WithAllCapabilities, WithMaskedPaths(nil), diff --git a/oci/spec_opts_linux.go b/oci/spec_opts_linux.go index bfe04797b..1448ee78f 100644 --- a/oci/spec_opts_linux.go +++ b/oci/spec_opts_linux.go @@ -37,9 +37,7 @@ func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Sp if err != nil { return err } - for _, d := range devs { - s.Linux.Devices = append(s.Linux.Devices, d) - } + s.Linux.Devices = append(s.Linux.Devices, devs...) return nil } diff --git a/oci/spec_opts_unix.go b/oci/spec_opts_unix.go index 3f63dfd16..bcabf0efb 100644 --- a/oci/spec_opts_unix.go +++ b/oci/spec_opts_unix.go @@ -19,12 +19,69 @@ package oci import ( + "context" + "io/ioutil" "os" + "path/filepath" + "github.com/containerd/containerd/containers" specs "github.com/opencontainers/runtime-spec/specs-go" "golang.org/x/sys/unix" ) +// WithHostDevices adds all the hosts device nodes to the container's spec +func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + setLinux(s) + + devs, err := getDevices("/dev") + if err != nil { + return err + } + s.Linux.Devices = append(s.Linux.Devices, devs...) + return nil +} + +func getDevices(path string) ([]specs.LinuxDevice, error) { + files, err := ioutil.ReadDir(path) + if err != nil { + return nil, err + } + var out []specs.LinuxDevice + for _, f := range files { + switch { + case f.IsDir(): + switch f.Name() { + // ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825 + // ".udev" added to address https://github.com/opencontainers/runc/issues/2093 + case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev": + continue + default: + sub, err := getDevices(filepath.Join(path, f.Name())) + if err != nil { + return nil, err + } + + out = append(out, sub...) + continue + } + case f.Name() == "console": + continue + } + device, err := deviceFromPath(filepath.Join(path, f.Name()), "rwm") + if err != nil { + if err == ErrNotADevice { + continue + } + if os.IsNotExist(err) { + continue + } + return nil, err + } + out = append(out, *device) + } + return out, nil +} + func deviceFromPath(path, permissions string) (*specs.LinuxDevice, error) { var stat unix.Stat_t if err := unix.Lstat(path, &stat); err != nil {