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  }