github.com/system-transparency/u-root@v6.0.1-0.20190919065413-ed07a650de4c+incompatible/pkg/bootconfig/bootconfig.go (about) 1 // Copyright 2017-2019 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package bootconfig 6 7 import ( 8 "encoding/json" 9 "errors" 10 "fmt" 11 "log" 12 "os" 13 14 "github.com/u-root/u-root/pkg/crypto" 15 "github.com/u-root/u-root/pkg/kexec" 16 "github.com/u-root/u-root/pkg/multiboot" 17 ) 18 19 // BootConfig is a general-purpose boot configuration. It draws some 20 // characteristics from FIT but it's not compatible with it. It uses 21 // JSON for interoperability. 22 type BootConfig struct { 23 Name string `json:"name,omitempty"` 24 Kernel string `json:"kernel"` 25 Initramfs string `json:"initramfs,omitempty"` 26 KernelArgs string `json:"kernel_args,omitempty"` 27 DeviceTree string `json:"devicetree,omitempty"` 28 Multiboot string `json:"multiboot_kernel,omitempty"` 29 MultibootArgs string `json:"multiboot_args,omitempty"` 30 Modules []string `json:"multiboot_modules,omitempty"` 31 } 32 33 // IsValid returns true if a BootConfig object has valid content, and false 34 // otherwise 35 func (bc *BootConfig) IsValid() bool { 36 return (bc.Kernel != "" && bc.Multiboot == "") || (bc.Kernel == "" && bc.Multiboot != "") 37 } 38 39 // FileNames returns a slice of all filenames in the bootconfig. 40 func (bc *BootConfig) fileNames() []string { 41 str := make([]string, 0) 42 str = append(str, bc.Kernel) 43 str = append(str, bc.Initramfs) 44 for _, module := range bc.Modules { 45 str = append(str, module) 46 } 47 return str 48 } 49 50 func (bc *BootConfig) bytestream() []byte { 51 b := bc.Name + bc.Kernel + bc.Initramfs + bc.KernelArgs + bc.DeviceTree + bc.Multiboot + bc.MultibootArgs 52 for _, module := range bc.Modules { 53 b = b + module 54 } 55 return []byte(b) 56 } 57 58 // Boot tries to boot the kernel with optional initramfs and command line 59 // options. If a device-tree is specified, that will be used too 60 func (bc *BootConfig) Boot() error { 61 crypto.TryMeasureData(crypto.BootConfigPCR, bc.bytestream(), "bootconfig") 62 crypto.TryMeasureFiles(bc.fileNames()...) 63 if bc.Kernel != "" { 64 kernel, err := os.Open(bc.Kernel) 65 if err != nil { 66 return err 67 } 68 var initramfs *os.File 69 if bc.Initramfs != "" { 70 initramfs, err = os.Open(bc.Initramfs) 71 if err != nil { 72 return err 73 } 74 } 75 defer func() { 76 // clean up 77 if kernel != nil { 78 if err := kernel.Close(); err != nil { 79 log.Printf("Error closing kernel file descriptor: %v", err) 80 } 81 } 82 if initramfs != nil { 83 if err := initramfs.Close(); err != nil { 84 log.Printf("Error closing initramfs file descriptor: %v", err) 85 } 86 } 87 }() 88 if err := kexec.FileLoad(kernel, initramfs, bc.KernelArgs); err != nil { 89 return err 90 } 91 } else if bc.Multiboot != "" { 92 // check multiboot header 93 if err := multiboot.Probe(bc.Multiboot); err != nil { 94 log.Printf("Error parsing multiboot header: %v", err) 95 return err 96 } 97 if err := multiboot.Load(true, bc.Multiboot, bc.MultibootArgs, bc.Modules, nil); err != nil { 98 return fmt.Errorf("kexec.Load() error: %v", err) 99 } 100 } 101 err := kexec.Reboot() 102 if err == nil { 103 return errors.New("Unexpectedly returned from Reboot() without error. The system did not reboot") 104 } 105 return err 106 } 107 108 // NewBootConfig parses a boot configuration in JSON format and returns a 109 // BootConfig object. 110 func NewBootConfig(data []byte) (*BootConfig, error) { 111 var bootconfig BootConfig 112 if err := json.Unmarshal(data, &bootconfig); err != nil { 113 return nil, err 114 } 115 return &bootconfig, nil 116 }