xref: /aosp_15_r20/build/soong/cmd/host_bionic_verify/host_bionic_verify.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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