You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
79 lines
2.6 KiB
79 lines
2.6 KiB
// tera-initramfs-tool creates a deterministic, minimal newc+gzip initramfs.
|
|
// The supplied static executable becomes PID 1; no shell or shared libraries
|
|
// are added to the recovery trust boundary.
|
|
package main
|
|
|
|
import (
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
func main() {
|
|
flags := flag.NewFlagSet("tera-initramfs-tool", flag.ExitOnError)
|
|
initPath := flags.String("init", "", "static Linux arm64 recovery init binary")
|
|
output := flags.String("output", "", "new .cpio.gz output path")
|
|
var trustAnchors stringList
|
|
flags.Var(&trustAnchors, "trust-anchor", "public update trust-anchor JSON to include (repeatable)")
|
|
flags.Parse(os.Args[1:])
|
|
if err := runWithTrustAnchors(*initPath, *output, trustAnchors); err != nil {
|
|
fmt.Fprintln(os.Stderr, "tera-initramfs-tool:", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
type stringList []string
|
|
|
|
func (values *stringList) String() string { return fmt.Sprint([]string(*values)) }
|
|
|
|
func (values *stringList) Set(value string) error {
|
|
*values = append(*values, value)
|
|
return nil
|
|
}
|
|
|
|
func run(initPath, output string) error {
|
|
return runWithTrustAnchors(initPath, output, nil)
|
|
}
|
|
|
|
func runWithTrustAnchors(initPath, output string, trustAnchors []string) error {
|
|
if initPath == "" || output == "" {
|
|
return errors.New("init and output are required")
|
|
}
|
|
info, err := os.Lstat(initPath)
|
|
if err != nil || !info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 {
|
|
return errors.New("init must be a regular non-symlink file")
|
|
}
|
|
initBinary, err := os.ReadFile(initPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
extra := make([]archiveEntry, 0, len(trustAnchors))
|
|
seen := make(map[string]struct{}, len(trustAnchors))
|
|
for _, trustPath := range trustAnchors {
|
|
info, err := os.Lstat(trustPath)
|
|
if err != nil || !info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 || info.Size() <= 0 || info.Size() > 64*1024 {
|
|
return errors.New("trust anchor must be a non-empty regular non-symlink JSON file no larger than 64 KiB")
|
|
}
|
|
name := filepath.Base(trustPath)
|
|
if filepath.Ext(name) != ".json" || name == ".json" || strings.ContainsAny(name, "/\\") {
|
|
return errors.New("trust anchor must have a safe JSON basename")
|
|
}
|
|
if _, duplicate := seen[name]; duplicate {
|
|
return errors.New("duplicate trust-anchor basename")
|
|
}
|
|
data, err := os.ReadFile(trustPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
seen[name] = struct{}{}
|
|
extra = append(extra, archiveEntry{name: "etc/tera/update-trust/" + name, mode: 0o100444, data: data})
|
|
}
|
|
if err := writeInitramfsWithEntries(output, initBinary, extra); err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("created minimal recovery initramfs: %s\n", output)
|
|
return nil
|
|
}
|
|
|