Skip to content

Commit 1803a21

Browse files
committed
Populate new base layers with real but empty hives
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) Signed-off-by: Paul "TBBle" Hampson <[email protected]>
1 parent 7a7edb2 commit 1803a21

133 files changed

Lines changed: 27320 additions & 8 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ require (
1212
github.com/containerd/go-runc v1.0.0
1313
github.com/containerd/ttrpc v1.1.0
1414
github.com/containerd/typeurl v1.0.2
15+
github.com/gabriel-samfira/go-hivex v0.0.0-20190725123041-b40bc95a7ced
1516
github.com/gogo/protobuf v1.3.2
1617
github.com/golang/mock v1.6.0
1718
github.com/google/go-cmp v0.5.6
@@ -31,6 +32,7 @@ require (
3132
golang.org/x/net v0.0.0-20210825183410-e898025ed96a // indirect
3233
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
3334
golang.org/x/sys v0.0.0-20210510120138-977fb7262007
35+
golang.org/x/tools v0.1.1
3436
google.golang.org/grpc v1.40.0
3537
)
3638

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM
264264
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
265265
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
266266
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
267+
github.com/gabriel-samfira/go-hivex v0.0.0-20190725123041-b40bc95a7ced h1:QGy2AdPMyJWF1pI/GaAxpEY0qIFn/ekrimYrucQeNNk=
268+
github.com/gabriel-samfira/go-hivex v0.0.0-20190725123041-b40bc95a7ced/go.mod h1:2uhxVfr/8oFRFnCQbpoSzKG+qCvKH3yVt8FPASfJO28=
267269
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
268270
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
269271
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -694,6 +696,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
694696
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
695697
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
696698
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
699+
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
697700
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
698701
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
699702
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -872,6 +875,7 @@ golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roY
872875
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
873876
golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
874877
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
878+
golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=
875879
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
876880
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
877881
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

internal/wclayer/converttobaselayer.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,28 @@ import (
1616

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

19-
// Ensure the given file exists as an ordinary file, and create a zero-length file if not.
20-
func ensureFile(path string, root *os.File) error {
19+
//go:generate go run mkminimalhive_windows.go -output zminimalhive_windows.go
20+
21+
// Ensure the given file exists as an ordinary file, and create a minimal hive file if not.
22+
func ensureHive(path string, root *os.File) error {
2123
stat, err := safefile.LstatRelative(path, root)
2224
if err != nil && os.IsNotExist(err) {
23-
newFile, err := safefile.OpenRelative(path, root, 0, syscall.FILE_SHARE_WRITE, winapi.FILE_CREATE, 0)
25+
minimalHiveBytes, err := minimalHiveContents()
26+
if err != nil {
27+
return err
28+
}
29+
30+
newFile, err := safefile.OpenRelative(path, root, syscall.GENERIC_WRITE, syscall.FILE_SHARE_WRITE, winapi.FILE_CREATE, 0)
2431
if err != nil {
2532
return err
2633
}
34+
35+
_, err = newFile.Write(minimalHiveBytes)
36+
if err != nil {
37+
newFile.Close()
38+
return err
39+
}
40+
2741
return newFile.Close()
2842
}
2943

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

4963
for _, hiveName := range hiveNames {
5064
hivePath := filepath.Join(hiveSourcePath, hiveName)
51-
if err = ensureFile(hivePath, root); err != nil {
65+
if err = ensureHive(hivePath, root); err != nil {
5266
return
5367
}
5468
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// +build generate_but_never_actually_compile
2+
3+
// This exists to force the inclusion of the below package in
4+
// go.mod and hence the vendor directory, so that
5+
// golang.org/x/tools/go/packages.Load can read files from it.
6+
7+
// However, if this import statement gets pulled into an actual
8+
// compile (i.e. by appearing in mkminimalhive_windows.go) then
9+
// it forces both CGO and installation of the libhive library
10+
// this package wraps.
11+
12+
// Per https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module
13+
// this is the best option.
14+
15+
package main
16+
17+
import _ "github.com/gabriel-samfira/go-hivex"
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// +build generate
2+
3+
/*
4+
mkminimalhive_windows generates a minimal hive blob function
5+
so that we do not carry a runtime dependency on the hive source.
6+
7+
The generated source contains a single function, minimalHiveContents,
8+
which returns a []byte of the desired data.
9+
10+
Largely based on how mksyscall_windows works.
11+
*/
12+
13+
package main
14+
15+
import (
16+
"encoding/base64"
17+
"errors"
18+
"flag"
19+
"fmt"
20+
"io/ioutil"
21+
"log"
22+
"os"
23+
"path/filepath"
24+
25+
"golang.org/x/tools/go/packages"
26+
)
27+
28+
var (
29+
filename = flag.String("output", "", "output file name (standard output if omitted)")
30+
)
31+
32+
//readMinimalHiveContents finds the `minimal` hive binary from the package as there's no way to create this file
33+
// Originally from https://github.com/buildpacks/imgutil/blob/main/tools/bcdhive_generator/bcdhive_hivex.go
34+
func readMinimalHiveContents() ([]byte, error) {
35+
pkgs, err := packages.Load(&packages.Config{}, "github.com/gabriel-samfira/go-hivex")
36+
if err != nil {
37+
return nil, err
38+
}
39+
if len(pkgs) != 1 || len(pkgs[0].GoFiles) != 1 {
40+
return nil, errors.New("hivex module root not found")
41+
}
42+
hivexRootPath := filepath.Dir(pkgs[0].GoFiles[0])
43+
minimalHivePath := filepath.Join(hivexRootPath, "testdata", "minimal")
44+
return ioutil.ReadFile(minimalHivePath)
45+
}
46+
47+
func usage() {
48+
fmt.Fprintf(os.Stderr, "usage: mkminimalhive_windows [flags] [path ...]\n")
49+
flag.PrintDefaults()
50+
os.Exit(1)
51+
}
52+
53+
func main() {
54+
flag.Usage = usage
55+
flag.Parse()
56+
if len(flag.Args()) != 0 {
57+
fmt.Fprintf(os.Stderr, "unexpected filename arguments\n")
58+
usage()
59+
}
60+
61+
hiveData, err := readMinimalHiveContents()
62+
if err != nil {
63+
log.Fatal(err)
64+
}
65+
66+
hiveBase64 := base64.StdEncoding.EncodeToString(hiveData)
67+
68+
source := []byte(`// Code generated by mkminimalhive_windows DO NOT EDIT.
69+
70+
package wclayer
71+
72+
import (
73+
"encoding/base64"
74+
)
75+
76+
const hiveBase64 = "` + hiveBase64 + `"
77+
78+
func minimalHiveContents() ([]byte, error) {
79+
return base64.StdEncoding.DecodeString(hiveBase64)
80+
}
81+
`)
82+
83+
if *filename == "" {
84+
_, err = os.Stdout.Write(source)
85+
} else {
86+
err = ioutil.WriteFile(*filename, source, 0644)
87+
}
88+
if err != nil {
89+
log.Fatal(err)
90+
}
91+
}

internal/wclayer/zminimalhive_windows.go

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)