blob: 147710945dc22a868d5d52bd6fc9e9b962c487e5 [file] [log] [blame]
Lorenz Brunae0d90d2019-09-05 17:53:56 +02001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package main
18
19import (
20 "io/ioutil"
21 "os"
22 "os/exec"
23 "os/signal"
24 node2 "smalltown/internal/node"
25 "smalltown/internal/storage"
26 "smalltown/pkg/tpm"
27 "syscall"
28
29 "go.uber.org/zap"
30 "golang.org/x/sys/unix"
31)
32
33func main() {
34 logger, err := zap.NewDevelopment()
35 if err != nil {
36 panic(err)
37 }
38 logger.Info("Starting Smalltown Init")
39
40 // Set up bare minimum mounts
41 if err := os.Mkdir("/sys", 0755); err != nil {
42 panic(err)
43 }
44 if err := unix.Mount("sysfs", "/sys", "sysfs", unix.MS_NOEXEC|unix.MS_NOSUID|unix.MS_NODEV, ""); err != nil {
45 panic(err)
46 }
47
48 if err := os.Mkdir("/proc", 0755); err != nil {
49 panic(err)
50 }
51 if err := unix.Mount("procfs", "/proc", "proc", unix.MS_NOEXEC|unix.MS_NOSUID|unix.MS_NODEV, ""); err != nil {
52 panic(err)
53 }
54
55 signalChannel := make(chan os.Signal, 2)
56 signal.Notify(signalChannel)
57
58 if err := storage.FindPartitions(); err != nil {
59 logger.Panic("Failed to search for partitions", zap.Error(err))
60 }
61
62 if err := os.Mkdir("/esp", 0755); err != nil {
63 panic(err)
64 }
65
66 if err := unix.Mount(storage.ESPDevicePath, "/esp", "vfat", unix.MS_NOEXEC|unix.MS_NODEV|unix.MS_SYNC, ""); err != nil {
67 logger.Panic("Failed to mount ESP partition", zap.Error(err))
68 }
69
70 if err := tpm.Initialize(logger.With(zap.String("component", "tpm"))); err != nil {
71 logger.Panic("Failed to initialize TPM 2.0", zap.Error(err))
72 }
73
74 // TODO(lorenz): This really doesn't belong here and needs to be asynchronous as well
75 var keyLocation = "/esp/EFI/smalltown/data-key.bin"
76 sealedKeyFile, err := os.Open(keyLocation)
77 if os.IsNotExist(err) {
78 logger.Info("Initializing encrypted storage, this might take a while...")
79 key, err := tpm.GenerateSafeKey(256 / 8)
80 if err != nil {
81 panic(err)
82 }
83 sealedKey, err := tpm.Seal(key, tpm.SecureBootPCRs)
84 if err != nil {
85 panic(err)
86 }
87 if err := storage.InitializeEncryptedBlockDevice("data", storage.SmalltownDataCryptPath, key); err != nil {
88 panic(err)
89 }
90 mkfsCmd := exec.Command("/bin/mkfs.xfs", "-qf", "/dev/data")
91 if _, err := mkfsCmd.Output(); err != nil {
92 panic(err)
93 }
94 // Existence of this file indicates that the encrypted storage has been successfully initialized
95 if err := ioutil.WriteFile(keyLocation, sealedKey, 0600); err != nil {
96 panic(err)
97 }
98 logger.Info("Initialized encrypted storage")
99 } else if err != nil {
100 panic(err)
101 } else {
102 sealedKey, err := ioutil.ReadAll(sealedKeyFile)
103 if err != nil {
104 panic(err)
105 }
106 key, err := tpm.Unseal(sealedKey)
107 if err != nil {
108 panic(err)
109 }
110 if err := storage.MapEncryptedBlockDevice("data", storage.SmalltownDataCryptPath, key); err != nil {
111 panic(err)
112 }
113 logger.Info("Opened encrypted storage")
114 }
115 sealedKeyFile.Close()
116
117 if err := os.Mkdir("/data", 0755); err != nil {
118 panic(err)
119 }
120
121 if err := unix.Mount("/dev/data", "/data", "xfs", unix.MS_NOEXEC|unix.MS_NODEV, ""); err != nil {
122 panic(err)
123 }
124
125 node, err := node2.NewSmalltownNode(logger, "/esp/EFI/smalltown", "/data", 7833, 7834)
126 if err != nil {
127 panic(err)
128 }
129
130 err = node.Start()
131 if err != nil {
132 panic(err)
133 }
134
135 // We're PID1, so orphaned processes get reparented to us to clean up
136 for {
137 sig := <-signalChannel
138 switch sig {
139 case unix.SIGCHLD:
140 var status unix.WaitStatus
141 var rusage unix.Rusage
142 for {
143 res, err := unix.Wait4(-1, &status, syscall.WNOHANG, &rusage)
144 if err != nil {
145 logger.Error("Failed to wait on orphaned child", zap.Error(err))
146 break
147 }
148 if res <= 0 {
149 break
150 }
151 }
152 // TODO(lorenz): We can probably get more than just SIGCHLD as init, but I can't think
153 // of any others right now, just log them in case we hit any of them.
154 default:
155 logger.Warn("Got unexpected signal", zap.String("signal", sig.String()))
156 }
157 }
158}