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