github.com/criyle/go-sandbox@v0.10.3/pkg/mount/builder_linux.go (about)

     1  package mount
     2  
     3  import (
     4  	"os"
     5  	"strings"
     6  
     7  	"golang.org/x/sys/unix"
     8  )
     9  
    10  const (
    11  	bind  = unix.MS_BIND | unix.MS_NOSUID | unix.MS_PRIVATE | unix.MS_REC
    12  	mFlag = unix.MS_NOSUID | unix.MS_NOATIME | unix.MS_NODEV
    13  )
    14  
    15  // NewDefaultBuilder creates default builder for minimal rootfs
    16  func NewDefaultBuilder() *Builder {
    17  	return NewBuilder().
    18  		WithBind("/usr", "usr", true).
    19  		WithBind("/lib", "lib", true).
    20  		WithBind("/lib64", "lib64", true).
    21  		WithBind("/bin", "bin", true)
    22  }
    23  
    24  // Build creates sequence of syscalls for fork_exec
    25  func (b *Builder) Build() ([]SyscallParams, error) {
    26  	var err error
    27  	ret := make([]SyscallParams, 0, len(b.Mounts))
    28  	for _, m := range b.Mounts {
    29  		var mknod bool
    30  		if mknod, err = isBindMountFileOrNotExists(m); err != nil {
    31  			return nil, err
    32  		}
    33  		sp, err := m.ToSyscall()
    34  		if err != nil {
    35  			return nil, err
    36  		}
    37  		sp.MakeNod = mknod
    38  		ret = append(ret, *sp)
    39  	}
    40  	return ret, nil
    41  }
    42  
    43  // FilterNotExist removes bind mount that does not exists
    44  func (b *Builder) FilterNotExist() *Builder {
    45  	rt := b.Mounts[:0]
    46  	for _, m := range b.Mounts {
    47  		if m.IsBindMount() {
    48  			if _, err := os.Stat(m.Source); os.IsNotExist(err) {
    49  				continue
    50  			}
    51  		}
    52  		rt = append(rt, m)
    53  	}
    54  	b.Mounts = rt
    55  	return b
    56  }
    57  
    58  func isBindMountFileOrNotExists(m Mount) (bool, error) {
    59  	if m.IsBindMount() {
    60  		if fi, err := os.Stat(m.Source); os.IsNotExist(err) {
    61  			return false, err
    62  		} else if !fi.IsDir() {
    63  			return true, err
    64  		}
    65  	}
    66  	return false, nil
    67  }
    68  
    69  // WithMounts add mounts to builder
    70  func (b *Builder) WithMounts(m []Mount) *Builder {
    71  	b.Mounts = append(b.Mounts, m...)
    72  	return b
    73  }
    74  
    75  // WithMount add single mount to builder
    76  func (b *Builder) WithMount(m Mount) *Builder {
    77  	b.Mounts = append(b.Mounts, m)
    78  	return b
    79  }
    80  
    81  // WithBind adds a bind mount to builder
    82  func (b *Builder) WithBind(source, target string, readonly bool) *Builder {
    83  	var flags uintptr = bind
    84  	if readonly {
    85  		flags |= unix.MS_RDONLY
    86  	}
    87  	b.Mounts = append(b.Mounts, Mount{
    88  		Source: source,
    89  		Target: target,
    90  		Flags:  flags,
    91  	})
    92  	return b
    93  }
    94  
    95  // WithTmpfs add a tmpfs mount to builder
    96  func (b *Builder) WithTmpfs(target, data string) *Builder {
    97  	b.Mounts = append(b.Mounts, Mount{
    98  		Source: "tmpfs",
    99  		Target: target,
   100  		FsType: "tmpfs",
   101  		Flags:  mFlag,
   102  		Data:   data,
   103  	})
   104  	return b
   105  }
   106  
   107  // WithProc add proc file system
   108  func (b *Builder) WithProc() *Builder {
   109  	b.Mounts = append(b.Mounts, Mount{
   110  		Source: "proc",
   111  		Target: "proc",
   112  		FsType: "proc",
   113  		Flags:  unix.MS_NOSUID | unix.MS_NODEV | unix.MS_NOEXEC | unix.MS_RDONLY,
   114  	})
   115  	return b
   116  }
   117  
   118  func (b Builder) String() string {
   119  	var sb strings.Builder
   120  	sb.WriteString("Mounts: ")
   121  	for i, m := range b.Mounts {
   122  		sb.WriteString(m.String())
   123  		if i != len(b.Mounts)-1 {
   124  			sb.WriteString(", ")
   125  		}
   126  	}
   127  	return sb.String()
   128  }