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

// 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
}