talm

Форк
0
/
switchroot.go 
170 строк · 4.0 Кб
1
// This Source Code Form is subject to the terms of the Mozilla Public
2
// License, v. 2.0. If a copy of the MPL was not distributed with this
3
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4

5
package switchroot
6

7
import (
8
	"fmt"
9
	"log"
10
	"os"
11
	"path/filepath"
12

13
	"github.com/siderolabs/go-debug"
14
	"golang.org/x/sys/unix"
15

16
	"github.com/aenix-io/talm/internal/pkg/mount"
17
	"github.com/aenix-io/talm/internal/pkg/secureboot"
18
	"github.com/aenix-io/talm/internal/pkg/secureboot/tpm2"
19
	"github.com/siderolabs/talos/pkg/machinery/constants"
20
)
21

22
// Paths preserved in the initramfs.
23
var preservedPaths = map[string]struct{}{
24
	constants.ExtensionsConfigFile:    {},
25
	constants.FirmwarePath:            {},
26
	constants.SDStubDynamicInitrdPath: {},
27
}
28

29
// Switch moves the rootfs to a specified directory. See
30
// https://github.com/karelzak/util-linux/blob/master/sys-utils/switch_root.c.
31
func Switch(prefix string, mountpoints *mount.Points) (err error) {
32
	log.Println("moving mounts to the new rootfs")
33

34
	if err = mount.Move(mountpoints, prefix); err != nil {
35
		return err
36
	}
37

38
	log.Printf("changing working directory into %s", prefix)
39

40
	if err = unix.Chdir(prefix); err != nil {
41
		return fmt.Errorf("error changing working directory to %s: %w", prefix, err)
42
	}
43

44
	var old *os.File
45

46
	if old, err = os.Open("/"); err != nil {
47
		return fmt.Errorf("error opening /: %w", err)
48
	}
49

50
	//nolint:errcheck
51
	defer old.Close()
52

53
	log.Printf("moving %s to /", prefix)
54

55
	if err = unix.Mount(prefix, "/", "", unix.MS_MOVE, ""); err != nil {
56
		return fmt.Errorf("error moving /: %w", err)
57
	}
58

59
	log.Println("changing root directory")
60

61
	if err = unix.Chroot("."); err != nil {
62
		return fmt.Errorf("error chroot: %w", err)
63
	}
64

65
	log.Println("cleaning up initramfs")
66

67
	if _, err = recursiveDelete(int(old.Fd()), "/"); err != nil {
68
		return fmt.Errorf("error deleting initramfs: %w", err)
69
	}
70

71
	// extend PCR 11 with leave-initrd
72
	if err = tpm2.PCRExtent(secureboot.UKIPCR, []byte(secureboot.LeaveInitrd)); err != nil {
73
		return fmt.Errorf("failed to extend PCR %d with leave-initrd: %v", secureboot.UKIPCR, err)
74
	}
75

76
	// Note that /sbin/init is machined. We call it init since this is the
77
	// convention.
78
	log.Println("executing /sbin/init")
79

80
	envv := []string{
81
		constants.TcellMinimizeEnvironment,
82
	}
83

84
	if debug.RaceEnabled {
85
		envv = append(envv, "GORACE=halt_on_error=1")
86

87
		log.Printf("race detection enabled with halt_on_error=1")
88
	}
89

90
	if err = unix.Exec("/sbin/init", []string{"/sbin/init"}, envv); err != nil {
91
		return fmt.Errorf("error executing /sbin/init: %w", err)
92
	}
93

94
	return nil
95
}
96

97
func recursiveDelete(fd int, path string) (preserved bool, err error) {
98
	parentDev, err := getDev(fd)
99
	if err != nil {
100
		return false, err
101
	}
102

103
	dir := os.NewFile(uintptr(fd), "__ignored__")
104
	//nolint:errcheck
105
	defer dir.Close()
106

107
	names, err := dir.Readdirnames(-1)
108
	if err != nil {
109
		return false, err
110
	}
111

112
	preserved = false
113

114
	for _, name := range names {
115
		p, err := recusiveDeleteInner(fd, parentDev, name, filepath.Join(path, name))
116
		if err != nil {
117
			return false, err
118
		}
119

120
		preserved = preserved || p
121
	}
122

123
	return preserved, nil
124
}
125

126
func recusiveDeleteInner(parentFd int, parentDev uint64, childName, path string) (preserved bool, err error) {
127
	if _, preserved = preservedPaths[path]; preserved {
128
		return preserved, nil
129
	}
130

131
	childFd, err := unix.Openat(parentFd, childName, unix.O_DIRECTORY|unix.O_NOFOLLOW, unix.O_RDWR)
132
	if err != nil {
133
		return false, unix.Unlinkat(parentFd, childName, 0)
134
	}
135

136
	//nolint:errcheck
137
	defer unix.Close(childFd)
138

139
	var childFdDev uint64
140

141
	if childFdDev, err = getDev(childFd); err != nil {
142
		return false, err
143
	} else if childFdDev != parentDev {
144
		return false, nil
145
	}
146

147
	preserved, err = recursiveDelete(childFd, path)
148
	if err != nil {
149
		return false, err
150
	}
151

152
	if preserved {
153
		// some child paths got preserved, skip unlinking the parent
154
		return preserved, nil
155
	}
156

157
	err = unix.Unlinkat(parentFd, childName, unix.AT_REMOVEDIR)
158

159
	return false, err
160
}
161

162
func getDev(fd int) (dev uint64, err error) {
163
	var stat unix.Stat_t
164

165
	if err := unix.Fstat(fd, &stat); err != nil {
166
		return 0, err
167
	}
168

169
	return stat.Dev, nil
170
}
171

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.