gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/types/asset.go (about)

     1  // Copyright (c) 2017 Intel Corporation
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  //
     5  
     6  package types
     7  
     8  import (
     9  	"crypto/sha512"
    10  	"encoding/hex"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"path/filepath"
    14  
    15  	"github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
    16  )
    17  
    18  // AssetType describe a type of assets.
    19  type AssetType string
    20  
    21  // Annotations returns the path and hash annotations for a given Asset type.
    22  func (t AssetType) Annotations() (string, string, error) {
    23  	switch t {
    24  	case KernelAsset:
    25  		return annotations.KernelPath, annotations.KernelHash, nil
    26  	case ImageAsset:
    27  		return annotations.ImagePath, annotations.ImageHash, nil
    28  	case InitrdAsset:
    29  		return annotations.InitrdPath, annotations.InitrdHash, nil
    30  	case HypervisorAsset:
    31  		return annotations.HypervisorPath, annotations.HypervisorHash, nil
    32  	case JailerAsset:
    33  		return annotations.JailerPath, annotations.JailerHash, nil
    34  	case FirmwareAsset:
    35  		return annotations.FirmwarePath, annotations.FirmwareHash, nil
    36  	}
    37  
    38  	return "", "", fmt.Errorf("Wrong asset type %s", t)
    39  }
    40  
    41  const (
    42  	// KernelAsset is a kernel asset.
    43  	KernelAsset AssetType = "kernel"
    44  
    45  	// ImageAsset is an image asset.
    46  	ImageAsset AssetType = "image"
    47  
    48  	// InitrdAsset is an intird asset.
    49  	InitrdAsset AssetType = "initrd"
    50  
    51  	// HypervisorAsset is an hypervisor asset.
    52  	HypervisorAsset AssetType = "hypervisor"
    53  
    54  	// HypervisorCtlAsset is an hypervisor control asset.
    55  	HypervisorCtlAsset AssetType = "hypervisorctl"
    56  	// JailerAsset is an jailer asset.
    57  	JailerAsset AssetType = "jailer"
    58  
    59  	// FirmwareAsset is a firmware asset.
    60  	FirmwareAsset AssetType = "firmware"
    61  )
    62  
    63  // Asset represents a virtcontainers asset.
    64  type Asset struct {
    65  	path         string
    66  	computedHash string
    67  	kind         AssetType
    68  }
    69  
    70  // Path returns an asset path.
    71  func (a Asset) Path() string {
    72  	return a.path
    73  }
    74  
    75  // Type returns an asset type.
    76  func (a Asset) Type() AssetType {
    77  	return a.kind
    78  }
    79  
    80  // Valid checks if an asset is valid or not.
    81  func (a *Asset) Valid() bool {
    82  	if !filepath.IsAbs(a.path) {
    83  		return false
    84  	}
    85  
    86  	switch a.kind {
    87  	case KernelAsset:
    88  		return true
    89  	case ImageAsset:
    90  		return true
    91  	case InitrdAsset:
    92  		return true
    93  	case HypervisorAsset:
    94  		return true
    95  	case JailerAsset:
    96  		return true
    97  	case FirmwareAsset:
    98  		return true
    99  	}
   100  
   101  	return false
   102  }
   103  
   104  // Hash returns the hex encoded string for the asset hash
   105  func (a *Asset) Hash(hashType string) (string, error) {
   106  	var hashEncodedLen int
   107  	var hash string
   108  
   109  	// We read the actual asset content
   110  	bytes, err := ioutil.ReadFile(a.path)
   111  	if err != nil {
   112  		return "", err
   113  	}
   114  
   115  	if len(bytes) == 0 {
   116  		return "", fmt.Errorf("Empty asset file at %s", a.path)
   117  	}
   118  
   119  	// Build the asset hash and convert it to a string.
   120  	// We only support SHA512 for now.
   121  	switch hashType {
   122  	case annotations.SHA512:
   123  		hashComputed := sha512.Sum512(bytes)
   124  		hashEncodedLen = hex.EncodedLen(len(hashComputed))
   125  		hashEncoded := make([]byte, hashEncodedLen)
   126  		hex.Encode(hashEncoded, hashComputed[:])
   127  		hash = string(hashEncoded[:])
   128  	default:
   129  		return "", fmt.Errorf("Invalid hash type %s", hashType)
   130  	}
   131  
   132  	a.computedHash = hash
   133  
   134  	return hash, nil
   135  }
   136  
   137  // NewAsset returns a new asset from a slice of annotations.
   138  func NewAsset(anno map[string]string, t AssetType) (*Asset, error) {
   139  	pathAnnotation, hashAnnotation, err := t.Annotations()
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  
   144  	if pathAnnotation == "" || hashAnnotation == "" {
   145  		return nil, fmt.Errorf("Missing annotation paths for %s", t)
   146  	}
   147  
   148  	path, ok := anno[pathAnnotation]
   149  	if !ok || path == "" {
   150  		return nil, nil
   151  	}
   152  
   153  	if !filepath.IsAbs(path) {
   154  		return nil, fmt.Errorf("%s is not an absolute path", path)
   155  	}
   156  
   157  	a := &Asset{path: path, kind: t}
   158  
   159  	hash, ok := anno[hashAnnotation]
   160  	if !ok || hash == "" {
   161  		return a, nil
   162  	}
   163  
   164  	// We have a hash annotation, we need to verify the asset against it.
   165  	hashType, ok := anno[annotations.AssetHashType]
   166  	if !ok {
   167  		hashType = annotations.SHA512
   168  	}
   169  
   170  	hashComputed, err := a.Hash(hashType)
   171  	if err != nil {
   172  		return a, err
   173  	}
   174  
   175  	// If our computed asset hash does not match the passed annotation, we must exit.
   176  	if hashComputed != hash {
   177  		return nil, fmt.Errorf("Invalid hash for %s: computed %s, expecting %s]", a.path, hashComputed, hash)
   178  	}
   179  
   180  	return a, nil
   181  }