github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/efivarfs/varfs_test.go (about)

     1  // Copyright 2022 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 efivarfs
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/binary"
    10  	"errors"
    11  	"os"
    12  	"path/filepath"
    13  	"strings"
    14  	"testing"
    15  
    16  	guid "github.com/google/uuid"
    17  )
    18  
    19  func TestProbeAndReturn(t *testing.T) {
    20  	for _, tt := range []struct {
    21  		name    string
    22  		path    string
    23  		wantErr error
    24  	}{
    25  		{
    26  			name:    "wrong magic",
    27  			path:    "/tmp",
    28  			wantErr: ErrNoFS,
    29  		},
    30  		{
    31  			name:    "wrong directory",
    32  			path:    "/bogus",
    33  			wantErr: ErrNoFS,
    34  		},
    35  	} {
    36  		t.Run(tt.name, func(t *testing.T) {
    37  			if _, err := NewPath(tt.path); !errors.Is(err, tt.wantErr) {
    38  				t.Errorf("Unexpected error: %v", err)
    39  			}
    40  		})
    41  	}
    42  }
    43  
    44  func TestGet(t *testing.T) {
    45  	for _, tt := range []struct {
    46  		name    string
    47  		vd      VariableDescriptor
    48  		attr    VariableAttributes
    49  		data    []byte
    50  		setup   func(path string, t *testing.T)
    51  		wantErr error
    52  	}{
    53  		{
    54  			name: "get var",
    55  			vd: VariableDescriptor{
    56  				Name: "TestVar",
    57  				GUID: func() guid.UUID {
    58  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
    59  					return g
    60  				}(),
    61  			},
    62  			attr: AttributeNonVolatile,
    63  			data: []byte("testdata"),
    64  			setup: func(path string, t *testing.T) {
    65  				t.Helper()
    66  				f := createTestVar(path, "TestVar-bc54d3fb-ed45-462d-9df8-b9f736228350", t)
    67  				var buf bytes.Buffer
    68  				if err := binary.Write(&buf, binary.LittleEndian, AttributeNonVolatile); err != nil {
    69  					t.Errorf("Failed writing bytes: %v", err)
    70  				}
    71  				if _, err := buf.Write([]byte("testdata")); err != nil {
    72  					t.Errorf("Failed writing data: %v", err)
    73  				}
    74  				if _, err := buf.WriteTo(f); err != nil {
    75  					t.Errorf("Failed writing to file: %v", err)
    76  				}
    77  				if err := f.Close(); err != nil {
    78  					t.Errorf("Failed to close file: %v", err)
    79  				}
    80  			},
    81  			wantErr: nil,
    82  		},
    83  		{
    84  			name: "not exist",
    85  			vd: VariableDescriptor{
    86  				Name: "TestVar",
    87  				GUID: func() guid.UUID {
    88  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
    89  					return g
    90  				}(),
    91  			},
    92  			attr:    0,
    93  			data:    nil,
    94  			setup:   func(path string, t *testing.T) { t.Helper() },
    95  			wantErr: ErrVarNotExist,
    96  		},
    97  		/* TODO: this test seems utterly broken. I have no idea why it ever seemed it might work.
    98  		{
    99  			name: "no permission",
   100  			vd: VariableDescriptor{
   101  				Name: "TestVar",
   102  				GUID: func() *guid.UUID {
   103  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   104  					return &g
   105  				}(),
   106  			},
   107  			attr: 0,
   108  			data: nil,
   109  			setup: func(path string, t *testing.T) {
   110  				t.Helper()
   111  				f := createTestVar(path, "TestVar-bc54d3fb-ed45-462d-9df8-b9f736228350", t)
   112  				if err := f.Chmod(0222); err != nil {
   113  					t.Errorf("Failed changing permissions: %v", err)
   114  				}
   115  				if err := f.Close(); err != nil {
   116  					t.Errorf("Failed to close file: %v", err)
   117  				}
   118  			},
   119  			wantErr: ErrVarPermission,
   120  		},
   121  		*/
   122  		{
   123  			name: "var empty",
   124  			vd: VariableDescriptor{
   125  				Name: "TestVar",
   126  				GUID: func() guid.UUID {
   127  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   128  					return g
   129  				}(),
   130  			},
   131  			attr: 0,
   132  			data: nil,
   133  			setup: func(path string, t *testing.T) {
   134  				t.Helper()
   135  				if err := createTestVar(path, "TestVar-bc54d3fb-ed45-462d-9df8-b9f736228350", t).Close(); err != nil {
   136  					t.Errorf("Failed to close file: %v", err)
   137  				}
   138  			},
   139  			wantErr: ErrVarNotExist,
   140  		},
   141  	} {
   142  		t.Run(tt.name, func(t *testing.T) {
   143  			tmp := t.TempDir()
   144  			tt.setup(tmp, t)
   145  			// This setup bypasses all the tests for this fake varfs.
   146  			e := &EFIVarFS{path: tmp}
   147  
   148  			attr, data, err := e.Get(tt.vd)
   149  			if errors.Is(err, ErrNoFS) {
   150  				t.Logf("no EFIVarFS: %v; skipping this test", err)
   151  				return
   152  			}
   153  			if !errors.Is(err, tt.wantErr) {
   154  				t.Errorf("Expected: %q, got: %v", tt.wantErr, err)
   155  			}
   156  			if attr != tt.attr {
   157  				t.Errorf("Want %v, Got: %v", tt.attr, attr)
   158  			}
   159  			if !bytes.Equal(data, tt.data) {
   160  				t.Errorf("Want: %v, Got: %v", tt.data, data)
   161  			}
   162  		})
   163  	}
   164  }
   165  
   166  func TestSet(t *testing.T) {
   167  	for _, tt := range []struct {
   168  		name    string
   169  		vd      VariableDescriptor
   170  		attr    VariableAttributes
   171  		data    []byte
   172  		setup   func(path string, t *testing.T)
   173  		wantErr error
   174  	}{
   175  		{
   176  			name: "set var",
   177  			vd: VariableDescriptor{
   178  				Name: "TestVar",
   179  				GUID: func() guid.UUID {
   180  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   181  					return g
   182  				}(),
   183  			},
   184  			attr:    0,
   185  			data:    nil,
   186  			setup:   func(path string, t *testing.T) { t.Helper() },
   187  			wantErr: nil,
   188  		},
   189  		{
   190  			name: "append write",
   191  			vd: VariableDescriptor{
   192  				Name: "TestVar",
   193  				GUID: func() guid.UUID {
   194  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   195  					return g
   196  				}(),
   197  			},
   198  			attr:    AttributeAppendWrite,
   199  			data:    nil,
   200  			setup:   func(path string, t *testing.T) { t.Helper() },
   201  			wantErr: nil,
   202  		},
   203  		{
   204  			name: "no read permission",
   205  			vd: VariableDescriptor{
   206  				Name: "TestVar",
   207  				GUID: func() guid.UUID {
   208  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   209  					return g
   210  				}(),
   211  			},
   212  			attr: 0,
   213  			data: nil,
   214  			setup: func(path string, t *testing.T) {
   215  				t.Helper()
   216  				f := createTestVar(path, "TestVar-bc54d3fb-ed45-462d-9df8-b9f736228350", t)
   217  				if err := f.Chmod(0222); err != nil {
   218  					t.Errorf("Failed changing permissions: %v", err)
   219  				}
   220  				if err := f.Close(); err != nil {
   221  					t.Errorf("Failed to close file: %v", err)
   222  				}
   223  			},
   224  			wantErr: ErrVarPermission,
   225  		},
   226  		{
   227  			name: "var exists",
   228  			vd: VariableDescriptor{
   229  				Name: "TestVar",
   230  				GUID: func() guid.UUID {
   231  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   232  					return g
   233  				}(),
   234  			},
   235  			attr: 0,
   236  			data: nil,
   237  			setup: func(path string, t *testing.T) {
   238  				t.Helper()
   239  				f := createTestVar(path, "TestVar-bc54d3fb-ed45-462d-9df8-b9f736228350", t)
   240  				if err := f.Close(); err != nil {
   241  					t.Errorf("Failed to close file: %v", err)
   242  				}
   243  			},
   244  			wantErr: errors.New("inappropriate ioctl for device"),
   245  		},
   246  		{
   247  			name: "input data",
   248  			vd: VariableDescriptor{
   249  				Name: "TestVar",
   250  				GUID: func() guid.UUID {
   251  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   252  					return g
   253  				}(),
   254  			},
   255  			attr:    0,
   256  			data:    []byte("tests"),
   257  			setup:   func(path string, t *testing.T) { t.Helper() },
   258  			wantErr: nil,
   259  		},
   260  	} {
   261  		t.Run(tt.name, func(t *testing.T) {
   262  			tmp := t.TempDir()
   263  			tt.setup(tmp, t)
   264  			// This setup bypasses all the tests for this fake varfs.
   265  			e := &EFIVarFS{path: tmp}
   266  
   267  			if err := e.Set(tt.vd, tt.attr, tt.data); err != nil {
   268  				if !errors.Is(err, tt.wantErr) {
   269  					// Needed as some errors include changing tmp directory names
   270  					if !strings.Contains(err.Error(), tt.wantErr.Error()) {
   271  						t.Errorf("Want: %v, Got: %v", tt.wantErr, err)
   272  					}
   273  				}
   274  			}
   275  		})
   276  	}
   277  }
   278  
   279  func TestRemove(t *testing.T) {
   280  	for _, tt := range []struct {
   281  		name    string
   282  		vd      VariableDescriptor
   283  		setup   func(path string, t *testing.T)
   284  		wantErr error
   285  	}{
   286  		{
   287  			name: "remove var",
   288  			vd: VariableDescriptor{
   289  				Name: "TestVar",
   290  				GUID: func() guid.UUID {
   291  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   292  					return g
   293  				}(),
   294  			},
   295  			setup: func(path string, t *testing.T) {
   296  				t.Helper()
   297  				if err := createTestVar(path, "TestVar-bc54d3fb-ed45-462d-9df8-b9f736228350", t).Close(); err != nil {
   298  					t.Errorf("Failed to close file: %v", err)
   299  				}
   300  			},
   301  			wantErr: errors.New("inappropriate ioctl for device"),
   302  		},
   303  		{
   304  			name: "no permission",
   305  			vd: VariableDescriptor{
   306  				Name: "TestVar",
   307  				GUID: func() guid.UUID {
   308  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   309  					return g
   310  				}(),
   311  			},
   312  			setup: func(path string, t *testing.T) {
   313  				t.Helper()
   314  				f := createTestVar(path, "TestVar-bc54d3fb-ed45-462d-9df8-b9f736228350", t)
   315  				if err := f.Chmod(0444); err != nil {
   316  					t.Errorf("Failed changing permissions: %v", err)
   317  				}
   318  				if err := f.Close(); err != nil {
   319  					t.Errorf("Failed to close file: %v", err)
   320  				}
   321  			},
   322  			wantErr: ErrVarPermission,
   323  		},
   324  		{
   325  			name: "var not exist",
   326  			vd: VariableDescriptor{
   327  				Name: "TestVar",
   328  				GUID: func() guid.UUID {
   329  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   330  					return g
   331  				}(),
   332  			},
   333  			setup:   func(path string, t *testing.T) { t.Helper() },
   334  			wantErr: ErrVarNotExist,
   335  		},
   336  	} {
   337  		t.Run(tt.name, func(t *testing.T) {
   338  			tmp := t.TempDir()
   339  			tt.setup(tmp, t)
   340  			// This setup bypasses all the tests for this fake varfs.
   341  			e := &EFIVarFS{path: tmp}
   342  
   343  			if err := e.Remove(tt.vd); err != nil {
   344  				if !errors.Is(err, tt.wantErr) {
   345  					// Needed as some errors include changing tmp directory names
   346  					if !strings.Contains(err.Error(), tt.wantErr.Error()) {
   347  						t.Errorf("Want: %v, Got: %v", tt.wantErr, err)
   348  					}
   349  				}
   350  			}
   351  		})
   352  	}
   353  }
   354  
   355  func TestList(t *testing.T) {
   356  	for _, tt := range []struct {
   357  		name    string
   358  		vd      VariableDescriptor
   359  		dir     string
   360  		setup   func(path string, t *testing.T)
   361  		wantErr error
   362  	}{
   363  		{
   364  			name: "empty var",
   365  			vd: VariableDescriptor{
   366  				Name: "TestVar",
   367  				GUID: func() guid.UUID {
   368  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   369  					return g
   370  				}(),
   371  			},
   372  			dir: t.TempDir(),
   373  			setup: func(path string, t *testing.T) {
   374  				t.Helper()
   375  				if err := createTestVar(path, "TestVar-bc54d3fb-ed45-462d-9df8-b9f736228350", t).Close(); err != nil {
   376  					t.Errorf("Failed to close file: %v", err)
   377  				}
   378  			},
   379  			wantErr: nil,
   380  		},
   381  		{
   382  			name: "var with data",
   383  			vd: VariableDescriptor{
   384  				Name: "TestVar",
   385  				GUID: func() guid.UUID {
   386  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   387  					return g
   388  				}(),
   389  			},
   390  			dir: t.TempDir(),
   391  			setup: func(path string, t *testing.T) {
   392  				t.Helper()
   393  				f := createTestVar(path, "TestVar-bc54d3fb-ed45-462d-9df8-b9f736228350", t)
   394  				var buf bytes.Buffer
   395  				if err := binary.Write(&buf, binary.LittleEndian, AttributeNonVolatile); err != nil {
   396  					t.Errorf("Failed writing bytes: %v", err)
   397  				}
   398  				if _, err := buf.Write([]byte("testdata")); err != nil {
   399  					t.Errorf("Failed writing data: %v", err)
   400  				}
   401  				if _, err := buf.WriteTo(f); err != nil {
   402  					t.Errorf("Failed writing to file: %v", err)
   403  				}
   404  				if err := f.Close(); err != nil {
   405  					t.Errorf("Failed to close file: %v", err)
   406  				}
   407  			},
   408  			wantErr: nil,
   409  		},
   410  		{
   411  			name: "no regular files",
   412  			vd: VariableDescriptor{
   413  				Name: "TestVar",
   414  				GUID: func() guid.UUID {
   415  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   416  					return g
   417  				}(),
   418  			},
   419  			dir: t.TempDir(),
   420  			setup: func(path string, t *testing.T) {
   421  				t.Helper()
   422  				if err := os.Mkdir(filepath.Join(path, "testdir"), 0644); err != nil {
   423  					t.Errorf("Failed to create directory: %v", err)
   424  				}
   425  			},
   426  			wantErr: nil,
   427  		},
   428  		{
   429  			name: "no permission",
   430  			vd: VariableDescriptor{
   431  				Name: "TestVar",
   432  				GUID: func() guid.UUID {
   433  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   434  					return g
   435  				}(),
   436  			},
   437  			dir: t.TempDir(),
   438  			setup: func(path string, t *testing.T) {
   439  				t.Helper()
   440  				if err := os.Chmod(path, 0222); err != nil {
   441  					t.Errorf("Failed changing permissions: %v", err)
   442  				}
   443  			},
   444  			wantErr: ErrVarPermission,
   445  		},
   446  		{
   447  			name: "no dir",
   448  			vd: VariableDescriptor{
   449  				Name: "TestVar",
   450  				GUID: func() guid.UUID {
   451  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   452  					return g
   453  				}(),
   454  			},
   455  			dir:     "/bogus",
   456  			setup:   func(path string, t *testing.T) { t.Helper() },
   457  			wantErr: ErrVarNotExist,
   458  		},
   459  		{
   460  			name: "malformed vars",
   461  			vd: VariableDescriptor{
   462  				Name: "TestVar",
   463  				GUID: func() guid.UUID {
   464  					g := guid.MustParse("bc54d3fb-ed45-462d-9df8-b9f736228350")
   465  					return g
   466  				}(),
   467  			},
   468  			dir: t.TempDir(),
   469  			setup: func(path string, t *testing.T) {
   470  				t.Helper()
   471  				if err := createTestVar(path, "TestVar-bc54d3fb-ed45-462d-9df8-b9f7362283500000", t).Close(); err != nil {
   472  					t.Errorf("Failed to close file: %v", err)
   473  				}
   474  				if err := createTestVar(path, "TestVar-bc54d3fb-ed45-462d-9df8-b", t).Close(); err != nil {
   475  					t.Errorf("Failed to close file: %v", err)
   476  				}
   477  			},
   478  			wantErr: nil,
   479  		},
   480  	} {
   481  		t.Run(tt.name, func(t *testing.T) {
   482  			tmp := t.TempDir()
   483  			tt.setup(tt.dir, t)
   484  			// This setup bypasses all the tests for this fake varfs.
   485  			e := &EFIVarFS{path: tmp}
   486  
   487  			if _, err := e.List(); err != nil {
   488  				if !errors.Is(err, tt.wantErr) {
   489  					// Needed as some errors include changing tmp directory names
   490  					if !strings.Contains(err.Error(), tt.wantErr.Error()) {
   491  						t.Errorf("Want: %v, Got: %v", tt.wantErr, err)
   492  					}
   493  				}
   494  			}
   495  		})
   496  	}
   497  }
   498  
   499  func createTestVar(path, varFullName string, t *testing.T) *os.File {
   500  	t.Helper()
   501  	f, err := os.Create(filepath.Join(path, varFullName))
   502  	if err != nil {
   503  		t.Errorf("Failed creating test var: %v", err)
   504  	}
   505  	return f
   506  }
   507  
   508  func TestNew(t *testing.T) {
   509  	// the EFI file system may not be available, but we call New
   510  	// anyway to at least get some coverage.
   511  	e, err := New()
   512  	t.Logf("New(): %v, %v", e, err)
   513  }