...

Source file src/github.com/sigstore/rekor/pkg/fuzz/alpine_utils.go

Documentation: github.com/sigstore/rekor/pkg/fuzz

     1  //
     2  // Copyright 2023 The Sigstore Authors.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package fuzz
    17  
    18  import (
    19  	"archive/tar"
    20  	"bytes"
    21  	"compress/gzip"
    22  	"errors"
    23  	"fmt"
    24  	"os"
    25  	"strings"
    26  
    27  	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
    28  	"github.com/sigstore/rekor/pkg/types"
    29  )
    30  
    31  // Allows the fuzzer to create a .SIGN filename
    32  func getSignFilename(ff *fuzz.ConsumeFuzzer) (string, error) {
    33  	keyName, err := ff.GetString()
    34  	if err != nil {
    35  		return "", err
    36  	}
    37  	var b strings.Builder
    38  	b.WriteString(".SIGN.RSA.")
    39  	b.WriteString(keyName)
    40  	b.WriteString(".rsa.pub")
    41  	return b.String(), nil
    42  }
    43  
    44  // createPkgInfoFileContents creates a structured pkginfo file
    45  //
    46  // .PKGINFO files look like this:
    47  //
    48  // # Generated by abuild 3.9.0-r2
    49  // # using fakeroot version 1.25.3
    50  // # Wed Jul  6 19:09:49 UTC 2022
    51  // pkgname = busybox
    52  // pkgver = 1.35.0-r18
    53  // pkgdesc = Size optimized toolbox of many common UNIX utilities
    54  // url = https://busybox.net/
    55  // builddate = 1657134589
    56  // packager = Buildozer <developer@email.org>
    57  // size = 958464
    58  // arch = x86_64
    59  // origin = busybox
    60  // commit = 332d2fff53cd4537d415e15e55e8ceb6fe6eaedb
    61  // maintainer = Sören Tempel <soeren+alpine@soeren-tempel.net>
    62  // provider_priority = 100
    63  // license = GPL-2.0-only
    64  // replaces = busybox-initscripts
    65  // provides = /bin/sh
    66  // triggers = /bin /usr/bin /sbin /usr/sbin /lib/modules/*
    67  // # automatically detected:
    68  // provides = cmd:busybox=1.35.0-r18
    69  // provides = cmd:sh=1.35.0-r18
    70  // depend = so:libc.musl-x86_64.so.1
    71  // datahash = 7d3351ac6c3ebaf18182efb5390061f50d077ce5ade60a15909d91278f70ada7
    72  func createPkgInfoFileContents(ff *fuzz.ConsumeFuzzer) ([]byte, error) {
    73  	var b strings.Builder
    74  	noOfRows, err := ff.GetInt()
    75  	if err != nil {
    76  		return []byte(""), err
    77  	}
    78  
    79  	// Comments at the top of the pkginfo file
    80  	header, err := ff.GetBytes()
    81  	if err != nil {
    82  		return []byte(""), err
    83  	}
    84  	b.Write(header)
    85  
    86  	for i := 0; i < noOfRows; i++ {
    87  		key, err := ff.GetBytes()
    88  		if err != nil {
    89  			return []byte(""), err
    90  		}
    91  		value, err := ff.GetBytes()
    92  		if err != nil {
    93  			return []byte(""), err
    94  		}
    95  		b.Write(key)
    96  		b.Write([]byte(" = "))
    97  		b.Write(value)
    98  		b.WriteString("\n")
    99  	}
   100  	return []byte(b.String()), nil
   101  }
   102  
   103  // Adds a .SIGN file to tarBytes
   104  func addSignFile(ff *fuzz.ConsumeFuzzer, tarFiles []*fuzz.TarFile) ([]*fuzz.TarFile, error) {
   105  	SIGNFileContents, err := ff.GetBytes()
   106  	if err != nil {
   107  		return tarFiles, err
   108  	}
   109  
   110  	SIGNFileName, err := getSignFilename(ff)
   111  	if err != nil {
   112  		return tarFiles, err
   113  	}
   114  	signFile := &fuzz.TarFile{
   115  		Body: SIGNFileContents,
   116  		Hdr: &tar.Header{
   117  			Name:     SIGNFileName,
   118  			Mode:     0644,
   119  			Size:     int64(len(SIGNFileContents)),
   120  			Typeflag: tar.TypeReg,
   121  			Gid:      0,
   122  			Uid:      0,
   123  		},
   124  	}
   125  	tarFiles = append(tarFiles, signFile)
   126  
   127  	return tarFiles, nil
   128  }
   129  
   130  // Allows the fuzzer to randomize whether a .SIGN file should
   131  // be added to tarBytes
   132  func shouldAddSignFile(ff *fuzz.ConsumeFuzzer, tarFiles []*fuzz.TarFile) bool {
   133  	shouldRequireSIGNFile, err := ff.GetBool()
   134  	if err != nil {
   135  		return false
   136  	}
   137  	if shouldRequireSIGNFile {
   138  		for _, tarFile := range tarFiles {
   139  			if strings.HasPrefix(tarFile.Hdr.Name, ".SIGN") {
   140  				return false
   141  			}
   142  		}
   143  		return true
   144  	}
   145  	return false
   146  }
   147  
   148  // Allows the fuzzer to randomize whether a .PKGINFO file should
   149  // be added to tarBytes
   150  func shouldAddPkgInfoFile(ff *fuzz.ConsumeFuzzer, tarFiles []*fuzz.TarFile) bool {
   151  	shouldRequirePKGINFOFile, err := ff.GetBool()
   152  	if err != nil {
   153  		return false
   154  	}
   155  	if shouldRequirePKGINFOFile {
   156  		for _, tarFile := range tarFiles {
   157  			if strings.HasPrefix(tarFile.Hdr.Name, ".PKGINFO") {
   158  				return false
   159  			}
   160  		}
   161  		return true
   162  	}
   163  	return false
   164  }
   165  
   166  // Adds the .PKGINFO file to the tar files
   167  func addPkgInfoFile(ff *fuzz.ConsumeFuzzer, tarFiles []*fuzz.TarFile) ([]*fuzz.TarFile, error) {
   168  	tarFile := &fuzz.TarFile{}
   169  	PKGINFOFileContents, err := createPkgInfoFileContents(ff)
   170  	if err != nil {
   171  		return tarFiles, err
   172  	}
   173  	tarFile.Body = PKGINFOFileContents
   174  	tarFile.Hdr = &tar.Header{
   175  		Name:     ".PKGINFO",
   176  		Mode:     0644,
   177  		Size:     int64(len(PKGINFOFileContents)),
   178  		Typeflag: tar.TypeReg,
   179  		Gid:      0,
   180  		Uid:      0,
   181  	}
   182  
   183  	return tarFiles, nil
   184  }
   185  
   186  func AlpineArtifactBytes(ff *fuzz.ConsumeFuzzer) ([]byte, error) {
   187  	var tarFiles, tarFiles2 []*fuzz.TarFile
   188  	var err error
   189  
   190  	tarFiles, err = ff.TarFiles()
   191  	if err != nil {
   192  		return []byte(""), err
   193  	}
   194  	if shouldAddSignFile(ff, tarFiles) {
   195  		tarFiles, err = addSignFile(ff, tarFiles)
   196  		if err != nil {
   197  			return []byte(""), err
   198  		}
   199  	}
   200  
   201  	tarFiles2, err = ff.TarFiles()
   202  	if err != nil {
   203  		return []byte(""), err
   204  	}
   205  
   206  	if shouldAddPkgInfoFile(ff, tarFiles2) {
   207  		tarFiles2, err = addPkgInfoFile(ff, tarFiles2)
   208  		if err != nil {
   209  			return []byte(""), err
   210  		}
   211  	}
   212  
   213  	return concatenateTarArchives(tarFiles, tarFiles2)
   214  }
   215  
   216  func concatenateTarArchives(tarFiles1 []*fuzz.TarFile, tarFiles2 []*fuzz.TarFile) ([]byte, error) {
   217  	var buf1, buf2 bytes.Buffer
   218  	var err error
   219  
   220  	tw1 := tar.NewWriter(&buf1)
   221  	for _, tf := range tarFiles1 {
   222  		err = tw1.WriteHeader(tf.Hdr)
   223  		if err != nil {
   224  			return []byte(""), err
   225  		}
   226  		_, err = tw1.Write(tf.Body)
   227  		if err != nil {
   228  			return []byte(""), err
   229  		}
   230  	}
   231  	tw1.Close()
   232  	tarBytes := buf1.Bytes()
   233  
   234  	tw2 := tar.NewWriter(&buf2)
   235  	for _, tf := range tarFiles2 {
   236  		err = tw2.WriteHeader(tf.Hdr)
   237  		if err != nil {
   238  			return []byte(""), err
   239  		}
   240  		_, err = tw2.Write(tf.Body)
   241  		if err != nil {
   242  			return []byte(""), err
   243  		}
   244  	}
   245  	tw2.Close()
   246  	tarBytes2 := buf2.Bytes()
   247  
   248  	var b1 bytes.Buffer
   249  	w1 := gzip.NewWriter(&b1)
   250  	defer w1.Close()
   251  	_, err = w1.Write(tarBytes)
   252  	if err != nil {
   253  		return []byte(""), err
   254  	}
   255  	w1.Close()
   256  
   257  	var b2 bytes.Buffer
   258  	w2 := gzip.NewWriter(&b2)
   259  	defer w2.Close()
   260  	_, err = w2.Write(tarBytes2)
   261  	if err != nil {
   262  		return []byte(""), err
   263  	}
   264  	w2.Close()
   265  	concatenated := append(b1.Bytes(), b2.Bytes()...)
   266  	return concatenated, nil
   267  }
   268  
   269  func setAlpineArtifactFields(ff *fuzz.ConsumeFuzzer, props *types.ArtifactProperties) (func(), error) {
   270  	cleanup := func() {}
   271  
   272  	err := setArtifactHash(ff, props)
   273  	if err != nil {
   274  		return cleanup, err
   275  	}
   276  
   277  	artifactBytes, err := AlpineArtifactBytes(ff)
   278  	if err != nil {
   279  		return cleanup, err
   280  	}
   281  
   282  	shouldSetArtifactBytes, err := ff.GetBool()
   283  	if err != nil {
   284  		return cleanup, err
   285  	}
   286  
   287  	if shouldSetArtifactBytes {
   288  		props.ArtifactBytes = artifactBytes
   289  		return func() {
   290  			// do nothing
   291  		}, nil
   292  	}
   293  	artifactFile, err := createAbsFile(ff, "ArtifactFile", artifactBytes)
   294  	cleanup = func() {
   295  		os.Remove("ArtifactFile")
   296  	}
   297  	props.ArtifactPath = artifactFile
   298  	return cleanup, err
   299  }
   300  
   301  // Creates an ArtifactProperties with values determined by the fuzzer
   302  func CreateAlpineProps(ff *fuzz.ConsumeFuzzer) (types.ArtifactProperties, func(), error) {
   303  	props := &types.ArtifactProperties{}
   304  
   305  	cleanupArtifactFile, err := setAlpineArtifactFields(ff, props)
   306  	if err != nil {
   307  		return *props, cleanupArtifactFile, err
   308  	}
   309  	if props.ArtifactPath == nil && props.ArtifactBytes == nil {
   310  		return *props, cleanupArtifactFile, errors.New("ArtifactPath and ArtifactBytes cannot both be nil")
   311  	}
   312  
   313  	err = setAdditionalAuthenticatedData(ff, props)
   314  	if err != nil {
   315  		return *props, cleanupArtifactFile, errors.New("Failed setting AdditionalAuthenticatedData")
   316  	}
   317  
   318  	cleanupSignatureFile, err := setSignatureFields(ff, props)
   319  	if err != nil {
   320  		return *props, func() {
   321  			cleanupArtifactFile()
   322  			cleanupSignatureFile()
   323  		}, fmt.Errorf("failed setting signature fields: %w", err)
   324  	}
   325  
   326  	cleanupPublicKeyFile, err := setPublicKeyFields(ff, props)
   327  	if err != nil {
   328  		return *props, func() {
   329  			cleanupArtifactFile()
   330  			cleanupSignatureFile()
   331  			cleanupPublicKeyFile()
   332  		}, fmt.Errorf("failed setting public key fields: %w", err)
   333  	}
   334  
   335  	err = setPKIFormat(ff, props)
   336  	if err != nil {
   337  		return *props, func() {
   338  			cleanupArtifactFile()
   339  			cleanupSignatureFile()
   340  			cleanupPublicKeyFile()
   341  		}, fmt.Errorf("failed setting PKI Format: %w", err)
   342  	}
   343  
   344  	return *props, func() {
   345  		cleanupArtifactFile()
   346  		cleanupSignatureFile()
   347  		cleanupPublicKeyFile()
   348  	}, nil
   349  }
   350  

View as plain text