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 15// Verifies a host bionic executable with an embedded linker. 16package main 17 18import ( 19 "debug/elf" 20 "flag" 21 "fmt" 22 "io" 23 "os" 24) 25 26func main() { 27 var inputFile, linkerFile string 28 29 flag.StringVar(&inputFile, "i", "", "Input file") 30 flag.StringVar(&linkerFile, "l", "", "Linker file") 31 flag.Parse() 32 33 if inputFile == "" || linkerFile == "" || flag.NArg() != 0 { 34 flag.Usage() 35 os.Exit(1) 36 } 37 38 r, err := os.Open(inputFile) 39 if err != nil { 40 fmt.Fprintln(os.Stderr, err.Error()) 41 os.Exit(2) 42 } 43 defer r.Close() 44 45 linker, err := elf.Open(linkerFile) 46 if err != nil { 47 fmt.Fprintln(os.Stderr, err.Error()) 48 os.Exit(4) 49 } 50 51 err = checkElf(r, linker) 52 if err != nil { 53 fmt.Fprintln(os.Stderr, err.Error()) 54 os.Exit(5) 55 } 56} 57 58// Check the ELF file, and return the address to the _start function 59func checkElf(r io.ReaderAt, linker *elf.File) error { 60 file, err := elf.NewFile(r) 61 if err != nil { 62 return err 63 } 64 65 symbols, err := file.Symbols() 66 if err != nil { 67 return err 68 } 69 70 for _, prog := range file.Progs { 71 if prog.Type == elf.PT_INTERP { 72 return fmt.Errorf("File should not have a PT_INTERP header") 73 } 74 } 75 76 if dlwrap_start, err := findSymbol(symbols, "__dlwrap__start"); err != nil { 77 return err 78 } else if dlwrap_start.Value != file.Entry { 79 return fmt.Errorf("Expected file entry(0x%x) to point to __dlwrap_start(0x%x)", 80 file.Entry, dlwrap_start.Value) 81 } 82 83 err = checkLinker(file, linker, symbols) 84 if err != nil { 85 return fmt.Errorf("Linker executable failed verification against app embedded linker: %s\n"+ 86 "linker might not be in sync with crtbegin_dynamic.o.", 87 err) 88 } 89 90 return nil 91} 92 93func findSymbol(symbols []elf.Symbol, name string) (elf.Symbol, error) { 94 for _, sym := range symbols { 95 if sym.Name == name { 96 return sym, nil 97 } 98 } 99 return elf.Symbol{}, fmt.Errorf("Failed to find symbol %q", name) 100} 101 102// Check that all of the PT_LOAD segments have been embedded properly 103func checkLinker(file, linker *elf.File, fileSyms []elf.Symbol) error { 104 dlwrapLinkerOffset, err := findSymbol(fileSyms, "__dlwrap_linker_offset") 105 if err != nil { 106 return err 107 } 108 109 for i, lprog := range linker.Progs { 110 if lprog.Type != elf.PT_LOAD { 111 continue 112 } 113 114 laddr := lprog.Vaddr + dlwrapLinkerOffset.Value 115 116 found := false 117 for _, prog := range file.Progs { 118 if prog.Type != elf.PT_LOAD { 119 continue 120 } 121 122 if laddr < prog.Vaddr || laddr > prog.Vaddr+prog.Memsz { 123 continue 124 } 125 found = true 126 127 if lprog.Flags != prog.Flags { 128 return fmt.Errorf("Linker prog %d (0x%x) flags (%s) do not match (%s)", 129 i, lprog.Vaddr, lprog.Flags, prog.Flags) 130 } 131 132 if laddr+lprog.Memsz > prog.Vaddr+prog.Filesz { 133 return fmt.Errorf("Linker prog %d (0x%x) not fully present (0x%x > 0x%x)", 134 i, lprog.Vaddr, laddr+lprog.Memsz, prog.Vaddr+prog.Filesz) 135 } 136 } 137 if !found { 138 return fmt.Errorf("Linker prog %d (0x%x) not found at offset 0x%x", 139 i, lprog.Vaddr, dlwrapLinkerOffset.Value) 140 } 141 } 142 143 return nil 144} 145