github.com/rootless-containers/rootlesskit/v2@v2.3.4/pkg/copyup/tmpfssymlink/tmpfssymlink.go (about)

     1  package tmpfssymlink
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  
     9  	"golang.org/x/sys/unix"
    10  
    11  	"github.com/rootless-containers/rootlesskit/v2/pkg/copyup"
    12  )
    13  
    14  func NewChildDriver() copyup.ChildDriver {
    15  	return &childDriver{}
    16  }
    17  
    18  type childDriver struct {
    19  }
    20  
    21  func (d *childDriver) CopyUp(dirs []string) ([]string, error) {
    22  	// we create bind0 outside of StateDir so as to allow
    23  	// copying up /run with stateDir=/run/user/1001/rootlesskit/default.
    24  	bind0, err := os.MkdirTemp("/tmp", "rootlesskit-b")
    25  	if err != nil {
    26  		return nil, fmt.Errorf("creating bind0 directory under /tmp: %w", err)
    27  	}
    28  	defer os.RemoveAll(bind0)
    29  	var copied []string
    30  	for _, d := range dirs {
    31  		d := filepath.Clean(d)
    32  		if d == "/tmp" {
    33  			// TODO: we can support copy-up /tmp by changing bind0TempDir
    34  			return copied, errors.New("/tmp cannot be copied up")
    35  		}
    36  
    37  		if err := unix.Mount(d, bind0, "", uintptr(unix.MS_BIND|unix.MS_REC), ""); err != nil {
    38  			return copied, fmt.Errorf("failed to create bind mount on %s: %w", d, err)
    39  		}
    40  
    41  		if err := unix.Mount("none", d, "tmpfs", 0, ""); err != nil {
    42  			return copied, fmt.Errorf("failed to mount tmpfs on %s: %w", d, err)
    43  		}
    44  
    45  		bind1, err := os.MkdirTemp(d, ".ro")
    46  		if err != nil {
    47  			return copied, fmt.Errorf("creating a directory under %s: %w", d, err)
    48  		}
    49  		if err := unix.Mount(bind0, bind1, "", uintptr(unix.MS_MOVE), ""); err != nil {
    50  			return copied, fmt.Errorf("failed to move mount point from %s to %s: %w", bind0, bind1, err)
    51  		}
    52  
    53  		files, err := os.ReadDir(bind1)
    54  		if err != nil {
    55  			return copied, fmt.Errorf("reading dir %s: %w", bind1, err)
    56  		}
    57  		for _, f := range files {
    58  			fFull := filepath.Join(bind1, f.Name())
    59  			var symlinkSrc string
    60  			if f.Type()&os.ModeSymlink != 0 {
    61  				symlinkSrc, err = os.Readlink(fFull)
    62  				if err != nil {
    63  					return copied, fmt.Errorf("reading dir %s: %w", fFull, err)
    64  				}
    65  			} else {
    66  				symlinkSrc = filepath.Join(filepath.Base(bind1), f.Name())
    67  			}
    68  			symlinkDst := filepath.Join(d, f.Name())
    69  			// `mount` may create extra `/etc/mtab` after mounting empty tmpfs on /etc
    70  			// https://github.com/rootless-containers/rootlesskit/issues/45
    71  			if err = os.RemoveAll(symlinkDst); err != nil {
    72  				return copied, fmt.Errorf("removing %s: %w", symlinkDst, err)
    73  			}
    74  			if err := os.Symlink(symlinkSrc, symlinkDst); err != nil {
    75  				return copied, fmt.Errorf("symlinking %s to %s: %w", symlinkSrc, symlinkDst, err)
    76  			}
    77  		}
    78  		copied = append(copied, d)
    79  	}
    80  	return copied, nil
    81  }