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, fmt.Errorf("Linker executable failed verification against app embedded linker: %s\n"+ 109 "linker might not be in sync with crtbegin_dynamic.o.", 110 err) 111 } 112 113 start, err := findSymbol(symbols, "_start") 114 if err != nil { 115 return 0, fmt.Errorf("Failed to find _start symbol") 116 } 117 return start.Value, nil 118} 119 120func findSymbol(symbols []elf.Symbol, name string) (elf.Symbol, error) { 121 for _, sym := range symbols { 122 if sym.Name == name { 123 return sym, nil 124 } 125 } 126 return elf.Symbol{}, fmt.Errorf("Failed to find symbol %q", name) 127} 128 129// Check that all of the PT_LOAD segments have been embedded properly 130func checkLinker(file, linker *elf.File, fileSyms []elf.Symbol) error { 131 dlwrap_linker_offset, err := findSymbol(fileSyms, "__dlwrap_linker_offset") 132 if err != nil { 133 return err 134 } 135 136 for i, lprog := range linker.Progs { 137 if lprog.Type != elf.PT_LOAD { 138 continue 139 } 140 141 laddr := lprog.Vaddr + dlwrap_linker_offset.Value 142 143 found := false 144 for _, prog := range file.Progs { 145 if prog.Type != elf.PT_LOAD { 146 continue 147 } 148 149 if laddr < prog.Vaddr || laddr > prog.Vaddr+prog.Memsz { 150 continue 151 } 152 found = true 153 154 if lprog.Flags != prog.Flags { 155 return fmt.Errorf("Linker prog %d (0x%x) flags (%s) do not match (%s)", 156 i, lprog.Vaddr, lprog.Flags, prog.Flags) 157 } 158 159 if laddr+lprog.Memsz > prog.Vaddr+prog.Filesz { 160 return fmt.Errorf("Linker prog %d (0x%x) not fully present (0x%x > 0x%x)", 161 i, lprog.Vaddr, laddr+lprog.Memsz, prog.Vaddr+prog.Filesz) 162 } 163 } 164 if !found { 165 return fmt.Errorf("Linker prog %d (0x%x) not found at offset 0x%x", 166 i, lprog.Vaddr, dlwrap_linker_offset.Value) 167 } 168 } 169 170 return nil 171} 172