github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/securelaunch/measurement/dmi.go (about) 1 // Copyright 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 measurement 6 7 import ( 8 "bytes" 9 "encoding/json" 10 "errors" 11 "fmt" 12 "log" 13 "strings" 14 15 slaunch "github.com/mvdan/u-root-coreutils/pkg/securelaunch" 16 "github.com/mvdan/u-root-coreutils/pkg/securelaunch/tpm" 17 "github.com/mvdan/u-root-coreutils/pkg/smbios" 18 ) 19 20 type fieldCluster struct { 21 Label string `json:"label"` 22 Fields []string `json:"fields"` 23 } 24 25 // DmiCollector describes the "dmi" portion of policy file. 26 type DmiCollector struct { 27 Type string `json:"type"` 28 Clusters []fieldCluster `json:"events"` 29 } 30 31 // NewDmiCollector extracts the "dmi" portion from the policy file and 32 // initializes a new DmiCollector structure. 33 // 34 // It returns an error if unmarshalling of DmiCollector fails. 35 func NewDmiCollector(config []byte) (Collector, error) { 36 slaunch.Debug("New DMI Collector initialized") 37 dc := new(DmiCollector) 38 err := json.Unmarshal(config, &dc) 39 if err != nil { 40 return nil, err 41 } 42 return dc, nil 43 } 44 45 // Lookup table to convert a string to a DMI type. 46 // (taken from the dmidecode man page) 47 var typeTable = map[string]uint8{ 48 "bios": 0, 49 "system": 1, 50 "base board": 2, 51 "chassis": 3, 52 "processor": 4, 53 "memory controller": 5, 54 "memory module": 6, 55 "cache": 7, 56 "port connector": 8, 57 "system slots": 9, 58 "on board devices": 10, 59 "oem strings": 11, 60 "system configuration options": 12, 61 "bios language": 13, 62 "group associations": 14, 63 "system event log": 15, 64 "physical memory array": 16, 65 "memory device": 17, 66 "32-bit memory error": 18, 67 "memory array mapped address": 19, 68 "memory device mapped address": 20, 69 "built-in pointing device": 21, 70 "portable battery": 22, 71 "system reset": 23, 72 "hardware security": 24, 73 "system power controls": 25, 74 "voltage probe": 26, 75 "cooling device": 27, 76 "temperature probe": 28, 77 "electrical current probe": 29, 78 "out-of-band remote access": 30, 79 "boot integrity services": 31, 80 "system boot": 32, 81 "64-bit memory error": 33, 82 "management device": 34, 83 "management device component": 35, 84 "management device threshold data": 36, 85 "memory channel": 37, 86 "ipmi device": 38, 87 "power supply": 39, 88 "additional information": 40, 89 "onboard device": 41, 90 } 91 92 // parseTypeFilter looks up the DMI types and sets the corresponding entries 93 // in a map to true. 94 func parseTypeFilter(typeStrings []string) (map[smbios.TableType]bool, error) { 95 types := map[smbios.TableType]bool{} 96 for _, ts := range typeStrings { 97 if tg, ok := typeTable[strings.ToLower(ts)]; ok { 98 types[smbios.TableType(tg)] = true 99 } 100 } 101 return types, nil 102 } 103 104 // Collect gets all smbios data, filters is based on the types provided in the 105 // policy file, then measures the filtered data into the TPM. 106 // 107 // It satisfies the Collector interface. 108 func (s *DmiCollector) Collect() error { 109 slaunch.Debug("DMI Collector: Entering ") 110 if s.Type != "dmi" { 111 return errors.New("invalid type passed to a DmiCollector method") 112 } 113 114 var labels []string // collect all types entered by user in one slice 115 for _, fieldCluster := range s.Clusters { 116 labels = append(labels, fieldCluster.Label) 117 } 118 119 slaunch.Debug("DMI Collector: len(labels)=%d", len(labels)) 120 121 // lables would be []{BIOS, Chassis, Processor} 122 typeFilter, err := parseTypeFilter(labels) 123 if err != nil { 124 return fmt.Errorf("invalid --type: %v", err) 125 } 126 127 slaunch.Debug("DMI Collector: len(typeFilter)=%d", len(typeFilter)) 128 129 si, err := smbios.FromSysfs() 130 if err != nil { 131 return fmt.Errorf("error parsing data: %v", err) 132 } 133 134 slaunch.Debug("DMI Collector: len(si.Tables)=%d", len(si.Tables)) 135 136 for _, t := range si.Tables { 137 if len(typeFilter) != 0 && !typeFilter[t.Type] { 138 continue 139 } 140 141 pt, err := smbios.ParseTypedTable(t) 142 if err != nil { 143 log.Printf("DMI Collector: skipping type %s, err=%v", t.Type, err) 144 continue 145 } 146 147 slaunch.Debug(pt.String()) 148 b := []byte(pt.String()) 149 eventDesc := fmt.Sprintf("DMI Collector: Measured dmi label=[%v]", t.Type) 150 if e := tpm.ExtendPCRDebug(pcr, bytes.NewReader(b), eventDesc); e != nil { 151 log.Printf("DMI Collector: err =%v", e) 152 return e // return error if any single type fails .. 153 } 154 } 155 156 return nil 157 }