github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/securelaunch/measurement/cpuid.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  	"fmt"
    11  	"log"
    12  	"strings"
    13  
    14  	"github.com/intel-go/cpuid"
    15  	slaunch "github.com/mvdan/u-root-coreutils/pkg/securelaunch"
    16  	"github.com/mvdan/u-root-coreutils/pkg/securelaunch/tpm"
    17  )
    18  
    19  const defaultCPUIDFile = "cpuid.txt"
    20  
    21  // CPUIDCollector describes the "cpuid" portion of the policy file.
    22  type CPUIDCollector struct {
    23  	Type     string `json:"type"`
    24  	Location string `json:"location"`
    25  }
    26  
    27  // NewCPUIDCollector extracts the "cpuid" portion from the policy file and
    28  // initializes a new CPUIDCollector structure.
    29  //
    30  // An error is returned if unmarshalling of CPUIDCollector fails.
    31  func NewCPUIDCollector(config []byte) (Collector, error) {
    32  	slaunch.Debug("New CPUID Collector initialized\n")
    33  	fc := new(CPUIDCollector)
    34  	err := json.Unmarshal(config, &fc)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	return fc, nil
    39  }
    40  
    41  // getCPUIDInfo uses a string builder to store data obtained from the
    42  // intel-go/cpuid package.
    43  //
    44  // It returns a byte slice of the string built.
    45  func getCPUIDInfo() []byte {
    46  	var w strings.Builder
    47  	fmt.Fprintf(&w, "VendorString:           %s\n", cpuid.VendorIdentificatorString)
    48  	fmt.Fprintf(&w, "ProcessorBrandString:   %s\n", cpuid.ProcessorBrandString)
    49  	fmt.Fprintf(&w, "SteppingId:     %d\n", cpuid.SteppingId)
    50  	fmt.Fprintf(&w, "ProcessorType:  %d\n", cpuid.ProcessorType)
    51  	fmt.Fprintf(&w, "DisplayFamily:  %d\n", cpuid.DisplayFamily)
    52  	fmt.Fprintf(&w, "DisplayModel:   %d\n", cpuid.DisplayModel)
    53  	fmt.Fprintf(&w, "CacheLineSize:  %d\n", cpuid.CacheLineSize)
    54  	fmt.Fprintf(&w, "MaxLogocalCPUId:%d\n", cpuid.MaxLogicalCPUId)
    55  	fmt.Fprintf(&w, "InitialAPICId:  %d\n", cpuid.InitialAPICId)
    56  	fmt.Fprintf(&w, "Smallest monitor-line size in bytes:  %d\n", cpuid.MonLineSizeMin)
    57  	fmt.Fprintf(&w, "Largest monitor-line size in bytes:   %d\n", cpuid.MonLineSizeMax)
    58  	fmt.Fprintf(&w, "Monitor Interrupt break-event is supported:  %v\n", cpuid.MonitorIBE)
    59  	fmt.Fprintf(&w, "MONITOR/MWAIT extensions are supported:      %v\n", cpuid.MonitorEMX)
    60  	fmt.Fprintf(&w, "AVX state:     %v\n", cpuid.EnabledAVX)
    61  	fmt.Fprintf(&w, "AVX-512 state: %v\n", cpuid.EnabledAVX512)
    62  	fmt.Fprintf(&w, "Interrupt thresholds in digital thermal sensor: %v\n", cpuid.ThermalSensorInterruptThresholds)
    63  
    64  	fmt.Fprintf(&w, "Features: ")
    65  	for i := uint64(0); i < 64; i++ {
    66  		if cpuid.HasFeature(1 << i) {
    67  			fmt.Fprintf(&w, "%s ", cpuid.FeatureNames[1<<i])
    68  		}
    69  	}
    70  	fmt.Fprintf(&w, "\n")
    71  
    72  	fmt.Fprintf(&w, "ExtendedFeatures: ")
    73  	for i := uint64(0); i < 64; i++ {
    74  		if cpuid.HasExtendedFeature(1 << i) {
    75  			fmt.Fprintf(&w, "%s ", cpuid.ExtendedFeatureNames[1<<i])
    76  		}
    77  	}
    78  	fmt.Fprintf(&w, "\n")
    79  
    80  	fmt.Fprintf(&w, "ExtraFeatures: ")
    81  	for i := uint64(0); i < 64; i++ {
    82  		if cpuid.HasExtraFeature(1 << i) {
    83  			fmt.Fprintf(&w, "%s ", cpuid.ExtraFeatureNames[1<<i])
    84  		}
    85  	}
    86  	fmt.Fprintf(&w, "\n")
    87  
    88  	fmt.Fprintf(&w, "ThermalAndPowerFeatures: ")
    89  	for i := uint32(0); i < 64; i++ {
    90  		if cpuid.HasThermalAndPowerFeature(1 << i) {
    91  			if name, found := cpuid.ThermalAndPowerFeatureNames[1<<i]; found {
    92  				fmt.Fprintf(&w, "%s ", name)
    93  			}
    94  		}
    95  	}
    96  	fmt.Fprintf(&w, "\n")
    97  
    98  	for _, cacheDescription := range cpuid.CacheDescriptors {
    99  		fmt.Fprintf(&w, "CacheDescriptor: %v\n", cacheDescription)
   100  	}
   101  
   102  	return []byte(w.String())
   103  }
   104  
   105  // measureCPUIDFile extends the CPUIDInfo obtained from the cpuid package into
   106  // a TPM PCR.
   107  func measureCPUIDFile() ([]byte, error) {
   108  	d := getCPUIDInfo() // return strings builder
   109  	eventDesc := "CPUID Collector: Measured CPUID Info"
   110  	if e := tpm.ExtendPCRDebug(pcr, bytes.NewReader(d), eventDesc); e != nil {
   111  		return nil, e
   112  	}
   113  
   114  	return d, nil
   115  }
   116  
   117  // Collect gets the cpuid and extends it into the TPM and stores a copy on disk.
   118  //
   119  // It satisfies the Collector interface.
   120  func (s *CPUIDCollector) Collect() error {
   121  	d, err := measureCPUIDFile()
   122  	if err != nil {
   123  		log.Printf("CPUID Collector: err = %v", err)
   124  		return err
   125  	}
   126  
   127  	return slaunch.AddToPersistQueue("CPUID Collector", d, s.Location, defaultCPUIDFile)
   128  }