github.com/system-transparency/u-root@v6.0.1-0.20190919065413-ed07a650de4c+incompatible/pkg/uroot/util/root_linux.go (about)

     1  // Copyright 2014-2017 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package util contains various u-root utility functions.
     6  package util
     7  
     8  import (
     9  	"fmt"
    10  	"io/ioutil"
    11  	"log"
    12  	"os"
    13  	"runtime"
    14  	"strconv"
    15  	"strings"
    16  	"syscall"
    17  
    18  	"github.com/u-root/u-root/pkg/cmdline"
    19  	"golang.org/x/sys/unix"
    20  )
    21  
    22  const (
    23  	// Not all these paths may be populated or even exist but OTOH they might.
    24  	PATHHEAD = "/ubin"
    25  	PATHMID  = "/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin"
    26  	PATHTAIL = "/buildbin:/bbin"
    27  )
    28  
    29  type Creator interface {
    30  	Create() error
    31  	fmt.Stringer
    32  }
    33  
    34  type Dir struct {
    35  	Name string
    36  	Mode os.FileMode
    37  }
    38  
    39  func (d Dir) Create() error {
    40  	return os.MkdirAll(d.Name, d.Mode)
    41  }
    42  
    43  func (d Dir) String() string {
    44  	return fmt.Sprintf("dir %q (mode %#o)", d.Name, d.Mode)
    45  }
    46  
    47  type File struct {
    48  	Name     string
    49  	Contents string
    50  	Mode     os.FileMode
    51  }
    52  
    53  func (f File) Create() error {
    54  	return ioutil.WriteFile(f.Name, []byte(f.Contents), f.Mode)
    55  }
    56  
    57  func (f File) String() string {
    58  	return fmt.Sprintf("file %q (mode %#o)", f.Name, f.Mode)
    59  }
    60  
    61  type Symlink struct {
    62  	Target  string
    63  	NewPath string
    64  }
    65  
    66  func (s Symlink) Create() error {
    67  	os.Remove(s.NewPath)
    68  	return os.Symlink(s.Target, s.NewPath)
    69  }
    70  
    71  func (s Symlink) String() string {
    72  	return fmt.Sprintf("symlink %q -> %q", s.NewPath, s.Target)
    73  }
    74  
    75  type Link struct {
    76  	OldPath string
    77  	NewPath string
    78  }
    79  
    80  func (s Link) Create() error {
    81  	os.Remove(s.NewPath)
    82  	return os.Link(s.OldPath, s.NewPath)
    83  }
    84  
    85  func (s Link) String() string {
    86  	return fmt.Sprintf("link %q -> %q", s.NewPath, s.OldPath)
    87  }
    88  
    89  type Dev struct {
    90  	Name string
    91  	Mode uint32
    92  	Dev  int
    93  }
    94  
    95  func (d Dev) Create() error {
    96  	os.Remove(d.Name)
    97  	return syscall.Mknod(d.Name, d.Mode, d.Dev)
    98  }
    99  
   100  func (d Dev) String() string {
   101  	return fmt.Sprintf("dev %q (mode %#o; magic %d)", d.Name, d.Mode, d.Dev)
   102  }
   103  
   104  type Mount struct {
   105  	Source string
   106  	Target string
   107  	FSType string
   108  	Flags  uintptr
   109  	Opts   string
   110  }
   111  
   112  func (m Mount) Create() error {
   113  	return syscall.Mount(m.Source, m.Target, m.FSType, m.Flags, m.Opts)
   114  }
   115  
   116  func (m Mount) String() string {
   117  	return fmt.Sprintf("mount -t %q -o %s %q %q flags %#x", m.FSType, m.Opts, m.Source, m.Target, m.Flags)
   118  }
   119  
   120  var (
   121  	namespace = []Creator{
   122  		Dir{Name: "/buildbin", Mode: 0777},
   123  		Dir{Name: "/ubin", Mode: 0777},
   124  		Dir{Name: "/tmp", Mode: 0777},
   125  		Dir{Name: "/env", Mode: 0777},
   126  		Dir{Name: "/tcz", Mode: 0777},
   127  		Dir{Name: "/lib", Mode: 0777},
   128  		Dir{Name: "/usr/lib", Mode: 0777},
   129  		Dir{Name: "/var/log", Mode: 0777},
   130  		Dir{Name: "/go/pkg/linux_amd64", Mode: 0777},
   131  
   132  		Dir{Name: "/etc", Mode: 0777},
   133  
   134  		Dir{Name: "/proc", Mode: 0555},
   135  		Mount{Source: "proc", Target: "/proc", FSType: "proc"},
   136  		Mount{Source: "tmpfs", Target: "/tmp", FSType: "tmpfs"},
   137  
   138  		Dir{Name: "/dev", Mode: 0777},
   139  		Dev{Name: "/dev/tty", Mode: syscall.S_IFCHR | 0666, Dev: 0x0500},
   140  		Dev{Name: "/dev/urandom", Mode: syscall.S_IFCHR | 0444, Dev: 0x0109},
   141  		Dev{Name: "/dev/port", Mode: syscall.S_IFCHR | 0640, Dev: 0x0104},
   142  
   143  		// Kernel must be compiled with CONFIG_DEVTMPFS.
   144  		// Note that things kind of work even if this mount fails.
   145  		// TODO: move the Dir commands above below this line?
   146  		Mount{Source: "devtmpfs", Target: "/dev", FSType: "devtmpfs"},
   147  
   148  		Dir{Name: "/dev/pts", Mode: 0777},
   149  		Mount{Source: "devpts", Target: "/dev/pts", FSType: "devpts", Opts: "newinstance,ptmxmode=666,gid=5,mode=620"},
   150  		Dev{Name: "/dev/ptmx", Mode: syscall.S_IFCHR | 0666, Dev: 0x0502},
   151  		// Note: shm is required at least for Chrome. If you don't mount
   152  		// it chrome throws a bogus "out of memory" error, not the more
   153  		// useful "I can't open /dev/shm/whatever". SAD!
   154  		Dir{Name: "/dev/shm", Mode: 0777},
   155  		Mount{Source: "tmpfs", Target: "/dev/shm", FSType: "tmpfs"},
   156  
   157  		Dir{Name: "/sys", Mode: 0555},
   158  		Mount{Source: "sysfs", Target: "/sys", FSType: "sysfs"},
   159  		Mount{Source: "securityfs", Target: "/sys/kernel/security", FSType: "securityfs"},
   160  	}
   161  	cgroupsnamespace = []Creator{
   162  		Mount{Source: "cgroup", Target: "/sys/fs/cgroup", FSType: "tmpfs"},
   163  		Dir{Name: "/sys/fs/cgroup/memory", Mode: 0555},
   164  		Dir{Name: "/sys/fs/cgroup/freezer", Mode: 0555},
   165  		Dir{Name: "/sys/fs/cgroup/devices", Mode: 0555},
   166  		Dir{Name: "/sys/fs/cgroup/cpu,cpuacct", Mode: 0555},
   167  		Dir{Name: "/sys/fs/cgroup/blkio", Mode: 0555},
   168  		Dir{Name: "/sys/fs/cgroup/cpuset", Mode: 0555},
   169  		Dir{Name: "/sys/fs/cgroup/pids", Mode: 0555},
   170  		Dir{Name: "/sys/fs/cgroup/net_cls,net_prio", Mode: 0555},
   171  		Dir{Name: "/sys/fs/cgroup/hugetlb", Mode: 0555},
   172  		Dir{Name: "/sys/fs/cgroup/perf_event", Mode: 0555},
   173  		Symlink{NewPath: "/sys/fs/cgroup/cpu", Target: "/sys/fs/cgroup/cpu,cpuacct"},
   174  		Symlink{NewPath: "/sys/fs/cgroup/cpuacct", Target: "/sys/fs/cgroup/cpu,cpuacct"},
   175  		Symlink{NewPath: "/sys/fs/cgroup/net_cls", Target: "/sys/fs/cgroup/net_cls,net_prio"},
   176  		Symlink{NewPath: "/sys/fs/cgroup/net_prio", Target: "/sys/fs/cgroup/net_cls,net_prio"},
   177  		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/memory", FSType: "cgroup", Opts: "memory"},
   178  		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/freezer", FSType: "cgroup", Opts: "freezer"},
   179  		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/devices", FSType: "cgroup", Opts: "devices"},
   180  		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpu,cpuacct", FSType: "cgroup", Opts: "cpu,cpuacct"},
   181  		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/blkio", FSType: "cgroup", Opts: "blkio"},
   182  		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpuset", FSType: "cgroup", Opts: "cpuset"},
   183  		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/pids", FSType: "cgroup", Opts: "pids"},
   184  		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/net_cls,net_prio", FSType: "cgroup", Opts: "net_cls,net_prio"},
   185  		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/hugetlb", FSType: "cgroup", Opts: "hugetlb"},
   186  		Mount{Source: "cgroup", Target: "/sys/fs/cgroup/perf_event", FSType: "cgroup", Opts: "perf_event"},
   187  	}
   188  
   189  	Env = map[string]string{
   190  		"LD_LIBRARY_PATH": "/usr/local/lib",
   191  		"GOROOT":          "/go",
   192  		"GOPATH":          "/",
   193  		"GOBIN":           "/ubin",
   194  		"CGO_ENABLED":     "0",
   195  	}
   196  )
   197  
   198  func GoBin() string {
   199  	return fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s", runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH)
   200  }
   201  
   202  func create(namespace []Creator) {
   203  	// Clear umask bits so that we get stuff like ptmx right.
   204  	m := unix.Umask(0)
   205  	defer unix.Umask(m)
   206  	for _, c := range namespace {
   207  		if err := c.Create(); err != nil {
   208  			log.Printf("Error creating %s: %v", c, err)
   209  		} else {
   210  			log.Printf("Created %v", c)
   211  		}
   212  	}
   213  }
   214  
   215  // build the root file system.
   216  func Rootfs() {
   217  	Env["PATH"] = fmt.Sprintf("%v:%v:%v:%v", GoBin(), PATHHEAD, PATHMID, PATHTAIL)
   218  	for k, v := range Env {
   219  		os.Setenv(k, v)
   220  	}
   221  	create(namespace)
   222  
   223  	// systemd gets upset when it discovers something has already setup cgroups
   224  	// We have to do this after the base namespace is created, so we have /proc
   225  	initFlags := cmdline.GetInitFlagMap()
   226  	systemd, present := initFlags["systemd"]
   227  	systemdEnabled, boolErr := strconv.ParseBool(systemd)
   228  	if !present || boolErr != nil || systemdEnabled == false {
   229  		create(cgroupsnamespace)
   230  	}
   231  
   232  }
   233  
   234  // FindFileSystem returns nil if a file system is installed.
   235  // It rereads /proc/filesystems each time as the supported file systems can change
   236  // as modules are added and removed.
   237  func FindFileSystem(fs string) error {
   238  	b, err := ioutil.ReadFile("/proc/filesystems")
   239  	if err != nil {
   240  		return err
   241  	}
   242  	for _, l := range strings.Split(string(b), "\n") {
   243  		f := strings.Fields(l)
   244  		if (len(f) > 1 && f[0] == "nodev" && f[1] == fs) || (len(f) > 0 && f[0] != "nodev" && f[0] == fs) {
   245  			return nil
   246  		}
   247  	}
   248  	return fmt.Errorf("%s not found", fs)
   249  }