If we are running in a user namespace, don't try to mknod as
it won't be allowed. libcontainer will bind-mount the host's
devices over files in the container anyway, so it's not needed.
The chrootarchive package does a chroot (without mounting /proc) before
its work, so we cannot check /proc/self/uid_map when we need to. So
compute it in advance and pass it along with the tar options.
Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
| ... | ... |
@@ -11,6 +11,7 @@ import ( |
| 11 | 11 |
|
| 12 | 12 |
"github.com/docker/docker/pkg/pools" |
| 13 | 13 |
"github.com/docker/docker/pkg/system" |
| 14 |
+ rsystem "github.com/opencontainers/runc/libcontainer/system" |
|
| 14 | 15 |
) |
| 15 | 16 |
|
| 16 | 17 |
type copyFlags int |
| ... | ... |
@@ -105,6 +106,10 @@ func copyDir(srcDir, dstDir string, flags copyFlags) error {
|
| 105 | 105 |
case os.ModeNamedPipe: |
| 106 | 106 |
fallthrough |
| 107 | 107 |
case os.ModeSocket: |
| 108 |
+ if rsystem.RunningInUserNS() {
|
|
| 109 |
+ // cannot create a device if running in user namespace |
|
| 110 |
+ return nil |
|
| 111 |
+ } |
|
| 108 | 112 |
if err := syscall.Mkfifo(dstPath, stat.Mode); err != nil {
|
| 109 | 113 |
return err |
| 110 | 114 |
} |
| ... | ... |
@@ -59,6 +59,7 @@ type ( |
| 59 | 59 |
// For each include when creating an archive, the included name will be |
| 60 | 60 |
// replaced with the matching name from this map. |
| 61 | 61 |
RebaseNames map[string]string |
| 62 |
+ InUserNS bool |
|
| 62 | 63 |
} |
| 63 | 64 |
|
| 64 | 65 |
// Archiver allows the reuse of most utility functions of this package |
| ... | ... |
@@ -381,7 +382,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
| 381 | 381 |
return nil |
| 382 | 382 |
} |
| 383 | 383 |
|
| 384 |
-func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *TarChownOptions) error {
|
|
| 384 |
+func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *TarChownOptions, inUserns bool) error {
|
|
| 385 | 385 |
// hdr.Mode is in linux format, which we can use for sycalls, |
| 386 | 386 |
// but for os.Foo() calls we need the mode converted to os.FileMode, |
| 387 | 387 |
// so use hdrInfo.Mode() (they differ for e.g. setuid bits) |
| ... | ... |
@@ -409,7 +410,16 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L |
| 409 | 409 |
} |
| 410 | 410 |
file.Close() |
| 411 | 411 |
|
| 412 |
- case tar.TypeBlock, tar.TypeChar, tar.TypeFifo: |
|
| 412 |
+ case tar.TypeBlock, tar.TypeChar: |
|
| 413 |
+ if inUserns { // cannot create devices in a userns
|
|
| 414 |
+ return nil |
|
| 415 |
+ } |
|
| 416 |
+ // Handle this is an OS-specific way |
|
| 417 |
+ if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
|
|
| 418 |
+ return err |
|
| 419 |
+ } |
|
| 420 |
+ |
|
| 421 |
+ case tar.TypeFifo: |
|
| 413 | 422 |
// Handle this is an OS-specific way |
| 414 | 423 |
if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
|
| 415 | 424 |
return err |
| ... | ... |
@@ -817,7 +827,7 @@ loop: |
| 817 | 817 |
} |
| 818 | 818 |
} |
| 819 | 819 |
|
| 820 |
- if err := createTarFile(path, dest, hdr, trBuf, !options.NoLchown, options.ChownOpts); err != nil {
|
|
| 820 |
+ if err := createTarFile(path, dest, hdr, trBuf, !options.NoLchown, options.ChownOpts, options.InUserNS); err != nil {
|
|
| 821 | 821 |
return err |
| 822 | 822 |
} |
| 823 | 823 |
|
| ... | ... |
@@ -802,7 +802,7 @@ func TestTypeXGlobalHeaderDoesNotFail(t *testing.T) {
|
| 802 | 802 |
t.Fatal(err) |
| 803 | 803 |
} |
| 804 | 804 |
defer os.RemoveAll(tmpDir) |
| 805 |
- err = createTarFile(filepath.Join(tmpDir, "pax_global_header"), tmpDir, &hdr, nil, true, nil) |
|
| 805 |
+ err = createTarFile(filepath.Join(tmpDir, "pax_global_header"), tmpDir, &hdr, nil, true, nil, false) |
|
| 806 | 806 |
if err != nil {
|
| 807 | 807 |
t.Fatal(err) |
| 808 | 808 |
} |
| ... | ... |
@@ -10,6 +10,7 @@ import ( |
| 10 | 10 |
"syscall" |
| 11 | 11 |
|
| 12 | 12 |
"github.com/docker/docker/pkg/system" |
| 13 |
+ rsystem "github.com/opencontainers/runc/libcontainer/system" |
|
| 13 | 14 |
) |
| 14 | 15 |
|
| 15 | 16 |
// fixVolumePathPrefix does platform specific processing to ensure that if |
| ... | ... |
@@ -80,6 +81,11 @@ func minor(device uint64) uint64 {
|
| 80 | 80 |
// handleTarTypeBlockCharFifo is an OS-specific helper function used by |
| 81 | 81 |
// createTarFile to handle the following types of header: Block; Char; Fifo |
| 82 | 82 |
func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
|
| 83 |
+ if rsystem.RunningInUserNS() {
|
|
| 84 |
+ // cannot create a device if running in user namespace |
|
| 85 |
+ return nil |
|
| 86 |
+ } |
|
| 87 |
+ |
|
| 83 | 88 |
mode := uint32(hdr.Mode & 07777) |
| 84 | 89 |
switch hdr.Typeflag {
|
| 85 | 90 |
case tar.TypeBlock: |
| ... | ... |
@@ -111,7 +111,7 @@ func UnpackLayer(dest string, layer Reader, options *TarOptions) (size int64, er |
| 111 | 111 |
} |
| 112 | 112 |
defer os.RemoveAll(aufsTempdir) |
| 113 | 113 |
} |
| 114 |
- if err := createTarFile(filepath.Join(aufsTempdir, basename), dest, hdr, tr, true, nil); err != nil {
|
|
| 114 |
+ if err := createTarFile(filepath.Join(aufsTempdir, basename), dest, hdr, tr, true, nil, options.InUserNS); err != nil {
|
|
| 115 | 115 |
return 0, err |
| 116 | 116 |
} |
| 117 | 117 |
} |
| ... | ... |
@@ -219,7 +219,7 @@ func UnpackLayer(dest string, layer Reader, options *TarOptions) (size int64, er |
| 219 | 219 |
} |
| 220 | 220 |
srcHdr.Gid = xGID |
| 221 | 221 |
} |
| 222 |
- if err := createTarFile(path, dest, srcHdr, srcData, true, nil); err != nil {
|
|
| 222 |
+ if err := createTarFile(path, dest, srcHdr, srcData, true, nil, options.InUserNS); err != nil {
|
|
| 223 | 223 |
return 0, err |
| 224 | 224 |
} |
| 225 | 225 |
|
| ... | ... |
@@ -15,6 +15,7 @@ import ( |
| 15 | 15 |
"github.com/docker/docker/pkg/archive" |
| 16 | 16 |
"github.com/docker/docker/pkg/reexec" |
| 17 | 17 |
"github.com/docker/docker/pkg/system" |
| 18 |
+ rsystem "github.com/opencontainers/runc/libcontainer/system" |
|
| 18 | 19 |
) |
| 19 | 20 |
|
| 20 | 21 |
type applyLayerResponse struct {
|
| ... | ... |
@@ -34,6 +35,7 @@ func applyLayer() {
|
| 34 | 34 |
runtime.LockOSThread() |
| 35 | 35 |
flag.Parse() |
| 36 | 36 |
|
| 37 |
+ inUserns := rsystem.RunningInUserNS() |
|
| 37 | 38 |
if err := chroot(flag.Arg(0)); err != nil {
|
| 38 | 39 |
fatal(err) |
| 39 | 40 |
} |
| ... | ... |
@@ -49,6 +51,10 @@ func applyLayer() {
|
| 49 | 49 |
fatal(err) |
| 50 | 50 |
} |
| 51 | 51 |
|
| 52 |
+ if inUserns {
|
|
| 53 |
+ options.InUserNS = true |
|
| 54 |
+ } |
|
| 55 |
+ |
|
| 52 | 56 |
if tmpDir, err = ioutil.TempDir("/", "temp-docker-extract"); err != nil {
|
| 53 | 57 |
fatal(err) |
| 54 | 58 |
} |
| ... | ... |
@@ -88,6 +94,9 @@ func applyLayerHandler(dest string, layer archive.Reader, options *archive.TarOp |
| 88 | 88 |
} |
| 89 | 89 |
if options == nil {
|
| 90 | 90 |
options = &archive.TarOptions{}
|
| 91 |
+ if rsystem.RunningInUserNS() {
|
|
| 92 |
+ options.InUserNS = true |
|
| 93 |
+ } |
|
| 91 | 94 |
} |
| 92 | 95 |
if options.ExcludePatterns == nil {
|
| 93 | 96 |
options.ExcludePatterns = []string{}
|