Skip to content

Commit

Permalink
🚨WIP: Populate new base layers with real but empty hives
Browse files Browse the repository at this point in the history
Somewhere between Windows RS5 (Server LTSC 2019) and Windows 20H2, the
HCS started trying to load one of the hives in the base layer when
importing a layer that depends on it.

The observed symptom is:
> hcsshim::ImportLayer - failed failed in Win32: The configuration registry database is corrupt. (0x3f1)

WIP because at some point since I had this working in 2021, the
behaviour of `go mod vendor` changed and no longer includes the
testdata/minimal file, so that probably needs to be replaced.

Possibly, just with a HTTP pull from GitHub; the relevant file hasn't
changed in 3 years.

Signed-off-by: Paul "TBBle" Hampson <[email protected]>
  • Loading branch information
TBBle committed Aug 11, 2022
1 parent d376404 commit 035362c
Show file tree
Hide file tree
Showing 66 changed files with 13,660 additions and 8 deletions.
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/containerd/go-runc v1.0.0
github.com/containerd/ttrpc v1.1.0
github.com/containerd/typeurl v1.0.2
github.com/gabriel-samfira/go-hivex v0.0.0-20190725123041-b40bc95a7ced
github.com/gogo/protobuf v1.3.2
github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.5.6
Expand All @@ -30,6 +31,7 @@ require (
go.opencensus.io v0.22.3
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
golang.org/x/tools v0.1.5
google.golang.org/grpc v1.40.0
)

Expand All @@ -50,8 +52,10 @@ require (
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/net v0.0.0-20210825183410-e898025ed96a // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect
google.golang.org/protobuf v1.27.1 // indirect
)
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/gabriel-samfira/go-hivex v0.0.0-20190725123041-b40bc95a7ced h1:QGy2AdPMyJWF1pI/GaAxpEY0qIFn/ekrimYrucQeNNk=
github.com/gabriel-samfira/go-hivex v0.0.0-20190725123041-b40bc95a7ced/go.mod h1:2uhxVfr/8oFRFnCQbpoSzKG+qCvKH3yVt8FPASfJO28=
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
Expand Down Expand Up @@ -698,6 +700,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -878,6 +881,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
22 changes: 18 additions & 4 deletions internal/wclayer/converttobaselayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,28 @@ import (

var hiveNames = []string{"DEFAULT", "SAM", "SECURITY", "SOFTWARE", "SYSTEM"}

// Ensure the given file exists as an ordinary file, and create a zero-length file if not.
func ensureFile(path string, root *os.File) error {
//go:generate go run mkminimalhive_windows.go -output zminimalhive_windows.go

// Ensure the given file exists as an ordinary file, and create a minimal hive file if not.
func ensureHive(path string, root *os.File) error {
stat, err := safefile.LstatRelative(path, root)
if err != nil && os.IsNotExist(err) {
newFile, err := safefile.OpenRelative(path, root, 0, syscall.FILE_SHARE_WRITE, winapi.FILE_CREATE, 0)
minimalHiveBytes, err := minimalHiveContents()
if err != nil {
return err
}

newFile, err := safefile.OpenRelative(path, root, syscall.GENERIC_WRITE, syscall.FILE_SHARE_WRITE, winapi.FILE_CREATE, 0)
if err != nil {
return err
}

_, err = newFile.Write(minimalHiveBytes)
if err != nil {
newFile.Close()
return err
}

return newFile.Close()
}

Expand All @@ -48,7 +62,7 @@ func ensureBaseLayer(root *os.File) (hasUtilityVM bool, err error) {

for _, hiveName := range hiveNames {
hivePath := filepath.Join(hiveSourcePath, hiveName)
if err = ensureFile(hivePath, root); err != nil {
if err = ensureHive(hivePath, root); err != nil {
return
}
}
Expand Down
17 changes: 17 additions & 0 deletions internal/wclayer/mkminimalhive_forcegomod_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//go:build generate_but_never_actually_compile

// This exists to force the inclusion of the below package in
// go.mod and hence the vendor directory, so that
// golang.org/x/tools/go/packages.Load can read files from it.

// However, if this import statement gets pulled into an actual
// compile (i.e. by appearing in mkminimalhive_windows.go) then
// it forces both CGO and installation of the libhive library
// this package wraps.

// Per https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module
// this is the best option.

package main

import _ "github.com/gabriel-samfira/go-hivex"
90 changes: 90 additions & 0 deletions internal/wclayer/mkminimalhive_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//go:build generate

/*
mkminimalhive_windows generates a minimal hive blob function
so that we do not carry a runtime dependency on the hive source.
The generated source contains a single function, minimalHiveContents,
which returns a []byte of the desired data.
Largely based on how mksyscall_windows works.
*/

package main

import (
"encoding/base64"
"errors"
"flag"
"fmt"
"log"
"os"
"path/filepath"

"golang.org/x/tools/go/packages"
)

var (
filename = flag.String("output", "", "output file name (standard output if omitted)")
)

//readMinimalHiveContents finds the `minimal` hive binary from the package as there's no way to create this file
// Originally from https://github.com/buildpacks/imgutil/blob/main/tools/bcdhive_generator/bcdhive_hivex.go
func readMinimalHiveContents() ([]byte, error) {
pkgs, err := packages.Load(&packages.Config{}, "github.com/gabriel-samfira/go-hivex")
if err != nil {
return nil, err
}
if len(pkgs) != 1 || len(pkgs[0].GoFiles) != 1 {
return nil, errors.New("hivex module root not found")
}
hivexRootPath := filepath.Dir(pkgs[0].GoFiles[0])
minimalHivePath := filepath.Join(hivexRootPath, "testdata", "minimal")
return os.ReadFile(minimalHivePath)
}

func usage() {
fmt.Fprintf(os.Stderr, "usage: mkminimalhive_windows [flags] [path ...]\n")
flag.PrintDefaults()
os.Exit(1)
}

func main() {
flag.Usage = usage
flag.Parse()
if len(flag.Args()) != 0 {
fmt.Fprintf(os.Stderr, "unexpected filename arguments\n")
usage()
}

hiveData, err := readMinimalHiveContents()
if err != nil {
log.Fatal(err)
}

hiveBase64 := base64.StdEncoding.EncodeToString(hiveData)

source := []byte(`// Code generated by mkminimalhive_windows DO NOT EDIT.
package wclayer
import (
"encoding/base64"
)
const hiveBase64 = "` + hiveBase64 + `"
func minimalHiveContents() ([]byte, error) {
return base64.StdEncoding.DecodeString(hiveBase64)
}
`)

if *filename == "" {
_, err = os.Stdout.Write(source)
} else {
err = os.WriteFile(*filename, source, 0644)
}
if err != nil {
log.Fatal(err)
}
}
13 changes: 13 additions & 0 deletions internal/wclayer/zminimalhive_windows.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions test/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ require (
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7 // indirect
github.com/docker/docker-credential-helpers v0.6.3 // indirect
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
github.com/gabriel-samfira/go-hivex v0.0.0-20190725123041-b40bc95a7ced // indirect
github.com/gogo/googleapis v1.4.0 // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/golang/protobuf v1.5.0 // indirect
Expand All @@ -53,8 +54,11 @@ require (
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f // indirect
go.opencensus.io v0.22.3 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.5 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 // indirect
google.golang.org/protobuf v1.27.1 // indirect
)
Expand Down
Loading

0 comments on commit 035362c

Please sign in to comment.