1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package elfexec
16
17 import (
18 "debug/elf"
19 "fmt"
20 "reflect"
21 "strings"
22 "testing"
23 )
24
25 func TestGetBase(t *testing.T) {
26
27 fhExec := &elf.FileHeader{
28 Type: elf.ET_EXEC,
29 }
30 fhRel := &elf.FileHeader{
31 Type: elf.ET_REL,
32 }
33 fhDyn := &elf.FileHeader{
34 Type: elf.ET_DYN,
35 }
36 lsOffset := &elf.ProgHeader{
37 Vaddr: 0x400000,
38 Off: 0x200000,
39 }
40 kernelHeader := &elf.ProgHeader{
41 Vaddr: 0xffffffff81000000,
42 }
43 kernelAslrHeader := &elf.ProgHeader{
44 Vaddr: 0xffffffff80200000,
45 Off: 0x1000,
46 }
47
48 kernelPieAlignedHeader := &elf.ProgHeader{
49 Vaddr: 0xffff000010080000,
50 Off: 0x10000,
51 }
52
53 kernelPieUnalignedHeader := &elf.ProgHeader{
54 Vaddr: 0xffffffc010080800,
55 Off: 0x10800,
56 }
57 ppc64KernelHeader := &elf.ProgHeader{
58 Vaddr: 0xc000000000000000,
59 }
60
61 testcases := []struct {
62 label string
63 fh *elf.FileHeader
64 loadSegment *elf.ProgHeader
65 stextOffset *uint64
66 start, limit, offset uint64
67 want uint64
68 wanterr bool
69 }{
70 {"exec", fhExec, nil, nil, 0x400000, 0, 0, 0, false},
71 {"exec offset", fhExec, lsOffset, nil, 0x400000, 0x800000, 0, 0x200000, false},
72 {"exec offset 2", fhExec, lsOffset, nil, 0x200000, 0x600000, 0, 0, false},
73 {"exec nomap", fhExec, nil, nil, 0, 0, 0, 0, false},
74 {"exec kernel", fhExec, kernelHeader, uint64p(0xffffffff81000198), 0xffffffff82000198, 0xffffffff83000198, 0, 0x1000000, false},
75 {"exec kernel", fhExec, kernelHeader, uint64p(0xffffffff810002b8), 0xffffffff81000000, 0xffffffffa0000000, 0x0, 0x0, false},
76 {"exec kernel ASLR", fhExec, kernelHeader, uint64p(0xffffffff810002b8), 0xffffffff81000000, 0xffffffffa0000000, 0xffffffff81000000, 0x0, false},
77
78
79 {"exec kernel ASLR 2", fhExec, kernelAslrHeader, nil, 0xffffffff83e00000, 0xfffffffffc3fffff, 0x3c00000, 0x3c00000, false},
80 {"exec PPC64 kernel", fhExec, ppc64KernelHeader, uint64p(0xc000000000000000), 0xc000000000000000, 0xd00000001a730000, 0x0, 0x0, false},
81 {"exec chromeos kernel", fhExec, kernelHeader, uint64p(0xffffffff81000198), 0, 0x10197, 0, 0x7efffe68, false},
82 {"exec chromeos kernel 2", fhExec, kernelHeader, uint64p(0xffffffff81000198), 0, 0x10198, 0, 0x7efffe68, false},
83 {"exec chromeos kernel 3", fhExec, kernelHeader, uint64p(0xffffffff81000198), 0x198, 0x100000, 0, 0x7f000000, false},
84 {"exec chromeos kernel 4", fhExec, kernelHeader, uint64p(0xffffffff81200198), 0x198, 0x100000, 0, 0x7ee00000, false},
85 {"exec chromeos kernel unremapped", fhExec, kernelHeader, uint64p(0xffffffff810001c8), 0xffffffff834001c8, 0xffffffffc0000000, 0xffffffff834001c8, 0x2400000, false},
86 {"dyn", fhDyn, nil, nil, 0x200000, 0x300000, 0, 0x200000, false},
87 {"dyn map", fhDyn, lsOffset, nil, 0x0, 0x300000, 0, 0xFFFFFFFFFFE00000, false},
88 {"dyn nomap", fhDyn, nil, nil, 0x0, 0x0, 0, 0, false},
89 {"dyn map+offset", fhDyn, lsOffset, nil, 0x900000, 0xa00000, 0x200000, 0x500000, false},
90 {"dyn kernel", fhDyn, kernelPieAlignedHeader, uint64p(0xffff000010080000), 0xffff000010080000, 0xffffffffffffffff, 0xffff000010080000, 0, false},
91 {"dyn chromeos aslr kernel", fhDyn, kernelPieUnalignedHeader, uint64p(0xffffffc010080800), 0x800, 0xb7f800, 0, 0x3feff80000, false},
92 {"dyn chromeos aslr kernel unremapped", fhDyn, kernelPieUnalignedHeader, uint64p(0xffffffc010080800), 0xffffffdb5d680800, 0xffffffdb5e200000, 0xffffffdb5d680800, 0x1b4d600000, false},
93 {"rel", fhRel, nil, nil, 0x2000000, 0x3000000, 0, 0x2000000, false},
94 {"rel nomap", fhRel, nil, nil, 0x0, ^uint64(0), 0, 0, false},
95 {"rel offset", fhRel, nil, nil, 0x100000, 0x200000, 0x1, 0, true},
96 }
97
98 for _, tc := range testcases {
99 base, err := GetBase(tc.fh, tc.loadSegment, tc.stextOffset, tc.start, tc.limit, tc.offset)
100 if err != nil {
101 if !tc.wanterr {
102 t.Errorf("%s: want no error, got %v", tc.label, err)
103 }
104 continue
105 }
106 if tc.wanterr {
107 t.Errorf("%s: want error, got nil", tc.label)
108 continue
109 }
110 if base != tc.want {
111 t.Errorf("%s: want 0x%x, got 0x%x", tc.label, tc.want, base)
112 }
113 }
114 }
115
116 func uint64p(n uint64) *uint64 {
117 return &n
118 }
119
120 func TestFindProgHeaderForMapping(t *testing.T) {
121 buildList := func(headers []*elf.ProgHeader) (result string) {
122 builder := strings.Builder{}
123 if err := builder.WriteByte('['); err != nil {
124 t.Error("Failed to append '[' to the builder")
125 }
126 defer func() {
127 if err := builder.WriteByte(']'); err != nil {
128 t.Error("Failed to append ']' to the builder")
129 }
130 result = builder.String()
131 }()
132 if len(headers) == 0 {
133 if _, err := builder.WriteString("nil"); err != nil {
134 t.Error("Failed to append 'nil' to the builder")
135 }
136 return
137 }
138 if _, err := builder.WriteString(fmt.Sprintf("%#v", *headers[0])); err != nil {
139 t.Error("Failed to append first header to the builder")
140 }
141 for i, h := range headers[1:] {
142 if _, err := builder.WriteString(fmt.Sprintf(", %#v", *h)); err != nil {
143 t.Errorf("Failed to append header %d to the builder", i+1)
144 }
145 }
146 return
147 }
148
149
150 tinyHeaders := []elf.ProgHeader{
151 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0xc80, Memsz: 0xc80, Align: 0x200000},
152 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x1f0, Memsz: 0x1f0, Align: 0x200000},
153 }
154 tinyBadBSSHeaders := []elf.ProgHeader{
155 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0xc80, Memsz: 0xc80, Align: 0x200000},
156 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x100, Memsz: 0x1f0, Align: 0x200000},
157 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xd80, Vaddr: 0x400d80, Paddr: 0x400d80, Filesz: 0x90, Memsz: 0x90, Align: 0x200000},
158 }
159 smallHeaders := []elf.ProgHeader{
160 {Type: elf.PT_PHDR, Flags: elf.PF_R | elf.PF_X, Off: 0x40, Vaddr: 0x400040, Paddr: 0x400040, Filesz: 0x1f8, Memsz: 0x1f8, Align: 8},
161 {Type: elf.PT_INTERP, Flags: elf.PF_R, Off: 0x238, Vaddr: 0x400238, Paddr: 0x400238, Filesz: 0x1c, Memsz: 0x1c, Align: 1},
162 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0x400000, Paddr: 0x400000, Filesz: 0x6fc, Memsz: 0x6fc, Align: 0x200000},
163 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe10, Vaddr: 0x600e10, Paddr: 0x600e10, Filesz: 0x230, Memsz: 0x238, Align: 0x200000},
164 {Type: elf.PT_DYNAMIC, Flags: elf.PF_R | elf.PF_W, Off: 0xe28, Vaddr: 0x600e28, Paddr: 0x600e28, Filesz: 0x1d0, Memsz: 0x1d0, Align: 8},
165 }
166 smallBadBSSHeaders := []elf.ProgHeader{
167 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0x200000, Paddr: 0x200000, Filesz: 0x6fc, Memsz: 0x6fc, Align: 0x200000},
168 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0x700, Vaddr: 0x400700, Paddr: 0x400700, Filesz: 0x500, Memsz: 0x710, Align: 0x200000},
169 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe10, Vaddr: 0x600e10, Paddr: 0x600e10, Filesz: 0x230, Memsz: 0x238, Align: 0x200000},
170 }
171 mediumHeaders := []elf.ProgHeader{
172 {Type: elf.PT_PHDR, Flags: elf.PF_R, Off: 0x40, Vaddr: 0x40, Paddr: 0x40, Filesz: 0x268, Memsz: 0x268, Align: 8},
173 {Type: elf.PT_INTERP, Flags: elf.PF_R, Off: 0x2a8, Vaddr: 0x2a8, Paddr: 0x2a8, Filesz: 0x28, Memsz: 0x28, Align: 1},
174 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0x51800, Memsz: 0x51800, Align: 0x200000},
175 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0x51800, Vaddr: 0x251800, Paddr: 0x251800, Filesz: 0x24a8, Memsz: 0x24e8, Align: 0x200000},
176 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0x53d00, Vaddr: 0x453d00, Paddr: 0x453d00, Filesz: 0x13a58, Memsz: 0x91a198, Align: 0x200000},
177 {Type: elf.PT_TLS, Flags: elf.PF_R, Off: 0x51800, Vaddr: 0x51800, Paddr: 0x51800, Filesz: 0x0, Memsz: 0x38, Align: 0x8},
178 {Type: elf.PT_DYNAMIC, Flags: elf.PF_R | elf.PF_W, Off: 0x51d00, Vaddr: 0x251d00, Paddr: 0x251d00, Filesz: 0x1ef0, Memsz: 0x1ef0, Align: 8},
179 }
180 largeHeaders := []elf.ProgHeader{
181 {Type: elf.PT_PHDR, Flags: elf.PF_R, Off: 0x40, Vaddr: 0x40, Paddr: 0x40, Filesz: 0x268, Memsz: 0x268, Align: 8},
182 {Type: elf.PT_INTERP, Flags: elf.PF_R, Off: 0x2a8, Vaddr: 0x2a8, Paddr: 0x2a8, Filesz: 0x28, Memsz: 0x28, Align: 1},
183 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0x2ec5d2c0, Memsz: 0x2ec5d2c0, Align: 0x200000},
184 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0x2ec5d2c0, Vaddr: 0x2ee5d2c0, Paddr: 0x2ee5d2c0, Filesz: 0x1361118, Memsz: 0x1361150, Align: 0x200000},
185 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0x2ffbe440, Vaddr: 0x303be440, Paddr: 0x303be440, Filesz: 0x4637c0, Memsz: 0xc91610, Align: 0x200000},
186 {Type: elf.PT_TLS, Flags: elf.PF_R, Off: 0x2ec5d2c0, Vaddr: 0x2ee5d2c0, Paddr: 0x2ee5d2c0, Filesz: 0x120, Memsz: 0x103f8, Align: 0x40},
187 {Type: elf.PT_DYNAMIC, Flags: elf.PF_R | elf.PF_W, Off: 0x2ffbc9e0, Vaddr: 0x301bc9e0, Paddr: 0x301bc9e0, Filesz: 0x1f0, Memsz: 0x1f0, Align: 8},
188 }
189 ffmpegHeaders := []elf.ProgHeader{
190 {Type: elf.PT_PHDR, Flags: elf.PF_R, Off: 0x40, Vaddr: 0x200040, Paddr: 0x200040, Filesz: 0x1f8, Memsz: 0x1f8, Align: 8},
191 {Type: elf.PT_INTERP, Flags: elf.PF_R, Off: 0x238, Vaddr: 0x200238, Paddr: 0x200238, Filesz: 0x28, Memsz: 0x28, Align: 1},
192 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0x200000, Paddr: 0x200000, Filesz: 0x48d8410, Memsz: 0x48d8410, Align: 0x200000},
193 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0x48d8440, Vaddr: 0x4cd8440, Paddr: 0x4cd8440, Filesz: 0x18cbe0, Memsz: 0xd2fb70, Align: 0x200000},
194 {Type: elf.PT_TLS, Flags: elf.PF_R, Off: 0x48d8440, Vaddr: 0x4cd8440, Paddr: 0x4cd8440, Filesz: 0xa8, Memsz: 0x468, Align: 0x40},
195 {Type: elf.PT_DYNAMIC, Flags: elf.PF_R | elf.PF_W, Off: 0x4a63ad0, Vaddr: 0x4e63ad0, Paddr: 0x4e63ad0, Filesz: 0x200, Memsz: 0x200, Align: 8},
196 }
197 sentryHeaders := []elf.ProgHeader{
198 {Type: elf.PT_LOAD, Flags: elf.PF_X + elf.PF_R, Off: 0x0, Vaddr: 0x7f0000000000, Paddr: 0x7f0000000000, Filesz: 0xbc64d5, Memsz: 0xbc64d5, Align: 0x1000},
199 {Type: elf.PT_LOAD, Flags: elf.PF_R, Off: 0xbc7000, Vaddr: 0x7f0000bc7000, Paddr: 0x7f0000bc7000, Filesz: 0xcd6b30, Memsz: 0xcd6b30, Align: 0x1000},
200 {Type: elf.PT_LOAD, Flags: elf.PF_W + elf.PF_R, Off: 0x189e000, Vaddr: 0x7f000189e000, Paddr: 0x7f000189e000, Filesz: 0x58180, Memsz: 0x92d10, Align: 0x1000},
201 }
202
203 for _, tc := range []struct {
204 desc string
205 phdrs []elf.ProgHeader
206 pgoff uint64
207 memsz uint64
208 wantHeaders []*elf.ProgHeader
209 }{
210 {
211 desc: "no prog headers",
212 phdrs: nil,
213 pgoff: 0,
214 memsz: 0x1000,
215 wantHeaders: nil,
216 },
217 {
218 desc: "tiny file, 4KB at offset 0 matches both headers, b/178747588",
219 phdrs: tinyHeaders,
220 pgoff: 0,
221 memsz: 0x1000,
222 wantHeaders: []*elf.ProgHeader{
223 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0xc80, Memsz: 0xc80, Align: 0x200000},
224 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x1f0, Memsz: 0x1f0, Align: 0x200000},
225 },
226 },
227 {
228 desc: "tiny file, file offset 4KB matches no headers",
229 phdrs: tinyHeaders,
230 pgoff: 0x1000,
231 memsz: 0x1000,
232 wantHeaders: nil,
233 },
234 {
235 desc: "tiny file with unaligned memsz matches executable segment",
236 phdrs: tinyHeaders,
237 pgoff: 0,
238 memsz: 0xc80,
239 wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0xc80, Memsz: 0xc80, Align: 0x200000}},
240 },
241 {
242 desc: "tiny file with unaligned offset matches data segment",
243 phdrs: tinyHeaders,
244 pgoff: 0xc80,
245 memsz: 0x1000,
246 wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x1f0, Memsz: 0x1f0, Align: 0x200000}},
247 },
248 {
249 desc: "tiny bad BSS file, 4KB at offset 0 matches all three headers",
250 phdrs: tinyBadBSSHeaders,
251 pgoff: 0,
252 memsz: 0x1000,
253 wantHeaders: []*elf.ProgHeader{
254 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0xc80, Memsz: 0xc80, Align: 0x200000},
255 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x100, Memsz: 0x1f0, Align: 0x200000},
256 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xd80, Vaddr: 0x400d80, Paddr: 0x400d80, Filesz: 0x90, Memsz: 0x90, Align: 0x200000},
257 },
258 },
259 {
260 desc: "small file, offset 0, memsz 4KB matches both segments",
261 phdrs: smallHeaders,
262 pgoff: 0,
263 memsz: 0x1000,
264 wantHeaders: []*elf.ProgHeader{
265 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0x400000, Paddr: 0x400000, Filesz: 0x6fc, Memsz: 0x6fc, Align: 0x200000},
266 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe10, Vaddr: 0x600e10, Paddr: 0x600e10, Filesz: 0x230, Memsz: 0x238, Align: 0x200000},
267 },
268 },
269 {
270 desc: "small file, offset 0, memsz 8KB matches both segments",
271 phdrs: smallHeaders,
272 pgoff: 0,
273 memsz: 0x2000,
274 wantHeaders: []*elf.ProgHeader{
275 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0x400000, Paddr: 0x400000, Filesz: 0x6fc, Memsz: 0x6fc, Align: 0x200000},
276 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe10, Vaddr: 0x600e10, Paddr: 0x600e10, Filesz: 0x230, Memsz: 0x238, Align: 0x200000},
277 },
278 },
279 {
280 desc: "small file, offset 4KB matches data segment",
281 phdrs: smallHeaders,
282 pgoff: 0x1000,
283 memsz: 0x1000,
284 wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe10, Vaddr: 0x600e10, Paddr: 0x600e10, Filesz: 0x230, Memsz: 0x238, Align: 0x200000}},
285 },
286 {
287 desc: "small file, offset 8KB matches no segment",
288 phdrs: smallHeaders,
289 pgoff: 0x2000,
290 memsz: 0x1000,
291 wantHeaders: nil,
292 },
293 {
294 desc: "small bad BSS file, offset 0, memsz 4KB matches all three segments",
295 phdrs: smallBadBSSHeaders,
296 pgoff: 0,
297 memsz: 0x1000,
298 wantHeaders: []*elf.ProgHeader{
299 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0x200000, Paddr: 0x200000, Filesz: 0x6fc, Memsz: 0x6fc, Align: 0x200000},
300 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0x700, Vaddr: 0x400700, Paddr: 0x400700, Filesz: 0x500, Memsz: 0x710, Align: 0x200000},
301 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe10, Vaddr: 0x600e10, Paddr: 0x600e10, Filesz: 0x230, Memsz: 0x238, Align: 0x200000},
302 },
303 },
304 {
305 desc: "small bad BSS file, offset 0, memsz 8KB matches all three segments",
306 phdrs: smallBadBSSHeaders,
307 pgoff: 0,
308 memsz: 0x2000,
309 wantHeaders: []*elf.ProgHeader{
310 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0x200000, Paddr: 0x200000, Filesz: 0x6fc, Memsz: 0x6fc, Align: 0x200000},
311 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0x700, Vaddr: 0x400700, Paddr: 0x400700, Filesz: 0x500, Memsz: 0x710, Align: 0x200000},
312 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe10, Vaddr: 0x600e10, Paddr: 0x600e10, Filesz: 0x230, Memsz: 0x238, Align: 0x200000},
313 },
314 },
315 {
316 desc: "small bad BSS file, offset 4KB matches second data segment",
317 phdrs: smallBadBSSHeaders,
318 pgoff: 0x1000,
319 memsz: 0x1000,
320 wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe10, Vaddr: 0x600e10, Paddr: 0x600e10, Filesz: 0x230, Memsz: 0x238, Align: 0x200000}},
321 },
322 {
323 desc: "medium file large mapping that includes all address space matches executable segment, b/179920361",
324 phdrs: mediumHeaders,
325 pgoff: 0,
326 memsz: 0xd6e000,
327 wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0x51800, Memsz: 0x51800, Align: 0x200000}},
328 },
329 {
330 desc: "large file executable mapping matches executable segment",
331 phdrs: largeHeaders,
332 pgoff: 0,
333 memsz: 0x2ec5e000,
334 wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0x2ec5d2c0, Memsz: 0x2ec5d2c0, Align: 0x200000}},
335 },
336 {
337 desc: "large file first data mapping matches first data segment",
338 phdrs: largeHeaders,
339 pgoff: 0x2ec5d000,
340 memsz: 0x1362000,
341 wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0x2ec5d2c0, Vaddr: 0x2ee5d2c0, Paddr: 0x2ee5d2c0, Filesz: 0x1361118, Memsz: 0x1361150, Align: 0x200000}},
342 },
343 {
344 desc: "large file, split second data mapping matches second data segment",
345 phdrs: largeHeaders,
346 pgoff: 0x2ffbe000,
347 memsz: 0xb11000,
348 wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0x2ffbe440, Vaddr: 0x303be440, Paddr: 0x303be440, Filesz: 0x4637c0, Memsz: 0xc91610, Align: 0x200000}},
349 },
350 {
351 desc: "sentry headers, mapping for last page of executable segment matches executable segment",
352 phdrs: sentryHeaders,
353 pgoff: 0xbc6000,
354 memsz: 0x1000,
355 wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_X + elf.PF_R, Off: 0x0, Vaddr: 0x7f0000000000, Paddr: 0x7f0000000000, Filesz: 0xbc64d5, Memsz: 0xbc64d5, Align: 0x1000}},
356 },
357 {
358 desc: "ffmpeg headers, split mapping for executable segment matches executable segment, b/193176694",
359 phdrs: ffmpegHeaders,
360 pgoff: 0,
361 memsz: 0x48d8000,
362 wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0x200000, Paddr: 0x200000, Filesz: 0x48d8410, Memsz: 0x48d8410, Align: 0x200000}},
363 },
364 {
365 desc: "segments with no file bits (b/195427553), mapping for executable segment matches executable segment",
366 phdrs: []elf.ProgHeader{
367 {Type: elf.PT_LOAD, Flags: elf.PF_R, Off: 0x0, Vaddr: 0x0, Paddr: 0x0, Filesz: 0x115000, Memsz: 0x115000, Align: 0x1000},
368 {Type: elf.PT_LOAD, Flags: elf.PF_X + elf.PF_R, Off: 0x115000, Vaddr: 0x115000, Paddr: 0x115000, Filesz: 0x361e15, Memsz: 0x361e15, Align: 0x1000},
369 {Type: elf.PT_LOAD, Flags: elf.PF_W + elf.PF_R, Off: 0x0, Vaddr: 0x477000, Paddr: 0x477000, Filesz: 0x0, Memsz: 0x33c, Align: 0x1000},
370 {Type: elf.PT_LOAD, Flags: elf.PF_R, Off: 0x0, Vaddr: 0x478000, Paddr: 0x478000, Filesz: 0x0, Memsz: 0x47dc28, Align: 0x1000},
371 {Type: elf.PT_LOAD, Flags: elf.PF_R, Off: 0x477000, Vaddr: 0x8f6000, Paddr: 0x8f6000, Filesz: 0x140, Memsz: 0x140, Align: 0x1000},
372 {Type: elf.PT_LOAD, Flags: elf.PF_W + elf.PF_R, Off: 0x478000, Vaddr: 0x8f7000, Paddr: 0x8f7000, Filesz: 0x38, Memsz: 0x38, Align: 0x1000},
373 },
374 pgoff: 0x115000,
375 memsz: 0x362000,
376 wantHeaders: []*elf.ProgHeader{{Type: elf.PT_LOAD, Flags: elf.PF_X + elf.PF_R, Off: 0x115000, Vaddr: 0x115000, Paddr: 0x115000, Filesz: 0x361e15, Memsz: 0x361e15, Align: 0x1000}},
377 },
378 } {
379 t.Run(tc.desc, func(t *testing.T) {
380 gotHeaders := ProgramHeadersForMapping(tc.phdrs, tc.pgoff, tc.memsz)
381 if !reflect.DeepEqual(gotHeaders, tc.wantHeaders) {
382 t.Errorf("got program headers %q; want %q", buildList(gotHeaders), buildList(tc.wantHeaders))
383 }
384 })
385 }
386 }
387
388 func TestHeaderForFileOffset(t *testing.T) {
389 for _, tc := range []struct {
390 desc string
391 headers []*elf.ProgHeader
392 fileOffset uint64
393 wantError bool
394 want *elf.ProgHeader
395 }{
396 {
397 desc: "no headers, want error",
398 headers: nil,
399 wantError: true,
400 },
401 {
402 desc: "three headers, BSS in last segment, file offset selects first header",
403 headers: []*elf.ProgHeader{
404 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0xc80, Memsz: 0xc80, Align: 0x200000},
405 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x1f0, Memsz: 0x1f0, Align: 0x200000},
406 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe70, Vaddr: 0x400e70, Paddr: 0x400e70, Filesz: 0x90, Memsz: 0x100, Align: 0x200000},
407 },
408 fileOffset: 0xc79,
409 want: &elf.ProgHeader{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0xc80, Memsz: 0xc80, Align: 0x200000},
410 },
411 {
412 desc: "three headers, BSS in last segment, file offset selects second header",
413 headers: []*elf.ProgHeader{
414 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0xc80, Memsz: 0xc80, Align: 0x200000},
415 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x1f0, Memsz: 0x1f0, Align: 0x200000},
416 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe70, Vaddr: 0x400e70, Paddr: 0x400e70, Filesz: 0x90, Memsz: 0x100, Align: 0x200000},
417 },
418 fileOffset: 0xc80,
419 want: &elf.ProgHeader{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x1f0, Memsz: 0x1f0, Align: 0x200000},
420 },
421 {
422 desc: "three headers, BSS in last segment, file offset selects third header",
423 headers: []*elf.ProgHeader{
424 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0xc80, Memsz: 0xc80, Align: 0x200000},
425 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x1f0, Memsz: 0x1f0, Align: 0x200000},
426 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe70, Vaddr: 0x400e70, Paddr: 0x400e70, Filesz: 0x90, Memsz: 0x100, Align: 0x200000},
427 },
428 fileOffset: 0xef0,
429 want: &elf.ProgHeader{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe70, Vaddr: 0x400e70, Paddr: 0x400e70, Filesz: 0x90, Memsz: 0x100, Align: 0x200000},
430 },
431 {
432 desc: "three headers, BSS in last segment, file offset in uninitialized section selects third header",
433 headers: []*elf.ProgHeader{
434 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0xc80, Memsz: 0xc80, Align: 0x200000},
435 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x1f0, Memsz: 0x1f0, Align: 0x200000},
436 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe70, Vaddr: 0x400e70, Paddr: 0x400e70, Filesz: 0x90, Memsz: 0x100, Align: 0x200000},
437 },
438 fileOffset: 0xf40,
439 want: &elf.ProgHeader{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe70, Vaddr: 0x400e70, Paddr: 0x400e70, Filesz: 0x90, Memsz: 0x100, Align: 0x200000},
440 },
441 {
442 desc: "three headers, BSS in last segment, file offset past any segment gives error",
443 headers: []*elf.ProgHeader{
444 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0xc80, Memsz: 0xc80, Align: 0x200000},
445 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x1f0, Memsz: 0x1f0, Align: 0x200000},
446 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xe70, Vaddr: 0x400e70, Paddr: 0x400e70, Filesz: 0x90, Memsz: 0x100, Align: 0x200000},
447 },
448 fileOffset: 0xf70,
449 wantError: true,
450 },
451 {
452 desc: "three headers, BSS in second segment, file offset in mapped section selects second header",
453 headers: []*elf.ProgHeader{
454 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0xc80, Memsz: 0xc80, Align: 0x200000},
455 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x100, Memsz: 0x1f0, Align: 0x200000},
456 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xd80, Vaddr: 0x400d80, Paddr: 0x400d80, Filesz: 0x100, Memsz: 0x100, Align: 0x200000},
457 },
458 fileOffset: 0xd79,
459 want: &elf.ProgHeader{Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x100, Memsz: 0x1f0, Align: 0x200000},
460 },
461 {
462 desc: "three headers, BSS in second segment, file offset in unmapped section gives error",
463 headers: []*elf.ProgHeader{
464 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_X, Off: 0, Vaddr: 0, Paddr: 0, Filesz: 0xc80, Memsz: 0xc80, Align: 0x200000},
465 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xc80, Vaddr: 0x200c80, Paddr: 0x200c80, Filesz: 0x100, Memsz: 0x1f0, Align: 0x200000},
466 {Type: elf.PT_LOAD, Flags: elf.PF_R | elf.PF_W, Off: 0xd80, Vaddr: 0x400d80, Paddr: 0x400d80, Filesz: 0x100, Memsz: 0x100, Align: 0x200000},
467 },
468 fileOffset: 0xd80,
469 wantError: true,
470 },
471 } {
472 t.Run(tc.desc, func(t *testing.T) {
473 got, err := HeaderForFileOffset(tc.headers, tc.fileOffset)
474 if (err != nil) != tc.wantError {
475 t.Errorf("got error %v, want any error=%v", err, tc.wantError)
476 }
477 if err != nil {
478 return
479 }
480 if !reflect.DeepEqual(got, tc.want) {
481 t.Errorf("got program header %#v, want %#v", got, tc.want)
482 }
483 })
484 }
485 }
486
View as plain text