github.com/dctrud/umoci@v0.4.3-0.20191016193643-05a1d37de015/oci/layer/tar_extract.go (about)

     1  /*
     2   * umoci: Umoci Modifies Open Containers' Images
     3   * Copyright (C) 2016, 2017, 2018 SUSE LLC.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *    http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package layer
    19  
    20  import (
    21  	"archive/tar"
    22  	"bytes"
    23  	"fmt"
    24  	"io"
    25  	"os"
    26  	"path/filepath"
    27  	"strings"
    28  	"time"
    29  
    30  	"github.com/apex/log"
    31  	"github.com/cyphar/filepath-securejoin"
    32  	"github.com/openSUSE/umoci/pkg/fseval"
    33  	"github.com/openSUSE/umoci/pkg/system"
    34  	"github.com/openSUSE/umoci/third_party/shared"
    35  	"github.com/pkg/errors"
    36  	"golang.org/x/sys/unix"
    37  )
    38  
    39  // inUserNamespace is a cached return value of shared.RunningInUserNS(). We
    40  // compute this once globally rather than for each unpack. It won't change (we
    41  // would hope) after we check it the first time.
    42  var inUserNamespace = shared.RunningInUserNS()
    43  
    44  // TarExtractor represents a tar file to be extracted.
    45  type TarExtractor struct {
    46  	// mapOptions is the set of mapping options to use when extracting
    47  	// filesystem layers.
    48  	mapOptions MapOptions
    49  
    50  	// partialRootless indicates whether "partial rootless" tricks should be
    51  	// applied in our extraction. Rootless and userns execution have some
    52  	// similar tricks necessary, but not all rootless tricks should be applied
    53  	// when running in a userns -- hence the term "partial rootless" tricks.
    54  	partialRootless bool
    55  
    56  	// fsEval is an fseval.FsEval used for extraction.
    57  	fsEval fseval.FsEval
    58  
    59  	// upperPaths are paths that have either been extracted in the execution of
    60  	// this TarExtractor or are ancestors of paths extracted. The purpose of
    61  	// having this stored in-memory is to be able to handle opaque whiteouts as
    62  	// well as some other possible ordering issues with malformed archives (the
    63  	// downside of this approach is that it takes up memory -- we could switch
    64  	// to a trie if necessary). These paths are relative to the tar root but
    65  	// are fully symlink-expanded so no need to worry about that line noise.
    66  	upperPaths map[string]struct{}
    67  }
    68  
    69  // NewTarExtractor creates a new TarExtractor.
    70  func NewTarExtractor(opt MapOptions) *TarExtractor {
    71  	fsEval := fseval.DefaultFsEval
    72  	if opt.Rootless {
    73  		fsEval = fseval.RootlessFsEval
    74  	}
    75  
    76  	return &TarExtractor{
    77  		mapOptions:      opt,
    78  		partialRootless: opt.Rootless || inUserNamespace,
    79  		fsEval:          fsEval,
    80  		upperPaths:      make(map[string]struct{}),
    81  	}
    82  }
    83  
    84  // restoreMetadata applies the state described in tar.Header to the filesystem
    85  // at the given path. No sanity checking is done of the tar.Header's pathname
    86  // or other information. In addition, no mapping is done of the header.
    87  func (te *TarExtractor) restoreMetadata(path string, hdr *tar.Header) error {
    88  	// Some of the tar.Header fields don't match the OS API.
    89  	fi := hdr.FileInfo()
    90  
    91  	// Get the _actual_ file info to figure out if the path is a symlink.
    92  	isSymlink := hdr.Typeflag == tar.TypeSymlink
    93  	if realFi, err := te.fsEval.Lstat(path); err == nil {
    94  		isSymlink = realFi.Mode()&os.ModeSymlink == os.ModeSymlink
    95  	}
    96  
    97  	// Apply the owner. If we are rootless then "user.rootlesscontainers" has
    98  	// already been set up by unmapHeader, so nothing to do here.
    99  	if !te.mapOptions.Rootless {
   100  		// XXX: While unpriv.Lchown doesn't make a whole lot of sense this
   101  		//      should _probably_ be put inside FsEval.
   102  		if err := os.Lchown(path, hdr.Uid, hdr.Gid); err != nil {
   103  			return errors.Wrapf(err, "restore chown metadata: %s", path)
   104  		}
   105  	}
   106  
   107  	// We cannot apply hdr.Mode to symlinks, because symlinks don't have a mode
   108  	// of their own (they're special in that way). We have to apply this after
   109  	// we've applied the owner because setuid bits are cleared when changing
   110  	// owner (in rootless we don't care because we're always the owner).
   111  	if !isSymlink {
   112  		if err := te.fsEval.Chmod(path, fi.Mode()); err != nil {
   113  			return errors.Wrapf(err, "restore chmod metadata: %s", path)
   114  		}
   115  	}
   116  
   117  	// Apply access and modified time. Note that some archives won't fill the
   118  	// atime and mtime fields, so we have to set them to a more sane value.
   119  	// Otherwise Linux will start screaming at us, and nobody wants that.
   120  	mtime := hdr.ModTime
   121  	if mtime.IsZero() {
   122  		// XXX: Should we instead default to atime if it's non-zero?
   123  		mtime = time.Now()
   124  	}
   125  	atime := hdr.AccessTime
   126  	if atime.IsZero() {
   127  		// Default to the mtime.
   128  		atime = mtime
   129  	}
   130  
   131  	// Apply xattrs. In order to make sure that we *only* have the xattr set we
   132  	// want, we first clear the set of xattrs from the file then apply the ones
   133  	// set in the tar.Header.
   134  	err := te.fsEval.Lclearxattrs(path, ignoreXattrs)
   135  	if err != nil {
   136  		if errors.Cause(err) != unix.ENOTSUP {
   137  			return errors.Wrapf(err, "clear xattr metadata: %s", path)
   138  		}
   139  		log.Warnf("ignoring ENOTSUP on clearxattrs %q", path)
   140  	}
   141  
   142  	for name, value := range hdr.Xattrs {
   143  		value := []byte(value)
   144  
   145  		// Forbidden xattrs should never be touched.
   146  		if _, skip := ignoreXattrs[name]; skip {
   147  			// If the xattr is already set to the requested value, don't bail.
   148  			// The reason for this logic is kinda convoluted, but effectively
   149  			// because restoreMetadata is called with the *on-disk* metadata we
   150  			// run the risk of things like "security.selinux" being included in
   151  			// that metadata (and thus tripping the forbidden xattr error). By
   152  			// only touching xattrs that have a different value we are somewhat
   153  			// more efficient and we don't have to special case parent restore.
   154  			// Of course this will only ever impact ignoreXattrs.
   155  			if oldValue, err := te.fsEval.Lgetxattr(path, name); err == nil {
   156  				if bytes.Equal(value, oldValue) {
   157  					log.Debugf("restore xattr metadata: skipping already-set xattr %q: %s", name, hdr.Name)
   158  					continue
   159  				}
   160  			}
   161  			log.Warnf("xatt{%s} ignoring forbidden xattr: %q", hdr.Name, name)
   162  			continue
   163  		}
   164  		if err := te.fsEval.Lsetxattr(path, name, value, 0); err != nil {
   165  			// In rootless mode, some xattrs will fail (security.capability).
   166  			// This is _fine_ as long as we're not running as root (in which
   167  			// case we shouldn't be ignoring xattrs that we were told to set).
   168  			//
   169  			// TODO: We should translate all security.capability capabilites
   170  			//       into v3 capabilities, which allow us to write them as
   171  			//       unprivileged users (we also would need to translate them
   172  			//       back when creating archives).
   173  			if te.partialRootless && os.IsPermission(errors.Cause(err)) {
   174  				log.Warnf("rootless{%s} ignoring (usually) harmless EPERM on setxattr %q", hdr.Name, name)
   175  				continue
   176  			}
   177  			// We cannot do much if we get an ENOTSUP -- this usually means
   178  			// that extended attributes are simply unsupported by the
   179  			// underlying filesystem (such as AUFS or NFS).
   180  			if errors.Cause(err) == unix.ENOTSUP {
   181  				log.Warnf("xatt{%s} ignoring ENOTSUP on setxattr %q", hdr.Name, name)
   182  				continue
   183  			}
   184  			return errors.Wrapf(err, "restore xattr metadata: %s", path)
   185  		}
   186  	}
   187  
   188  	if err := te.fsEval.Lutimes(path, atime, mtime); err != nil {
   189  		return errors.Wrapf(err, "restore lutimes metadata: %s", path)
   190  	}
   191  
   192  	return nil
   193  }
   194  
   195  // applyMetadata applies the state described in tar.Header to the filesystem at
   196  // the given path, using the state of the TarExtractor to remap information
   197  // within the header. This should only be used with headers from a tar layer
   198  // (not from the filesystem). No sanity checking is done of the tar.Header's
   199  // pathname or other information.
   200  func (te *TarExtractor) applyMetadata(path string, hdr *tar.Header) error {
   201  	// Modify the header.
   202  	if err := unmapHeader(hdr, te.mapOptions); err != nil {
   203  		return errors.Wrap(err, "unmap header")
   204  	}
   205  
   206  	// Restore it on the filesystme.
   207  	return te.restoreMetadata(path, hdr)
   208  }
   209  
   210  // isDirlink returns whether the given path is a link to a directory (or a
   211  // dirlink in rsync(1) parlance) which is used by --keep-dirlink to see whether
   212  // we should extract through the link or clobber the link with a directory (in
   213  // the case where we see a directory to extract and a symlink already exists
   214  // there).
   215  func (te *TarExtractor) isDirlink(root string, path string) (bool, error) {
   216  	// Make sure it exists and is a symlink.
   217  	if _, err := te.fsEval.Readlink(path); err != nil {
   218  		return false, errors.Wrap(err, "read dirlink")
   219  	}
   220  
   221  	// Technically a string.TrimPrefix would also work...
   222  	unsafePath, err := filepath.Rel(root, path)
   223  	if err != nil {
   224  		return false, errors.Wrap(err, "get relative-to-root path")
   225  	}
   226  
   227  	// It should be noted that SecureJoin will evaluate all symlinks in the
   228  	// path, so we don't need to loop over it or anything like that. It'll just
   229  	// be done for us (in UnpackEntry only the dirname(3) is evaluated but here
   230  	// we evaluate the whole thing).
   231  	targetPath, err := securejoin.SecureJoinVFS(root, unsafePath, te.fsEval)
   232  	if err != nil {
   233  		// We hit a symlink loop -- which is fine but that means that this
   234  		// cannot be considered a dirlink.
   235  		if errno := InnerErrno(err); errno == unix.ELOOP {
   236  			err = nil
   237  		}
   238  		return false, errors.Wrap(err, "sanitize old target")
   239  	}
   240  
   241  	targetInfo, err := te.fsEval.Lstat(targetPath)
   242  	if err != nil {
   243  		// ENOENT or similar just means that it's a broken symlink, which
   244  		// means we have to overwrite it (but it's an allowed case).
   245  		if securejoin.IsNotExist(err) {
   246  			err = nil
   247  		}
   248  		return false, err
   249  	}
   250  
   251  	return targetInfo.IsDir(), nil
   252  }
   253  
   254  // UnpackEntry extracts the given tar.Header to the provided root, ensuring
   255  // that the layer state is consistent with the layer state that produced the
   256  // tar archive being iterated over. This does handle whiteouts, so a tar.Header
   257  // that represents a whiteout will result in the path being removed.
   258  func (te *TarExtractor) UnpackEntry(root string, hdr *tar.Header, r io.Reader) (Err error) {
   259  	// Make the paths safe.
   260  	hdr.Name = CleanPath(hdr.Name)
   261  	root = filepath.Clean(root)
   262  
   263  	log.WithFields(log.Fields{
   264  		"root": root,
   265  		"path": hdr.Name,
   266  		"type": hdr.Typeflag,
   267  	}).Debugf("unpacking entry")
   268  
   269  	// Get directory and filename, but we have to safely get the directory
   270  	// component of the path. SecureJoinVFS will evaluate the path itself,
   271  	// which we don't want (we're clever enough to handle the actual path being
   272  	// a symlink).
   273  	unsafeDir, file := filepath.Split(hdr.Name)
   274  	if filepath.Join("/", hdr.Name) == "/" {
   275  		// If we got an entry for the root, then unsafeDir is the full path.
   276  		unsafeDir, file = hdr.Name, "."
   277  	}
   278  	dir, err := securejoin.SecureJoinVFS(root, unsafeDir, te.fsEval)
   279  	if err != nil {
   280  		return errors.Wrap(err, "sanitise symlinks in root")
   281  	}
   282  	path := filepath.Join(dir, file)
   283  
   284  	// Before we do anything, get the state of dir. Because we might be adding
   285  	// or removing files, our parent directory might be modified in the
   286  	// process. As a result, we want to be able to restore the old state
   287  	// (because we only apply state that we find in the archive we're iterating
   288  	// over). We can safely ignore an error here, because a non-existent
   289  	// directory will be fixed by later archive entries.
   290  	if dirFi, err := te.fsEval.Lstat(dir); err == nil && path != dir {
   291  		// FIXME: This is really stupid.
   292  		link, _ := te.fsEval.Readlink(dir)
   293  		dirHdr, err := tar.FileInfoHeader(dirFi, link)
   294  		if err != nil {
   295  			return errors.Wrap(err, "convert dirFi to dirHdr")
   296  		}
   297  
   298  		// More faking to trick restoreMetadata to actually restore the directory.
   299  		dirHdr.Typeflag = tar.TypeDir
   300  		dirHdr.Linkname = ""
   301  
   302  		// os.Lstat doesn't get the list of xattrs by default. We need to fill
   303  		// this explicitly. Note that while Go's "archive/tar" takes strings,
   304  		// in Go strings can be arbitrary byte sequences so this doesn't
   305  		// restrict the possible values.
   306  		// TODO: Move this to a separate function so we can share it with
   307  		//       tar_generate.go.
   308  		xattrs, err := te.fsEval.Llistxattr(dir)
   309  		if err != nil {
   310  			if errors.Cause(err) != unix.ENOTSUP {
   311  				return errors.Wrap(err, "get dirHdr.Xattrs")
   312  			}
   313  			log.Warnf("ignoring ENOTSUP on listxattr %q", dir)
   314  		}
   315  		if len(xattrs) > 0 {
   316  			dirHdr.Xattrs = map[string]string{}
   317  			for _, xattr := range xattrs {
   318  				value, err := te.fsEval.Lgetxattr(dir, xattr)
   319  				if err != nil {
   320  					return errors.Wrap(err, "get xattr")
   321  				}
   322  				dirHdr.Xattrs[xattr] = string(value)
   323  			}
   324  		}
   325  
   326  		// Ensure that after everything we correctly re-apply the old metadata.
   327  		// We don't map this header because we're restoring files that already
   328  		// existed on the filesystem, not from a tar layer.
   329  		defer func() {
   330  			// Only overwrite the error if there wasn't one already.
   331  			if err := te.restoreMetadata(dir, dirHdr); err != nil {
   332  				if Err == nil {
   333  					Err = errors.Wrap(err, "restore parent directory")
   334  				}
   335  			}
   336  		}()
   337  	}
   338  
   339  	// Currently the spec doesn't specify what the hdr.Typeflag of whiteout
   340  	// files is meant to be. We specifically only produce regular files
   341  	// ('\x00') but it could be possible that someone produces a different
   342  	// Typeflag, expecting that the path is the only thing that matters in a
   343  	// whiteout entry.
   344  	if strings.HasPrefix(file, whPrefix) {
   345  		isOpaque := file == whOpaque
   346  		file = strings.TrimPrefix(file, whPrefix)
   347  
   348  		// We have to be quite careful here. While the most intuitive way of
   349  		// handling whiteouts would be to just RemoveAll without prejudice, We
   350  		// have to be careful here. If there is a whiteout entry for a file
   351  		// *after* a normal entry (in the same layer) then the whiteout must
   352  		// not remove the new entry. We handle this by keeping track of
   353  		// whichpaths have been touched by this layer's extraction (these form
   354  		// the "upperdir"). We also have to handle cases where a directory has
   355  		// been marked for deletion, but a child has been extracted in this
   356  		// layer.
   357  
   358  		path = filepath.Join(dir, file)
   359  		if isOpaque {
   360  			path = dir
   361  		}
   362  
   363  		// If the root doesn't exist we've got nothing to do.
   364  		// XXX: We currently cannot error out if a layer asks us to remove a
   365  		//      non-existent path with this implementation (because we don't
   366  		//      know if it was implicitly removed by another whiteout). In
   367  		//      future we could add lowerPaths that would help track whether
   368  		//      another whiteout caused the removal to "fail" or if the path
   369  		//      was actually missing -- which would allow us to actually error
   370  		//      out here if the layer is invalid).
   371  		if _, err := te.fsEval.Lstat(path); err != nil {
   372  			// Need to use securejoin.IsNotExist to handle ENOTDIR.
   373  			if securejoin.IsNotExist(err) {
   374  				err = nil
   375  			}
   376  			return errors.Wrap(err, "check whiteout target")
   377  		}
   378  
   379  		// Walk over the path to remove it. We remove a given path as soon as
   380  		// it isn't present in upperPaths (which includes ancestors of paths
   381  		// we've extracted so we only need to look up the one path). Otherwise
   382  		// we iterate over any children and try again. The only difference
   383  		// between opaque whiteouts and regular whiteouts is that we don't
   384  		// delete the directory itself with opaque whiteouts.
   385  		err = te.fsEval.Walk(path, func(subpath string, info os.FileInfo, err error) error {
   386  			// If we are passed an error, bail unless it's ENOENT.
   387  			if err != nil {
   388  				// If something was deleted outside of our knowledge it's not
   389  				// the end of the world. In principle this shouldn't happen
   390  				// though, so we log it for posterity.
   391  				if os.IsNotExist(errors.Cause(err)) {
   392  					log.Debugf("whiteout removal hit already-deleted path: %s", subpath)
   393  					err = filepath.SkipDir
   394  				}
   395  				return err
   396  			}
   397  
   398  			// Get the relative form of subpath to root to match
   399  			// te.upperPaths.
   400  			upperPath, err := filepath.Rel(root, subpath)
   401  			if err != nil {
   402  				return errors.Wrap(err, "find relative-to-root [should never happen]")
   403  			}
   404  
   405  			// Remove the path only if it hasn't been touched.
   406  			if _, ok := te.upperPaths[upperPath]; !ok {
   407  				// Opaque whiteouts don't remove the directory itself, so skip
   408  				// the top-level directory.
   409  				if isOpaque && CleanPath(path) == CleanPath(subpath) {
   410  					return nil
   411  				}
   412  
   413  				// Purge the path. We skip anything underneath (if it's a
   414  				// directory) since we just purged it -- and we don't want to
   415  				// hit ENOENT during iteration for no good reason.
   416  				err := errors.Wrap(te.fsEval.RemoveAll(subpath), "whiteout subpath")
   417  				if err == nil && info.IsDir() {
   418  					err = filepath.SkipDir
   419  				}
   420  				return err
   421  			}
   422  			return nil
   423  		})
   424  		return errors.Wrap(err, "whiteout remove")
   425  	}
   426  
   427  	// Get information about the path. This has to be done after we've dealt
   428  	// with whiteouts because it turns out that lstat(2) will return EPERM if
   429  	// you try to stat a whiteout on AUFS.
   430  	fi, err := te.fsEval.Lstat(path)
   431  	if err != nil {
   432  		// File doesn't exist, just switch fi to the file header.
   433  		fi = hdr.FileInfo()
   434  	}
   435  
   436  	// Attempt to create the parent directory of the path we're unpacking.
   437  	// We do a MkdirAll here because even though you need to have a tar entry
   438  	// for every component of a new path, applyMetadata will correct any
   439  	// inconsistencies.
   440  	// FIXME: We have to make this consistent, since if the tar archive doesn't
   441  	//        have entries for some of these components we won't be able to
   442  	//        verify that we have consistent results during unpacking.
   443  	if err := te.fsEval.MkdirAll(dir, 0777); err != nil {
   444  		return errors.Wrap(err, "mkdir parent")
   445  	}
   446  
   447  	isDirlink := false
   448  	// We remove whatever existed at the old path to clobber it so that
   449  	// creating a new path will not break. The only exception is if the path is
   450  	// a directory in both the layer and the current filesystem, in which case
   451  	// we don't delete it for obvious reasons. In all other cases we clobber.
   452  	//
   453  	// Note that this will cause hard-links in the "lower" layer to not be able
   454  	// to point to "upper" layer inodes even if the extracted type is the same
   455  	// as the old one, however it is not clear whether this is something a user
   456  	// would expect anyway. In addition, this will incorrectly deal with a
   457  	// TarLink that is present before the "upper" entry in the layer but the
   458  	// "lower" file still exists (so the hard-link would point to the old
   459  	// inode). It's not clear if such an archive is actually valid though.
   460  	if !fi.IsDir() || hdr.Typeflag != tar.TypeDir {
   461  		// If we are in --keep-dirlinks mode and the existing fs object is a
   462  		// symlink to a directory (with the pending object is a directory), we
   463  		// don't remove the symlink (and instead allow subsequent objects to be
   464  		// just written through the symlink into the directory). This is a very
   465  		// specific usecase where layers that were generated independently from
   466  		// each other (on different base filesystems) end up with weird things
   467  		// like /lib64 being a symlink only sometimes but you never want to
   468  		// delete libraries (not just the ones that were under the "real"
   469  		// directory).
   470  		//
   471  		// TODO: This code should also handle a pending symlink entry where the
   472  		//       existing object is a directory. I'm not sure how we could
   473  		//       disambiguate this from a symlink-to-a-file but I imagine that
   474  		//       this is something that would also be useful in the same vein
   475  		//       as --keep-dirlinks (which currently only prevents clobbering
   476  		//       in the opposite case).
   477  		if te.mapOptions.KeepDirlinks &&
   478  			fi.Mode()&os.ModeSymlink == os.ModeSymlink && hdr.Typeflag == tar.TypeDir {
   479  			isDirlink, err = te.isDirlink(root, path)
   480  			if err != nil {
   481  				return errors.Wrap(err, "check is dirlink")
   482  			}
   483  		}
   484  		if !(isDirlink && te.mapOptions.KeepDirlinks) {
   485  			if err := te.fsEval.RemoveAll(path); err != nil {
   486  				return errors.Wrap(err, "clobber old path")
   487  			}
   488  		}
   489  	}
   490  
   491  	// Now create or otherwise modify the state of the path. Right now, either
   492  	// the type of path matches hdr or the path doesn't exist. Note that we
   493  	// don't care about umasks or the initial mode here, since applyMetadata
   494  	// will fix all of that for us.
   495  	switch hdr.Typeflag {
   496  	// regular file
   497  	case tar.TypeReg, tar.TypeRegA:
   498  		// Create a new file, then just copy the data.
   499  		fh, err := te.fsEval.Create(path)
   500  		if err != nil {
   501  			return errors.Wrap(err, "create regular")
   502  		}
   503  		defer fh.Close()
   504  
   505  		// We need to make sure that we copy all of the bytes.
   506  		if n, err := io.Copy(fh, r); err != nil {
   507  			return err
   508  		} else if int64(n) != hdr.Size {
   509  			return errors.Wrap(io.ErrShortWrite, "unpack to regular file")
   510  		}
   511  
   512  		// Force close here so that we don't affect the metadata.
   513  		fh.Close()
   514  
   515  	// directory
   516  	case tar.TypeDir:
   517  		if isDirlink {
   518  			break
   519  		}
   520  
   521  		// Attempt to create the directory. We do a MkdirAll here because even
   522  		// though you need to have a tar entry for every component of a new
   523  		// path, applyMetadata will correct any inconsistencies.
   524  		if err := te.fsEval.MkdirAll(path, 0777); err != nil {
   525  			return errors.Wrap(err, "mkdirall")
   526  		}
   527  
   528  	// hard link, symbolic link
   529  	case tar.TypeLink, tar.TypeSymlink:
   530  		linkname := hdr.Linkname
   531  
   532  		// Hardlinks and symlinks act differently when it comes to the scoping.
   533  		// In both cases, we have to just unlink and then re-link the given
   534  		// path. But the function used and the argument are slightly different.
   535  		var linkFn func(string, string) error
   536  		switch hdr.Typeflag {
   537  		case tar.TypeLink:
   538  			linkFn = te.fsEval.Link
   539  			// Because hardlinks are inode-based we need to scope the link to
   540  			// the rootfs using SecureJoinVFS. As before, we need to be careful
   541  			// that we don't resolve the last part of the link path (in case
   542  			// the user actually wanted to hardlink to a symlink).
   543  			unsafeLinkDir, linkFile := filepath.Split(CleanPath(linkname))
   544  			linkDir, err := securejoin.SecureJoinVFS(root, unsafeLinkDir, te.fsEval)
   545  			if err != nil {
   546  				return errors.Wrap(err, "sanitise hardlink target in root")
   547  			}
   548  			linkname = filepath.Join(linkDir, linkFile)
   549  		case tar.TypeSymlink:
   550  			linkFn = te.fsEval.Symlink
   551  		}
   552  
   553  		// Link the new one.
   554  		if err := linkFn(linkname, path); err != nil {
   555  			// FIXME: Currently this can break if tar hardlink entries occur
   556  			//        before we hit the entry those hardlinks link to. I have a
   557  			//        feeling that such archives are invalid, but the correct
   558  			//        way of handling this is to delay link creation until the
   559  			//        very end. Unfortunately this won't work with symlinks
   560  			//        (which can link to directories).
   561  			return errors.Wrap(err, "link")
   562  		}
   563  
   564  	// character device node, block device node
   565  	case tar.TypeChar, tar.TypeBlock:
   566  		// In rootless mode we have no choice but to fake this, since mknod(2)
   567  		// doesn't work as an unprivileged user here.
   568  		//
   569  		// TODO: We need to add the concept of a fake block device in
   570  		//       "user.rootlesscontainers", because this workaround suffers
   571  		//       from the obvious issue that if the file is touched (even the
   572  		//       metadata) then it will be incorrectly copied into the layer.
   573  		//       This would break distribution images fairly badly.
   574  		if te.partialRootless {
   575  			log.Warnf("rootless{%s} creating empty file in place of device %d:%d", hdr.Name, hdr.Devmajor, hdr.Devminor)
   576  			fh, err := te.fsEval.Create(path)
   577  			if err != nil {
   578  				return errors.Wrap(err, "create rootless block")
   579  			}
   580  			defer fh.Close()
   581  			if err := fh.Chmod(0); err != nil {
   582  				return errors.Wrap(err, "chmod 0 rootless block")
   583  			}
   584  			goto out
   585  		}
   586  
   587  		// Otherwise the handling is the same as a FIFO.
   588  		fallthrough
   589  	// fifo node
   590  	case tar.TypeFifo:
   591  		// We have to remove and then create the device. In the FIFO case we
   592  		// could choose not to do so, but we do it anyway just to be on the
   593  		// safe side.
   594  
   595  		mode := system.Tarmode(hdr.Typeflag)
   596  		dev := unix.Mkdev(uint32(hdr.Devmajor), uint32(hdr.Devminor))
   597  
   598  		// Create the node.
   599  		if err := te.fsEval.Mknod(path, os.FileMode(int64(mode)|hdr.Mode), dev); err != nil {
   600  			return errors.Wrap(err, "mknod")
   601  		}
   602  
   603  	// We should never hit any other headers (Go abstracts them away from us),
   604  	// and we can't handle any custom Tar extensions. So just error out.
   605  	default:
   606  		return fmt.Errorf("unpack entry: %s: unknown typeflag '\\x%x'", hdr.Name, hdr.Typeflag)
   607  	}
   608  
   609  out:
   610  	// Apply the metadata, which will apply any mappings necessary. We don't
   611  	// apply metadata for hardlinks, because hardlinks don't have any separate
   612  	// metadata from their link (and the tar headers might not be filled).
   613  	if hdr.Typeflag != tar.TypeLink {
   614  		if err := te.applyMetadata(path, hdr); err != nil {
   615  			return errors.Wrap(err, "apply hdr metadata")
   616  		}
   617  	}
   618  
   619  	// Everything is done -- the path now exists. Add it (and all its
   620  	// ancestors) to the set of upper paths. We first have to figure out the
   621  	// proper path corresponding to hdr.Name though.
   622  	upperPath, err := filepath.Rel(root, path)
   623  	if err != nil {
   624  		// Really shouldn't happen because of the guarantees of SecureJoinVFS.
   625  		return errors.Wrap(err, "find relative-to-root [should never happen]")
   626  	}
   627  	for pth := upperPath; pth != filepath.Dir(pth); pth = filepath.Dir(pth) {
   628  		te.upperPaths[pth] = struct{}{}
   629  	}
   630  	return nil
   631  }