github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/boot/grub/config_test.go (about)

     1  // Copyright 2017-2020 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 grub
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"io"
    11  	"log"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  	"testing"
    16  
    17  	"github.com/mvdan/u-root-coreutils/pkg/boot/boottest"
    18  	"github.com/mvdan/u-root-coreutils/pkg/mount"
    19  	"github.com/mvdan/u-root-coreutils/pkg/mount/block"
    20  )
    21  
    22  // fakeDevices returns a list of fake block devices and a pool of mount points.
    23  // The pool is pre-populated so that Mount is never called.
    24  func fakeDevices() (block.BlockDevices, *mount.Pool, error) {
    25  	// For some reason, Glob("testdata_new/*/") does not work here.
    26  	files, err := os.ReadDir("testdata_new")
    27  	if err != nil {
    28  		return nil, nil, err
    29  	}
    30  	dirs := []string{}
    31  	for _, f := range files {
    32  		if f.IsDir() {
    33  			dirs = append(dirs, filepath.Join("testdata_new", f.Name()))
    34  		}
    35  	}
    36  
    37  	devices := block.BlockDevices{}
    38  	mountPool := &mount.Pool{}
    39  	for _, dir := range dirs {
    40  		// TODO: Also add LABEL to BlockDev
    41  		fsUUID, _ := os.ReadFile(filepath.Join(dir, "UUID"))
    42  		devices = append(devices, &block.BlockDev{
    43  			Name:   dir,
    44  			FSType: "test",
    45  			FsUUID: strings.TrimSpace(string(fsUUID)),
    46  		})
    47  		mountPool.Add(&mount.MountPoint{
    48  			Path:   dir,
    49  			Device: filepath.Join("/dev", dir),
    50  			FSType: "test",
    51  		})
    52  	}
    53  	return devices, mountPool, nil
    54  }
    55  
    56  // Enable this to generate new configs.
    57  func DISABLEDTestGenerateConfigs(t *testing.T) {
    58  	tests, err := filepath.Glob("testdata_new/*.json")
    59  	if err != nil {
    60  		t.Error("Failed to find test config files:", err)
    61  	}
    62  
    63  	for _, test := range tests {
    64  		configPath := strings.TrimSuffix(test, ".json")
    65  		t.Run(configPath, func(t *testing.T) {
    66  			devices, mountPool, err := fakeDevices()
    67  			if err != nil {
    68  				t.Fatal(err)
    69  			}
    70  			imgs, err := ParseLocalConfig(context.Background(), configPath, devices, mountPool)
    71  			if err != nil {
    72  				t.Fatalf("Failed to parse %s: %v", test, err)
    73  			}
    74  
    75  			if err := boottest.ToJSONFile(imgs, test); err != nil {
    76  				t.Errorf("failed to generate file: %v", err)
    77  			}
    78  		})
    79  	}
    80  }
    81  
    82  func TestConfigs(t *testing.T) {
    83  	// find all saved configs
    84  	tests, err := filepath.Glob("testdata_new/*.json")
    85  	if err != nil {
    86  		t.Error("Failed to find test config files:", err)
    87  	}
    88  
    89  	for _, test := range tests {
    90  		configPath := strings.TrimSuffix(test, ".json")
    91  		t.Run(configPath, func(t *testing.T) {
    92  			want, err := os.ReadFile(test)
    93  			if err != nil {
    94  				t.Errorf("Failed to read test json '%v':%v", test, err)
    95  			}
    96  
    97  			devices, mountPool, err := fakeDevices()
    98  			if err != nil {
    99  				t.Fatal(err)
   100  			}
   101  			imgs, err := ParseLocalConfig(context.Background(), configPath, devices, mountPool)
   102  			if err != nil {
   103  				t.Fatalf("Failed to parse %s: %v", test, err)
   104  			}
   105  
   106  			if err := boottest.CompareImagesToJSON(imgs, want); err != nil {
   107  				t.Errorf("ParseLocalConfig(): %v", err)
   108  			}
   109  		})
   110  	}
   111  }
   112  
   113  func FuzzParseGrubConfig(f *testing.F) {
   114  
   115  	baseDir := f.TempDir()
   116  
   117  	dirPath := filepath.Join(baseDir, "EFI", "uefi")
   118  	err := os.MkdirAll(dirPath, 0o777)
   119  	if err != nil {
   120  		f.Fatalf("failed %v: %v", dirPath, err)
   121  	}
   122  
   123  	path := filepath.Join(dirPath, "grub.cfg")
   124  	devices := block.BlockDevices{&block.BlockDev{
   125  		Name:   dirPath,
   126  		FSType: "test",
   127  		FsUUID: strings.TrimSpace("07338180-4a96-4611-aa6a-a452600e4cfe"),
   128  	}}
   129  	mountPool := &mount.Pool{}
   130  	mountPool.Add(&mount.MountPoint{
   131  		Path:   dirPath,
   132  		Device: filepath.Join("/dev", dirPath),
   133  		FSType: "test",
   134  	})
   135  
   136  	//no log output
   137  	log.SetOutput(io.Discard)
   138  	log.SetFlags(0)
   139  
   140  	// get seed corpora from testdata_new files
   141  	seeds, err := filepath.Glob("testdata_new/*/*/*/grub.cfg")
   142  	if err != nil {
   143  		f.Fatalf("failed to find seed corpora files: %v", err)
   144  	}
   145  
   146  	seeds2, err := filepath.Glob("testdata_new/*/*/grub.cfg")
   147  	if err != nil {
   148  		f.Fatalf("failed to find seed corpora files: %v", err)
   149  	}
   150  
   151  	seeds = append(seeds, seeds2...)
   152  	for _, seed := range seeds {
   153  		seedBytes, err := os.ReadFile(seed)
   154  		if err != nil {
   155  			f.Fatalf("failed read seed corpora from files %v: %v", seed, err)
   156  		}
   157  
   158  		f.Add(seedBytes)
   159  	}
   160  
   161  	f.Add([]byte("multiBoot 0\nmodule --nounzip"))
   162  	f.Fuzz(func(t *testing.T, data []byte) {
   163  		if len(data) > 4096 {
   164  			return
   165  		}
   166  
   167  		// do not allow arbitrary files reads
   168  		if bytes.Contains(data, []byte("include")) {
   169  			return
   170  		}
   171  
   172  		err = os.WriteFile(path, data, 0o777)
   173  		if err != nil {
   174  			t.Fatalf("Failed to create configfile '%v':%v", path, err)
   175  		}
   176  
   177  		ParseLocalConfig(context.Background(), baseDir, devices, mountPool)
   178  	})
   179  }