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, then injects 16// the address of the _start function for the linker_wrapper to use. 17package main 18 19import ( 20 "debug/elf" 21 "flag" 22 "fmt" 23 "io" 24 "os" 25 26 "android/soong/symbol_inject" 27) 28 29func main() { 30 var inputFile, linkerFile, outputFile string 31 32 flag.StringVar(&inputFile, "i", "", "Input file") 33 flag.StringVar(&linkerFile, "l", "", "Linker file") 34 flag.StringVar(&outputFile, "o", "", "Output file") 35 flag.Parse() 36 37 if inputFile == "" || linkerFile == "" || outputFile == "" || flag.NArg() != 0 { 38 flag.Usage() 39 os.Exit(1) 40 } 41 42 r, err := os.Open(inputFile) 43 if err != nil { 44 fmt.Fprintln(os.Stderr, err.Error()) 45 os.Exit(2) 46 } 47 defer r.Close() 48 49 file, err := symbol_inject.OpenFile(r) 50 if err != nil { 51 fmt.Fprintln(os.Stderr, err.Error()) 52 os.Exit(3) 53 } 54 55 linker, err := elf.Open(linkerFile) 56 if err != nil { 57 fmt.Fprintln(os.Stderr, err.Error()) 58 os.Exit(4) 59 } 60 61 start_addr, err := parseElf(r, linker) 62 if err != nil { 63 fmt.Fprintln(os.Stderr, err.Error()) 64 os.Exit(5) 65 } 66 67 w, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777) 68 if err != nil { 69 fmt.Fprintln(os.Stderr, err.Error()) 70 os.Exit(6) 71 } 72 defer w.Close() 73 74 err = symbol_inject.InjectUint64Symbol(file, w, "__dlwrap_original_start", start_addr) 75 if err != nil { 76 fmt.Fprintln(os.Stderr, err.Error()) 77 os.Exit(7) 78 } 79} 80 81// Check the ELF file, and return the address to the _start function 82func parseElf(r io.ReaderAt, linker *elf.File) (uint64, error) { 83 file, err := elf.NewFile(r) 84 if err != nil { 85 return 0, err 86 } 87 88 symbols, err := file.Symbols() 89 if err != nil { 90 return 0, err 91 } 92 93 for _, prog := range file.Progs { 94 if prog.Type == elf.PT_INTERP { 95 return 0, fmt.Errorf("File should not have a PT_INTERP header") 96 } 97 } 98 99 if dlwrap_start, err := findSymbol(symbols, "__dlwrap__start"); err != nil { 100 return 0, err 101 } else if dlwrap_start.Value != file.Entry { 102 return 0, fmt.Errorf("Expected file entry(0x%x) to point to __dlwrap_start(0x%x)", 103 file.Entry, dlwrap_start.Value) 104 } 105 106 err = checkLinker(file, linker, symbols) 107 if err != nil { 108 return 0, err 109 } 110 111 start, err := findSymbol(symbols, "_start") 112 if err != nil { 113 return 0, fmt.Errorf("Failed to find _start symbol") 114 } 115 return start.Value, nil 116} 117 118func findSymbol(symbols []elf.Symbol, name string) (elf.Symbol, error) { 119 for _, sym := range symbols { 120 if sym.Name == name { 121 return sym, nil 122 } 123 } 124 return elf.Symbol{}, fmt.Errorf("Failed to find symbol %q", name) 125} 126 127// Check that all of the PT_LOAD segments have been embedded properly 128func checkLinker(file, linker *elf.File, fileSyms []elf.Symbol) error { 129 dlwrap_linker_offset, err := findSymbol(fileSyms, "__dlwrap_linker_offset") 130 if err != nil { 131 return err 132 } 133 134 for i, lprog := range linker.Progs { 135 if lprog.Type != elf.PT_LOAD { 136 continue 137 } 138 139 laddr := lprog.Vaddr + dlwrap_linker_offset.Value 140 141 found := false 142 for _, prog := range file.Progs { 143 if prog.Type != elf.PT_LOAD { 144 continue 145 } 146 147 if laddr < prog.Vaddr || laddr > prog.Vaddr+prog.Memsz { 148 continue 149 } 150 found = true 151 152 if lprog.Flags != prog.Flags { 153 return fmt.Errorf("Linker prog %d (0x%x) flags (%s) do not match (%s)", 154 i, lprog.Vaddr, lprog.Flags, prog.Flags) 155 } 156 157 if laddr+lprog.Memsz > prog.Vaddr+prog.Filesz { 158 return fmt.Errorf("Linker prog %d (0x%x) not fully present (0x%x > 0x%x)", 159 i, lprog.Vaddr, laddr+lprog.Memsz, prog.Vaddr+prog.Filesz) 160 } 161 } 162 if !found { 163 return fmt.Errorf("Linker prog %d (0x%x) not found at offset 0x%x", 164 i, lprog.Vaddr, dlwrap_linker_offset.Value) 165 } 166 } 167 168 return nil 169} 170