1// Copyright 2018 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package main 16 17import ( 18 "debug/elf" 19 "fmt" 20 "testing" 21) 22 23// prog is a shortcut to fill out a elf.Prog structure 24func prog(flags elf.ProgFlag, offset, addr, filesz, memsz uint64) *elf.Prog { 25 return &elf.Prog{ 26 ProgHeader: elf.ProgHeader{ 27 Type: elf.PT_LOAD, 28 Flags: flags, 29 Off: offset, 30 Vaddr: addr, 31 Paddr: addr, 32 Filesz: filesz, 33 Memsz: memsz, 34 }, 35 } 36} 37 38// linkerGold returns an example elf.File from a linker binary that was linked 39// with gold. 40func linkerGold() *elf.File { 41 return &elf.File{ 42 Progs: []*elf.Prog{ 43 prog(elf.PF_R|elf.PF_X, 0, 0, 0xd0fac, 0xd0fac), 44 prog(elf.PF_R|elf.PF_W, 0xd1050, 0xd2050, 0x6890, 0xd88c), 45 }, 46 } 47} 48 49// fileGold returns an example elf binary with a properly embedded linker. The 50// embedded linker was the one returned by linkerGold. 51func fileGold() *elf.File { 52 return &elf.File{ 53 Progs: []*elf.Prog{ 54 prog(elf.PF_R, 0, 0, 0x2e0, 0x2e0), 55 prog(elf.PF_R|elf.PF_X, 0x1000, 0x1000, 0xd0fac, 0xd0fac), 56 prog(elf.PF_R|elf.PF_W, 0xd2050, 0xd3050, 0xd88c, 0xd88c), 57 prog(elf.PF_R, 0xe0000, 0xe1000, 0x10e4, 0x10e4), 58 prog(elf.PF_R|elf.PF_X, 0xe2000, 0xe3000, 0x1360, 0x1360), 59 prog(elf.PF_R|elf.PF_W, 0xe4000, 0xe5000, 0x1358, 0x1358), 60 }, 61 } 62} 63 64// linkerLld returns an example elf.File from a linker binary that was linked 65// with lld. 66func linkerLld() *elf.File { 67 return &elf.File{ 68 Progs: []*elf.Prog{ 69 prog(elf.PF_R, 0, 0, 0x3c944, 0x3c944), 70 prog(elf.PF_R|elf.PF_X, 0x3d000, 0x3d000, 0x946fa, 0x946fa), 71 prog(elf.PF_R|elf.PF_W, 0xd2000, 0xd2000, 0x7450, 0xf778), 72 }, 73 } 74} 75 76// fileGold returns an example elf binary with a properly embedded linker. The 77// embedded linker was the one returned by linkerLld. 78func fileLld() *elf.File { 79 return &elf.File{ 80 Progs: []*elf.Prog{ 81 prog(elf.PF_R, 0, 0, 0x3d944, 0x3d944), 82 prog(elf.PF_R|elf.PF_X, 0x3e000, 0x3e000, 0x946fa, 0x946fa), 83 prog(elf.PF_R|elf.PF_W, 0xd3000, 0xd3000, 0xf778, 0xf778), 84 prog(elf.PF_R, 0xe3000, 0xe3000, 0x10e4, 0x10e4), 85 prog(elf.PF_R|elf.PF_X, 0xe5000, 0xe5000, 0x1360, 0x1360), 86 prog(elf.PF_R|elf.PF_W, 0xe7000, 0xe7000, 0x1358, 0x1358), 87 }, 88 } 89} 90 91// linkerOffset returns the symbol representing the linker offset used by both 92// fileGold and fileLld 93func linkerOffset() []elf.Symbol { 94 return []elf.Symbol{ 95 elf.Symbol{ 96 Name: "__dlwrap_linker_offset", 97 Value: 0x1000, 98 }, 99 } 100} 101 102func TestCheckLinker(t *testing.T) { 103 cases := []struct { 104 name string 105 err error 106 file func() *elf.File 107 linker func() *elf.File 108 }{ 109 { 110 name: "good gold-linked linker", 111 file: fileGold, 112 linker: linkerGold, 113 }, 114 { 115 name: "good lld-linked linker", 116 file: fileLld, 117 linker: linkerLld, 118 }, 119 { 120 name: "truncated RO section", 121 err: fmt.Errorf("Linker prog 0 (0x0) not fully present (0x3d944 > 0x3d943)"), 122 file: func() *elf.File { 123 f := fileLld() 124 f.Progs[0].Filesz -= 1 125 f.Progs[0].Memsz -= 1 126 return f 127 }, 128 linker: linkerLld, 129 }, 130 } 131 132 for _, tc := range cases { 133 t.Run(tc.name, func(t *testing.T) { 134 err := checkLinker(tc.file(), tc.linker(), linkerOffset()) 135 if tc.err == nil { 136 if err != nil { 137 t.Fatalf("No error expected, but got: %v", err) 138 } 139 } else if err == nil { 140 t.Fatalf("Returned no error, but wanted: %v", tc.err) 141 } else if err.Error() != tc.err.Error() { 142 t.Fatalf("Different error found:\nwant: %v\n got: %v", tc.err, err) 143 } 144 }) 145 } 146} 147