1// Copyright 2014 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 15package elfexec 16 17import ( 18 "debug/elf" 19 "fmt" 20 "reflect" 21 "strings" 22 "testing" 23) 24 25func 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 // Kernel PIE header with vaddr aligned to a 4k boundary 48 kernelPieAlignedHeader := &elf.ProgHeader{ 49 Vaddr: 0xffff000010080000, 50 Off: 0x10000, 51 } 52 // Kernel PIE header with vaddr that doesn't fall on a 4k boundary 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 // TODO(aalexand): Figure out where this test case exactly comes from and 78 // whether it's still relevant. 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 116func uint64p(n uint64) *uint64 { 117 return &n 118} 119 120func 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 // Variuos ELF program headers for unit tests. 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 388func 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