diff --git a/boot-v1.go b/boot-v1.go index da33a20..9fc09c0 100644 --- a/boot-v1.go +++ b/boot-v1.go @@ -1,10 +1,10 @@ package main import ( - "fmt" "log" "os" "path/filepath" + "strconv" "strings" "syscall" "time" @@ -104,10 +104,7 @@ func applyConfig(cfgPath string, bootMounted bool) (cfg *configV1) { lowers[i] = dir - loopDev := fmt.Sprintf("/dev/loop%d", i+loopOffset) - losetup(loopDev, path) - - mount(loopDev, dir, "squashfs", layerMountFlags, "") + mountSquahfs(path, dir) } // prepare system root @@ -119,6 +116,13 @@ func applyConfig(cfgPath string, bootMounted bool) (cfg *configV1) { mount("overlay", "/system", "overlay", rootMountFlags, "lowerdir="+strings.Join(lowers, ":")+",upperdir=/changes/upperdir,workdir=/changes/workdir") + // make root rshared (default in systemd, required by Kubernetes 1.10+) + // equivalent to "mount --make-rshared /" + // see kernel's Documentation/sharedsubtree.txt (search rshared) + if err := syscall.Mount("", "/system", "", syscall.MS_SHARED|syscall.MS_REC, ""); err != nil { + fatalf("FATAL: mount --make-rshared / failed: %v", err) + } + if bootMounted { if layersInMemory { if err := syscall.Unmount("/boot", 0); err != nil { @@ -158,6 +162,37 @@ func applyConfig(cfgPath string, bootMounted bool) (cfg *configV1) { } } + // - groups + for _, group := range cfg.Groups { + log.Print("creating group ", group.Name) + + opts := make([]string, 0) + opts = append(opts /* chroot */, "/system", "groupadd", "-r") + if group.Gid != 0 { + opts = append(opts, "-g", strconv.Itoa(group.Gid)) + } + opts = append(opts, group.Name) + + run("chroot", opts...) + } + + // - user + for _, user := range cfg.Users { + log.Print("creating user ", user.Name) + + opts := make([]string, 0) + opts = append(opts /* chroot */, "/system", "useradd", "-r") + if user.Gid != 0 { + opts = append(opts, "-g", strconv.Itoa(user.Gid)) + } + if user.Uid != 0 { + opts = append(opts, "-u", strconv.Itoa(user.Uid)) + } + opts = append(opts, user.Name) + + run("chroot", opts...) + } + return } diff --git a/boot-v2.go b/boot-v2.go index 9286798..ae125b8 100644 --- a/boot-v2.go +++ b/boot-v2.go @@ -13,6 +13,9 @@ import ( func bootV2() { log.Print("-- boot v2 --") + kernelVersion := unameRelease() + log.Print("Linux version ", kernelVersion) + cfg := &config.Config{} { @@ -35,19 +38,18 @@ func bootV2() { auths = cfg.Auths // mount kernel modules - if cfg.Modules != "" { - log.Print("mount modules from ", cfg.Modules) + if cfg.Modules == "" { + log.Print("NOT mounting modules (nothing specified)") + } else { + mountSquahfs(cfg.Modules, "/modules") - err := os.MkdirAll("/modules", 0755) - if err != nil { - fatal("failed to create /modules: ", err) + modulesSourcePath := "/modules/lib/modules/" + kernelVersion + if _, err := os.Stat(modulesSourcePath); err != nil { + fatal("invalid modules dir: ", err) } - run("mount", cfg.Modules, "/modules") - loopOffset++ - - err = os.Symlink("/modules/lib/modules", "/lib/modules") - if err != nil { + os.MkdirAll("/lib/modules", 0755) + if err := os.Symlink(modulesSourcePath, "/lib/modules/"+kernelVersion); err != nil { fatal("failed to symlink modules: ", err) } } diff --git a/buildenv/Dockerfile b/buildenv/Dockerfile deleted file mode 100644 index df0dd43..0000000 --- a/buildenv/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -from golang:1.18beta2-alpine3.15 - -run apk add --update musl-dev git - -workdir /src diff --git a/go.mod b/go.mod index d7ed218..cdee25d 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,13 @@ module novit.nc/direktil/initrd require ( + github.com/freddierice/go-losetup/v2 v2.0.1 github.com/kr/pty v1.1.8 github.com/pkg/term v1.1.0 - golang.org/x/crypto v0.5.0 - golang.org/x/sys v0.4.0 - golang.org/x/term v0.4.0 - golang.zx2c4.com/wireguard/wgctrl v0.0.0-20221104135756-97bc4ad4a1cb + golang.org/x/crypto v0.16.0 + golang.org/x/sys v0.15.0 + golang.org/x/term v0.15.0 + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 novit.tech/direktil/pkg v0.0.0-20230201224712-5e39572dc50e @@ -14,15 +15,15 @@ require ( require ( github.com/cavaliergopher/cpio v1.0.1 // indirect - github.com/creack/pty v1.1.18 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/creack/pty v1.1.21 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/josharian/native v1.1.0 // indirect - github.com/mdlayher/genetlink v1.3.1 // indirect - github.com/mdlayher/netlink v1.7.1 // indirect - github.com/mdlayher/socket v0.4.0 // indirect - golang.org/x/net v0.5.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c // indirect + github.com/mdlayher/genetlink v1.3.2 // indirect + github.com/mdlayher/netlink v1.7.2 // indirect + github.com/mdlayher/socket v0.5.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb // indirect ) go 1.21 diff --git a/go.sum b/go.sum index 3e48c37..e83e170 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,14 @@ github.com/cavaliergopher/cpio v1.0.1/go.mod h1:pBdaqQjnvXxdS/6CvNDwIANIFSP0xRKI github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= +github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/freddierice/go-losetup/v2 v2.0.1 h1:wPDx/Elu9nDV8y/CvIbEDz5Xi5Zo80y4h7MKbi3XaAI= +github.com/freddierice/go-losetup/v2 v2.0.1/go.mod h1:TEyBrvlOelsPEhfWD5rutNXDmUszBXuFnwT1kIQF4J8= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -16,37 +22,58 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mdlayher/genetlink v1.3.1 h1:roBiPnual+eqtRkKX2Jb8UQN5ZPWnhDCGj/wR6Jlz2w= github.com/mdlayher/genetlink v1.3.1/go.mod h1:uaIPxkWmGk753VVIzDtROxQ8+T+dkHqOI0vB1NA9S/Q= +github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= +github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= github.com/mdlayher/netlink v1.7.1 h1:FdUaT/e33HjEXagwELR8R3/KL1Fq5x3G5jgHLp/BTmg= github.com/mdlayher/netlink v1.7.1/go.mod h1:nKO5CSjE/DJjVhk/TNp6vCE1ktVxEA8VEh8drhZzxsQ= +github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= +github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= +github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI= +github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= +github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= github.com/pkg/term v1.1.0 h1:xIAAdCMh3QIAy+5FrE8Ad8XoDhEU4ufwbaSozViP9kk= github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c h1:Okh6a1xpnJslG9Mn84pId1Mn+Q8cvpo4HCeeFWHo0cA= golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c/go.mod h1:enML0deDxY1ux+B6ANGiwtg0yAJi1rctkTpcHNAVPyg= +golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb h1:c5tyN8sSp8jSDxdCCDXVOpJwYXXhmTkNMt+g0zTSOic= +golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20221104135756-97bc4ad4a1cb h1:9aqVcYEDHmSNb0uOWukxV5lHV09WqiSiCuhEgWNETLY= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20221104135756-97bc4ad4a1cb/go.mod h1:mQqgjkW8GQQcJQsbBvK890TKqUK1DfKWkuBGbOkuMHQ= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/losetup.go b/losetup.go new file mode 100644 index 0000000..e89cc73 --- /dev/null +++ b/losetup.go @@ -0,0 +1,26 @@ +package main + +import ( + "syscall" + + "github.com/freddierice/go-losetup/v2" +) + +var loDevices = map[string]losetup.Device{} + +func losetupAttach(file string) losetup.Device { + if _, ok := loDevices[file]; !ok { + dev, err := losetup.Attach(file, 0, true) + if err != nil { + fatalf("failed to attach %q to a loop device: %v", file, err) + } + + loDevices[file] = dev + } + return loDevices[file] +} + +func mountSquahfs(source, target string) { + dev := losetupAttach(source) + mount(dev.Path(), target, "squashfs", syscall.MS_RDONLY, "") +} diff --git a/main.go b/main.go index 1f2a1b4..45464f9 100644 --- a/main.go +++ b/main.go @@ -192,10 +192,6 @@ mainLoop: } } -func losetup(dev, file string) { - run("/sbin/losetup", "-r", dev, file) -} - func run(cmd string, args ...string) { if output, err := exec.Command(cmd, args...).CombinedOutput(); err != nil { fatalf("command %s %q failed: %v\n%s", cmd, args, err, string(output)) diff --git a/modd.conf b/modd.conf index ff7e2bb..10d82c1 100644 --- a/modd.conf +++ b/modd.conf @@ -1,24 +1,13 @@ modd.conf {} -alpine/Dockerfile { - prep: docker build -t dkl-initrd alpine - prep: docker run --rm dkl-initrd | base64 -d >dist/base-initrd -} - -buildenv/Dockerfile { - prep: docker build -t dkl-initrd-build buildenv -} - go.??? **/*.go { prep: go test ./... prep: mkdir -p dist prep: go build -o dist/ ./tools/... - - prep: mkdir -p tmp/go tmp/.cache - prep: docker run --rm -v novit-go:/go -e GOCACHE=/go/.cache -v $PWD:/src -u $(id -u):$(id -g) dkl-initrd-build go build -o dist/init . } -dist/init dist/base-initrd { - prep: cd dist && ../dist/cpiocat init initrd.new +dist/init Dockerfile { + prep: docker build -t novit-initrd-gen . + prep: docker run novit-initrd-gen |base64 -d >dist/initrd.new prep: mv dist/initrd.new dist/initrd } diff --git a/uname.go b/uname.go new file mode 100644 index 0000000..8213dba --- /dev/null +++ b/uname.go @@ -0,0 +1,20 @@ +package main + +import "syscall" + +func unameRelease() string { + uname := &syscall.Utsname{} + if err := syscall.Uname(uname); err != nil { + fatalf("failed to get kernel version: %v", err) + } + + ba := make([]byte, 0, len(uname.Release)) + for _, c := range uname.Release { + if c == 0 { + break + } + ba = append(ba, byte(c)) + } + + return string(ba) +}