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  }