github.com/anchore/syft@v1.38.2/syft/file/cataloger/executable/elf_test.go (about)

     1  package executable
     2  
     3  import (
     4  	"debug/elf"
     5  	"os"
     6  	"path/filepath"
     7  	"testing"
     8  
     9  	"github.com/google/go-cmp/cmp"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/anchore/syft/syft/file"
    14  	"github.com/anchore/syft/syft/internal/unionreader"
    15  )
    16  
    17  func Test_findELFSecurityFeatures(t *testing.T) {
    18  
    19  	readerForFixture := func(t *testing.T, fixture string) unionreader.UnionReader {
    20  		t.Helper()
    21  		f, err := os.Open(filepath.Join("test-fixtures/elf", fixture))
    22  		require.NoError(t, err)
    23  		return f
    24  	}
    25  
    26  	tests := []struct {
    27  		name         string
    28  		fixture      string
    29  		want         *file.ELFSecurityFeatures
    30  		wantErr      require.ErrorAssertionFunc
    31  		wantStripped bool
    32  	}{
    33  		{
    34  			name:    "detect canary",
    35  			fixture: "bin/with_canary",
    36  			want: &file.ELFSecurityFeatures{
    37  				StackCanary:              boolRef(true), // ! important !
    38  				RelocationReadOnly:       file.RelocationReadOnlyNone,
    39  				LlvmSafeStack:            boolRef(false),
    40  				LlvmControlFlowIntegrity: boolRef(false),
    41  				ClangFortifySource:       boolRef(false),
    42  			},
    43  		},
    44  		{
    45  			name:    "detect nx",
    46  			fixture: "bin/with_nx",
    47  			want: &file.ELFSecurityFeatures{
    48  				StackCanary:              boolRef(false),
    49  				NoExecutable:             true, // ! important !
    50  				RelocationReadOnly:       file.RelocationReadOnlyNone,
    51  				LlvmSafeStack:            boolRef(false),
    52  				LlvmControlFlowIntegrity: boolRef(false),
    53  				ClangFortifySource:       boolRef(false),
    54  			},
    55  		},
    56  		{
    57  			name:    "detect relro",
    58  			fixture: "bin/with_relro",
    59  			want: &file.ELFSecurityFeatures{
    60  				StackCanary:              boolRef(false),
    61  				RelocationReadOnly:       file.RelocationReadOnlyFull, // ! important !
    62  				LlvmSafeStack:            boolRef(false),
    63  				LlvmControlFlowIntegrity: boolRef(false),
    64  				ClangFortifySource:       boolRef(false),
    65  			},
    66  		},
    67  		{
    68  			name:    "detect partial relro",
    69  			fixture: "bin/with_partial_relro",
    70  			want: &file.ELFSecurityFeatures{
    71  				StackCanary:              boolRef(false),
    72  				RelocationReadOnly:       file.RelocationReadOnlyPartial, // ! important !
    73  				LlvmSafeStack:            boolRef(false),
    74  				LlvmControlFlowIntegrity: boolRef(false),
    75  				ClangFortifySource:       boolRef(false),
    76  			},
    77  		},
    78  		{
    79  			name:    "detect pie",
    80  			fixture: "bin/with_pie",
    81  			want: &file.ELFSecurityFeatures{
    82  				StackCanary:                   boolRef(false),
    83  				RelocationReadOnly:            file.RelocationReadOnlyNone,
    84  				PositionIndependentExecutable: true, // ! important !
    85  				DynamicSharedObject:           true, // ! important !
    86  				LlvmSafeStack:                 boolRef(false),
    87  				LlvmControlFlowIntegrity:      boolRef(false),
    88  				ClangFortifySource:            boolRef(false),
    89  			},
    90  		},
    91  		{
    92  			name:    "detect dso",
    93  			fixture: "bin/pie_false_positive.so",
    94  			want: &file.ELFSecurityFeatures{
    95  				StackCanary:                   boolRef(false),
    96  				RelocationReadOnly:            file.RelocationReadOnlyPartial,
    97  				NoExecutable:                  true,
    98  				PositionIndependentExecutable: false, // ! important !
    99  				DynamicSharedObject:           true,  // ! important !
   100  				LlvmSafeStack:                 boolRef(false),
   101  				LlvmControlFlowIntegrity:      boolRef(false),
   102  				ClangFortifySource:            boolRef(false),
   103  			},
   104  		},
   105  		{
   106  			name:    "detect safestack",
   107  			fixture: "bin/with_safestack",
   108  			want: &file.ELFSecurityFeatures{
   109  				NoExecutable:                  true,
   110  				StackCanary:                   boolRef(false),
   111  				RelocationReadOnly:            file.RelocationReadOnlyPartial,
   112  				PositionIndependentExecutable: false,
   113  				DynamicSharedObject:           false,
   114  				LlvmSafeStack:                 boolRef(true), // ! important !
   115  				LlvmControlFlowIntegrity:      boolRef(false),
   116  				ClangFortifySource:            boolRef(false),
   117  			},
   118  		},
   119  		{
   120  			name:    "detect cfi",
   121  			fixture: "bin/with_cfi",
   122  			want: &file.ELFSecurityFeatures{
   123  				NoExecutable:                  true,
   124  				StackCanary:                   boolRef(false),
   125  				RelocationReadOnly:            file.RelocationReadOnlyPartial,
   126  				PositionIndependentExecutable: false,
   127  				DynamicSharedObject:           false,
   128  				LlvmSafeStack:                 boolRef(false),
   129  				LlvmControlFlowIntegrity:      boolRef(true), // ! important !
   130  				ClangFortifySource:            boolRef(false),
   131  			},
   132  		},
   133  		{
   134  			name:    "detect fortify",
   135  			fixture: "bin/with_fortify",
   136  			want: &file.ELFSecurityFeatures{
   137  				NoExecutable:                  true,
   138  				StackCanary:                   boolRef(false),
   139  				RelocationReadOnly:            file.RelocationReadOnlyPartial,
   140  				PositionIndependentExecutable: false,
   141  				DynamicSharedObject:           false,
   142  				LlvmSafeStack:                 boolRef(false),
   143  				LlvmControlFlowIntegrity:      boolRef(false),
   144  				ClangFortifySource:            boolRef(true), // ! important !
   145  			},
   146  		},
   147  	}
   148  	for _, tt := range tests {
   149  		t.Run(tt.name, func(t *testing.T) {
   150  			f, err := elf.NewFile(readerForFixture(t, tt.fixture))
   151  			require.NoError(t, err)
   152  
   153  			got := findELFSecurityFeatures(f)
   154  
   155  			if d := cmp.Diff(tt.want, got); d != "" {
   156  				t.Errorf("findELFSecurityFeatures() mismatch (-want +got):\n%s", d)
   157  			}
   158  		})
   159  	}
   160  }
   161  
   162  func Test_elfHasEntrypoint(t *testing.T) {
   163  
   164  	readerForFixture := func(t *testing.T, fixture string) unionreader.UnionReader {
   165  		t.Helper()
   166  		f, err := os.Open(filepath.Join("test-fixtures/shared-info", fixture))
   167  		require.NoError(t, err)
   168  		return f
   169  	}
   170  
   171  	tests := []struct {
   172  		name    string
   173  		fixture string
   174  		want    bool
   175  	}{
   176  		{
   177  			name:    "shared lib",
   178  			fixture: "bin/libhello.so",
   179  			want:    false,
   180  		},
   181  		{
   182  			name:    "application",
   183  			fixture: "bin/hello_linux",
   184  			want:    true,
   185  		},
   186  	}
   187  	for _, tt := range tests {
   188  		t.Run(tt.name, func(t *testing.T) {
   189  			f, err := elf.NewFile(readerForFixture(t, tt.fixture))
   190  			require.NoError(t, err)
   191  			assert.Equal(t, tt.want, elfHasEntrypoint(f))
   192  		})
   193  	}
   194  }
   195  
   196  func Test_elfHasExports(t *testing.T) {
   197  	readerForFixture := func(t *testing.T, fixture string) unionreader.UnionReader {
   198  		t.Helper()
   199  		f, err := os.Open(filepath.Join("test-fixtures/shared-info", fixture))
   200  		require.NoError(t, err)
   201  		return f
   202  	}
   203  
   204  	tests := []struct {
   205  		name    string
   206  		fixture string
   207  		want    bool
   208  	}{
   209  		{
   210  			name:    "shared lib",
   211  			fixture: "bin/libhello.so",
   212  			want:    true,
   213  		},
   214  		{
   215  			name:    "application",
   216  			fixture: "bin/hello_linux",
   217  			want:    false,
   218  		},
   219  	}
   220  	for _, tt := range tests {
   221  		t.Run(tt.name, func(t *testing.T) {
   222  			f, err := elf.NewFile(readerForFixture(t, tt.fixture))
   223  			require.NoError(t, err)
   224  			assert.Equal(t, tt.want, elfHasExports(f))
   225  			require.NoError(t, err)
   226  		})
   227  	}
   228  }