github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/sentry/loader/elf.go (about) 1 // Copyright 2018 The gVisor Authors. 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 package loader 16 17 import ( 18 "bytes" 19 "debug/elf" 20 "fmt" 21 "io" 22 23 "github.com/ttpreport/gvisor-ligolo/pkg/abi" 24 "github.com/ttpreport/gvisor-ligolo/pkg/abi/linux" 25 "github.com/ttpreport/gvisor-ligolo/pkg/context" 26 "github.com/ttpreport/gvisor-ligolo/pkg/cpuid" 27 "github.com/ttpreport/gvisor-ligolo/pkg/errors/linuxerr" 28 "github.com/ttpreport/gvisor-ligolo/pkg/hostarch" 29 "github.com/ttpreport/gvisor-ligolo/pkg/log" 30 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/arch" 31 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/limits" 32 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/memmap" 33 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/mm" 34 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/vfs" 35 "github.com/ttpreport/gvisor-ligolo/pkg/usermem" 36 ) 37 38 const ( 39 // elfMagic identifies an ELF file. 40 elfMagic = "\x7fELF" 41 42 // maxTotalPhdrSize is the maximum combined size of all program 43 // headers. Linux limits this to one page. 44 maxTotalPhdrSize = hostarch.PageSize 45 ) 46 47 var ( 48 // header64Size is the size of elf.Header64. 49 header64Size = (*linux.ElfHeader64)(nil).SizeBytes() 50 51 // Prog64Size is the size of elf.Prog64. 52 prog64Size = (*linux.ElfProg64)(nil).SizeBytes() 53 ) 54 55 func progFlagsAsPerms(f elf.ProgFlag) hostarch.AccessType { 56 var p hostarch.AccessType 57 if f&elf.PF_R == elf.PF_R { 58 p.Read = true 59 } 60 if f&elf.PF_W == elf.PF_W { 61 p.Write = true 62 } 63 if f&elf.PF_X == elf.PF_X { 64 p.Execute = true 65 } 66 return p 67 } 68 69 // elfInfo contains the metadata needed to load an ELF binary. 70 type elfInfo struct { 71 // os is the target OS of the ELF. 72 os abi.OS 73 74 // arch is the target architecture of the ELF. 75 arch arch.Arch 76 77 // entry is the program entry point. 78 entry hostarch.Addr 79 80 // phdrs are the program headers. 81 phdrs []elf.ProgHeader 82 83 // phdrSize is the size of a single program header in the ELF. 84 phdrSize int 85 86 // phdrOff is the offset of the program headers in the file. 87 phdrOff uint64 88 89 // sharedObject is true if the ELF represents a shared object. 90 sharedObject bool 91 } 92 93 type fullReader interface { 94 // ReadFull is the same as vfs.FileDescription.ReadFull. 95 ReadFull(ctx context.Context, dst usermem.IOSequence, offset int64) (int64, error) 96 } 97 98 // parseHeader parse the ELF header, verifying that this is a supported ELF 99 // file and returning the ELF program headers. 100 // 101 // This is similar to elf.NewFile, except that it is more strict about what it 102 // accepts from the ELF, and it doesn't parse unnecessary parts of the file. 103 func parseHeader(ctx context.Context, f fullReader) (elfInfo, error) { 104 // Check ident first; it will tell us the endianness of the rest of the 105 // structs. 106 var ident [elf.EI_NIDENT]byte 107 _, err := f.ReadFull(ctx, usermem.BytesIOSequence(ident[:]), 0) 108 if err != nil { 109 log.Infof("Error reading ELF ident: %v", err) 110 // The entire ident array always exists. 111 if err == io.EOF || err == io.ErrUnexpectedEOF { 112 err = linuxerr.ENOEXEC 113 } 114 return elfInfo{}, err 115 } 116 117 // Only some callers pre-check the ELF magic. 118 if !bytes.Equal(ident[:len(elfMagic)], []byte(elfMagic)) { 119 log.Infof("File is not an ELF") 120 return elfInfo{}, linuxerr.ENOEXEC 121 } 122 123 // We only support 64-bit, little endian binaries 124 if class := elf.Class(ident[elf.EI_CLASS]); class != elf.ELFCLASS64 { 125 log.Infof("Unsupported ELF class: %v", class) 126 return elfInfo{}, linuxerr.ENOEXEC 127 } 128 if endian := elf.Data(ident[elf.EI_DATA]); endian != elf.ELFDATA2LSB { 129 log.Infof("Unsupported ELF endianness: %v", endian) 130 return elfInfo{}, linuxerr.ENOEXEC 131 } 132 133 if version := elf.Version(ident[elf.EI_VERSION]); version != elf.EV_CURRENT { 134 log.Infof("Unsupported ELF version: %v", version) 135 return elfInfo{}, linuxerr.ENOEXEC 136 } 137 // EI_OSABI is ignored by Linux, which is the only OS supported. 138 os := abi.Linux 139 140 var hdr linux.ElfHeader64 141 hdrBuf := make([]byte, header64Size) 142 _, err = f.ReadFull(ctx, usermem.BytesIOSequence(hdrBuf), 0) 143 if err != nil { 144 log.Infof("Error reading ELF header: %v", err) 145 // The entire header always exists. 146 if err == io.EOF || err == io.ErrUnexpectedEOF { 147 err = linuxerr.ENOEXEC 148 } 149 return elfInfo{}, err 150 } 151 hdr.UnmarshalUnsafe(hdrBuf) 152 153 // We support amd64 and arm64. 154 var a arch.Arch 155 switch machine := elf.Machine(hdr.Machine); machine { 156 case elf.EM_X86_64: 157 a = arch.AMD64 158 case elf.EM_AARCH64: 159 a = arch.ARM64 160 default: 161 log.Infof("Unsupported ELF machine %d", machine) 162 return elfInfo{}, linuxerr.ENOEXEC 163 } 164 165 var sharedObject bool 166 elfType := elf.Type(hdr.Type) 167 switch elfType { 168 case elf.ET_EXEC: 169 sharedObject = false 170 case elf.ET_DYN: 171 sharedObject = true 172 default: 173 log.Infof("Unsupported ELF type %v", elfType) 174 return elfInfo{}, linuxerr.ENOEXEC 175 } 176 177 if int(hdr.Phentsize) != prog64Size { 178 log.Infof("Unsupported phdr size %d", hdr.Phentsize) 179 return elfInfo{}, linuxerr.ENOEXEC 180 } 181 totalPhdrSize := prog64Size * int(hdr.Phnum) 182 if totalPhdrSize < prog64Size { 183 log.Warningf("No phdrs or total phdr size overflows: prog64Size: %d phnum: %d", prog64Size, int(hdr.Phnum)) 184 return elfInfo{}, linuxerr.ENOEXEC 185 } 186 if totalPhdrSize > maxTotalPhdrSize { 187 log.Infof("Too many phdrs (%d): total size %d > %d", hdr.Phnum, totalPhdrSize, maxTotalPhdrSize) 188 return elfInfo{}, linuxerr.ENOEXEC 189 } 190 if int64(hdr.Phoff) < 0 || int64(hdr.Phoff+uint64(totalPhdrSize)) < 0 { 191 ctx.Infof("Unsupported phdr offset %d", hdr.Phoff) 192 return elfInfo{}, linuxerr.ENOEXEC 193 } 194 195 phdrBuf := make([]byte, totalPhdrSize) 196 _, err = f.ReadFull(ctx, usermem.BytesIOSequence(phdrBuf), int64(hdr.Phoff)) 197 if err != nil { 198 log.Infof("Error reading ELF phdrs: %v", err) 199 // If phdrs were specified, they should all exist. 200 if err == io.EOF || err == io.ErrUnexpectedEOF { 201 err = linuxerr.ENOEXEC 202 } 203 return elfInfo{}, err 204 } 205 206 phdrs := make([]elf.ProgHeader, hdr.Phnum) 207 for i := range phdrs { 208 var prog64 linux.ElfProg64 209 phdrBuf = prog64.UnmarshalUnsafe(phdrBuf) 210 phdrs[i] = elf.ProgHeader{ 211 Type: elf.ProgType(prog64.Type), 212 Flags: elf.ProgFlag(prog64.Flags), 213 Off: prog64.Off, 214 Vaddr: prog64.Vaddr, 215 Paddr: prog64.Paddr, 216 Filesz: prog64.Filesz, 217 Memsz: prog64.Memsz, 218 Align: prog64.Align, 219 } 220 } 221 222 return elfInfo{ 223 os: os, 224 arch: a, 225 entry: hostarch.Addr(hdr.Entry), 226 phdrs: phdrs, 227 phdrOff: hdr.Phoff, 228 phdrSize: prog64Size, 229 sharedObject: sharedObject, 230 }, nil 231 } 232 233 // mapSegment maps a phdr into the Task. offset is the offset to apply to 234 // phdr.Vaddr. 235 func mapSegment(ctx context.Context, m *mm.MemoryManager, fd *vfs.FileDescription, phdr *elf.ProgHeader, offset hostarch.Addr) error { 236 // We must make a page-aligned mapping. 237 adjust := hostarch.Addr(phdr.Vaddr).PageOffset() 238 239 addr, ok := offset.AddLength(phdr.Vaddr) 240 if !ok { 241 // If offset != 0 we should have ensured this would fit. 242 ctx.Warningf("Computed segment load address overflows: %#x + %#x", phdr.Vaddr, offset) 243 return linuxerr.ENOEXEC 244 } 245 addr -= hostarch.Addr(adjust) 246 247 fileSize := phdr.Filesz + adjust 248 if fileSize < phdr.Filesz { 249 ctx.Infof("Computed segment file size overflows: %#x + %#x", phdr.Filesz, adjust) 250 return linuxerr.ENOEXEC 251 } 252 ms, ok := hostarch.Addr(fileSize).RoundUp() 253 if !ok { 254 ctx.Infof("fileSize %#x too large", fileSize) 255 return linuxerr.ENOEXEC 256 } 257 mapSize := uint64(ms) 258 259 if mapSize > 0 { 260 // This must result in a page-aligned offset. i.e., the original 261 // phdr.Off must have the same alignment as phdr.Vaddr. If that is not 262 // true, MMap will reject the mapping. 263 fileOffset := phdr.Off - adjust 264 265 prot := progFlagsAsPerms(phdr.Flags) 266 mopts := memmap.MMapOpts{ 267 Length: mapSize, 268 Offset: fileOffset, 269 Addr: addr, 270 Fixed: true, 271 // Linux will happily allow conflicting segments to map over 272 // one another. 273 Unmap: true, 274 Private: true, 275 Perms: prot, 276 MaxPerms: hostarch.AnyAccess, 277 } 278 defer func() { 279 if mopts.MappingIdentity != nil { 280 mopts.MappingIdentity.DecRef(ctx) 281 } 282 }() 283 if err := fd.ConfigureMMap(ctx, &mopts); err != nil { 284 ctx.Infof("File is not memory-mappable: %v", err) 285 return err 286 } 287 if _, err := m.MMap(ctx, mopts); err != nil { 288 ctx.Infof("Error mapping PT_LOAD segment %+v at %#x: %v", phdr, addr, err) 289 return err 290 } 291 292 // We need to clear the end of the last page that exceeds fileSize so 293 // we don't map part of the file beyond fileSize. 294 // 295 // Note that Linux *does not* clear the portion of the first page 296 // before phdr.Off. 297 if mapSize > fileSize { 298 zeroAddr, ok := addr.AddLength(fileSize) 299 if !ok { 300 panic(fmt.Sprintf("successfully mmaped address overflows? %#x + %#x", addr, fileSize)) 301 } 302 zeroSize := int64(mapSize - fileSize) 303 if zeroSize < 0 { 304 panic(fmt.Sprintf("zeroSize too big? %#x", uint64(zeroSize))) 305 } 306 if _, err := m.ZeroOut(ctx, zeroAddr, zeroSize, usermem.IOOpts{IgnorePermissions: true}); err != nil { 307 ctx.Warningf("Failed to zero end of page [%#x, %#x): %v", zeroAddr, zeroAddr+hostarch.Addr(zeroSize), err) 308 return err 309 } 310 } 311 } 312 313 memSize := phdr.Memsz + adjust 314 if memSize < phdr.Memsz { 315 ctx.Infof("Computed segment mem size overflows: %#x + %#x", phdr.Memsz, adjust) 316 return linuxerr.ENOEXEC 317 } 318 319 // Allocate more anonymous pages if necessary. 320 if mapSize < memSize { 321 anonAddr, ok := addr.AddLength(mapSize) 322 if !ok { 323 panic(fmt.Sprintf("anonymous memory doesn't fit in pre-sized range? %#x + %#x", addr, mapSize)) 324 } 325 anonSize, ok := hostarch.Addr(memSize - mapSize).RoundUp() 326 if !ok { 327 ctx.Infof("extra anon pages too large: %#x", memSize-mapSize) 328 return linuxerr.ENOEXEC 329 } 330 331 // N.B. Linux uses vm_brk_flags to map these pages, which only 332 // honors the X bit, always mapping at least RW. ignoring These 333 // pages are not included in the final brk region. 334 prot := hostarch.ReadWrite 335 if phdr.Flags&elf.PF_X == elf.PF_X { 336 prot.Execute = true 337 } 338 339 if _, err := m.MMap(ctx, memmap.MMapOpts{ 340 Length: uint64(anonSize), 341 Addr: anonAddr, 342 // Fixed without Unmap will fail the mmap if something is 343 // already at addr. 344 Fixed: true, 345 Private: true, 346 Perms: prot, 347 MaxPerms: hostarch.AnyAccess, 348 }); err != nil { 349 ctx.Infof("Error mapping PT_LOAD segment %v anonymous memory: %v", phdr, err) 350 return err 351 } 352 } 353 354 return nil 355 } 356 357 // loadedELF describes an ELF that has been successfully loaded. 358 type loadedELF struct { 359 // os is the target OS of the ELF. 360 os abi.OS 361 362 // arch is the target architecture of the ELF. 363 arch arch.Arch 364 365 // entry is the entry point of the ELF. 366 entry hostarch.Addr 367 368 // start is the end of the ELF. 369 start hostarch.Addr 370 371 // end is the end of the ELF. 372 end hostarch.Addr 373 374 // interpter is the path to the ELF interpreter. 375 interpreter string 376 377 // phdrAddr is the address of the ELF program headers. 378 phdrAddr hostarch.Addr 379 380 // phdrSize is the size of a single program header in the ELF. 381 phdrSize int 382 383 // phdrNum is the number of program headers. 384 phdrNum int 385 386 // auxv contains a subset of ELF-specific auxiliary vector entries: 387 // * AT_PHDR 388 // * AT_PHENT 389 // * AT_PHNUM 390 // * AT_BASE 391 // * AT_ENTRY 392 auxv arch.Auxv 393 } 394 395 // loadParsedELF loads f into mm. 396 // 397 // info is the parsed elfInfo from the header. 398 // 399 // It does not load the ELF interpreter, or return any auxv entries. 400 // 401 // Preconditions: f is an ELF file. 402 func loadParsedELF(ctx context.Context, m *mm.MemoryManager, fd *vfs.FileDescription, info elfInfo, sharedLoadOffset hostarch.Addr) (loadedELF, error) { 403 first := true 404 var start, end hostarch.Addr 405 var interpreter string 406 for _, phdr := range info.phdrs { 407 switch phdr.Type { 408 case elf.PT_LOAD: 409 vaddr := hostarch.Addr(phdr.Vaddr) 410 if first { 411 first = false 412 start = vaddr 413 } 414 if vaddr < end { 415 // NOTE(b/37474556): Linux allows out-of-order 416 // segments, in violation of the spec. 417 ctx.Infof("PT_LOAD headers out-of-order. %#x < %#x", vaddr, end) 418 return loadedELF{}, linuxerr.ENOEXEC 419 } 420 var ok bool 421 end, ok = vaddr.AddLength(phdr.Memsz) 422 if !ok { 423 ctx.Infof("PT_LOAD header size overflows. %#x + %#x", vaddr, phdr.Memsz) 424 return loadedELF{}, linuxerr.ENOEXEC 425 } 426 427 case elf.PT_INTERP: 428 if phdr.Filesz < 2 { 429 ctx.Infof("PT_INTERP path too small: %v", phdr.Filesz) 430 return loadedELF{}, linuxerr.ENOEXEC 431 } 432 if phdr.Filesz > linux.PATH_MAX { 433 ctx.Infof("PT_INTERP path too big: %v", phdr.Filesz) 434 return loadedELF{}, linuxerr.ENOEXEC 435 } 436 if int64(phdr.Off) < 0 || int64(phdr.Off+phdr.Filesz) < 0 { 437 ctx.Infof("Unsupported PT_INTERP offset %d", phdr.Off) 438 return loadedELF{}, linuxerr.ENOEXEC 439 } 440 441 path := make([]byte, phdr.Filesz) 442 _, err := fd.ReadFull(ctx, usermem.BytesIOSequence(path), int64(phdr.Off)) 443 if err != nil { 444 // If an interpreter was specified, it should exist. 445 ctx.Infof("Error reading PT_INTERP path: %v", err) 446 return loadedELF{}, linuxerr.ENOEXEC 447 } 448 449 if path[len(path)-1] != 0 { 450 ctx.Infof("PT_INTERP path not NUL-terminated: %v", path) 451 return loadedELF{}, linuxerr.ENOEXEC 452 } 453 454 // Strip NUL-terminator and everything beyond from 455 // string. Note that there may be a NUL-terminator 456 // before len(path)-1. 457 interpreter = string(path[:bytes.IndexByte(path, '\x00')]) 458 if interpreter == "" { 459 // Linux actually attempts to open_exec("\0"). 460 // open_exec -> do_open_execat fails to check 461 // that name != '\0' before calling 462 // do_filp_open, which thus opens the working 463 // directory. do_open_execat returns EACCES 464 // because the directory is not a regular file. 465 // 466 // We bypass that nonsense and simply 467 // short-circuit with EACCES. Those this does 468 // mean that there may be some edge cases where 469 // the open path would return a different 470 // error. 471 ctx.Infof("PT_INTERP path is empty: %v", path) 472 return loadedELF{}, linuxerr.EACCES 473 } 474 } 475 } 476 477 // Shared objects don't have fixed load addresses. We need to pick a 478 // base address big enough to fit all segments, so we first create a 479 // mapping for the total size just to find a region that is big enough. 480 // 481 // It is safe to unmap it immediately without racing with another mapping 482 // because we are the only one in control of the MemoryManager. 483 // 484 // Note that the vaddr of the first PT_LOAD segment is ignored when 485 // choosing the load address (even if it is non-zero). The vaddr does 486 // become an offset from that load address. 487 var offset hostarch.Addr 488 if info.sharedObject { 489 totalSize := end - start 490 totalSize, ok := totalSize.RoundUp() 491 if !ok { 492 ctx.Infof("ELF PT_LOAD segments too big") 493 return loadedELF{}, linuxerr.ENOEXEC 494 } 495 496 var err error 497 offset, err = m.MMap(ctx, memmap.MMapOpts{ 498 Length: uint64(totalSize), 499 Addr: sharedLoadOffset, 500 Private: true, 501 }) 502 if err != nil { 503 ctx.Infof("Error allocating address space for shared object: %v", err) 504 return loadedELF{}, err 505 } 506 if err := m.MUnmap(ctx, offset, uint64(totalSize)); err != nil { 507 panic(fmt.Sprintf("Failed to unmap base address: %v", err)) 508 } 509 510 start, ok = start.AddLength(uint64(offset)) 511 if !ok { 512 ctx.Infof(fmt.Sprintf("Start %#x + offset %#x overflows?", start, offset)) 513 return loadedELF{}, linuxerr.EINVAL 514 } 515 516 end, ok = end.AddLength(uint64(offset)) 517 if !ok { 518 ctx.Infof(fmt.Sprintf("End %#x + offset %#x overflows?", end, offset)) 519 return loadedELF{}, linuxerr.EINVAL 520 } 521 522 info.entry, ok = info.entry.AddLength(uint64(offset)) 523 if !ok { 524 ctx.Infof("Entrypoint %#x + offset %#x overflows? Is the entrypoint within a segment?", info.entry, offset) 525 return loadedELF{}, err 526 } 527 } 528 529 // Map PT_LOAD segments. 530 for _, phdr := range info.phdrs { 531 switch phdr.Type { 532 case elf.PT_LOAD: 533 if phdr.Memsz == 0 { 534 // No need to load segments with size 0, but 535 // they exist in some binaries. 536 continue 537 } 538 539 if err := mapSegment(ctx, m, fd, &phdr, offset); err != nil { 540 ctx.Infof("Failed to map PT_LOAD segment: %+v", phdr) 541 return loadedELF{}, err 542 } 543 } 544 } 545 546 // This assumes that the first segment contains the ELF headers. This 547 // may not be true in a malformed ELF, but Linux makes the same 548 // assumption. 549 phdrAddr, ok := start.AddLength(info.phdrOff) 550 if !ok { 551 ctx.Warningf("ELF start address %#x + phdr offset %#x overflows", start, info.phdrOff) 552 phdrAddr = 0 553 } 554 555 return loadedELF{ 556 os: info.os, 557 arch: info.arch, 558 entry: info.entry, 559 start: start, 560 end: end, 561 interpreter: interpreter, 562 phdrAddr: phdrAddr, 563 phdrSize: info.phdrSize, 564 phdrNum: len(info.phdrs), 565 }, nil 566 } 567 568 // loadInitialELF loads f into mm. 569 // 570 // It creates an arch.Context64 for the ELF and prepares the mm for this arch. 571 // 572 // It does not load the ELF interpreter, or return any auxv entries. 573 // 574 // Preconditions: 575 // - f is an ELF file. 576 // - f is the first ELF loaded into m. 577 func loadInitialELF(ctx context.Context, m *mm.MemoryManager, fs cpuid.FeatureSet, fd *vfs.FileDescription) (loadedELF, *arch.Context64, error) { 578 info, err := parseHeader(ctx, fd) 579 if err != nil { 580 ctx.Infof("Failed to parse initial ELF: %v", err) 581 return loadedELF{}, nil, err 582 } 583 584 // Check Image Compatibility. 585 if arch.Host != info.arch { 586 ctx.Warningf("Found mismatch for platform %s with ELF type %s", arch.Host.String(), info.arch.String()) 587 return loadedELF{}, nil, linuxerr.ENOEXEC 588 } 589 590 // Create the arch.Context64 now so we can prepare the mmap layout before 591 // mapping anything. 592 ac := arch.New(info.arch) 593 594 l, err := m.SetMmapLayout(ac, limits.FromContext(ctx)) 595 if err != nil { 596 ctx.Warningf("Failed to set mmap layout: %v", err) 597 return loadedELF{}, nil, err 598 } 599 600 // PIELoadAddress tries to move the ELF out of the way of the default 601 // mmap base to ensure that the initial brk has sufficient space to 602 // grow. 603 le, err := loadParsedELF(ctx, m, fd, info, ac.PIELoadAddress(l)) 604 return le, ac, err 605 } 606 607 // loadInterpreterELF loads f into mm. 608 // 609 // The interpreter must be for the same OS/Arch as the initial ELF. 610 // 611 // It does not return any auxv entries. 612 // 613 // Preconditions: f is an ELF file. 614 func loadInterpreterELF(ctx context.Context, m *mm.MemoryManager, fd *vfs.FileDescription, initial loadedELF) (loadedELF, error) { 615 info, err := parseHeader(ctx, fd) 616 if err != nil { 617 if linuxerr.Equals(linuxerr.ENOEXEC, err) { 618 // Bad interpreter. 619 err = linuxerr.ELIBBAD 620 } 621 return loadedELF{}, err 622 } 623 624 if info.os != initial.os { 625 ctx.Infof("Initial ELF OS %v and interpreter ELF OS %v differ", initial.os, info.os) 626 return loadedELF{}, linuxerr.ELIBBAD 627 } 628 if info.arch != initial.arch { 629 ctx.Infof("Initial ELF arch %v and interpreter ELF arch %v differ", initial.arch, info.arch) 630 return loadedELF{}, linuxerr.ELIBBAD 631 } 632 633 // The interpreter is not given a load offset, as its location does not 634 // affect brk. 635 return loadParsedELF(ctx, m, fd, info, 0) 636 } 637 638 // loadELF loads args.File into the Task address space. 639 // 640 // If loadELF returns ErrSwitchFile it should be called again with the returned 641 // path and argv. 642 // 643 // Preconditions: args.File is an ELF file. 644 func loadELF(ctx context.Context, args LoadArgs) (loadedELF, *arch.Context64, error) { 645 bin, ac, err := loadInitialELF(ctx, args.MemoryManager, args.Features, args.File) 646 if err != nil { 647 ctx.Infof("Error loading binary: %v", err) 648 return loadedELF{}, nil, err 649 } 650 651 var interp loadedELF 652 if bin.interpreter != "" { 653 // Even if we do not allow the final link of the script to be 654 // resolved, the interpreter should still be resolved if it is 655 // a symlink. 656 args.ResolveFinal = true 657 // Refresh the traversal limit. 658 *args.RemainingTraversals = linux.MaxSymlinkTraversals 659 args.Filename = bin.interpreter 660 intFile, err := openPath(ctx, args) 661 if err != nil { 662 ctx.Infof("Error opening interpreter %s: %v", bin.interpreter, err) 663 return loadedELF{}, nil, err 664 } 665 defer intFile.DecRef(ctx) 666 667 interp, err = loadInterpreterELF(ctx, args.MemoryManager, intFile, bin) 668 if err != nil { 669 ctx.Infof("Error loading interpreter: %v", err) 670 return loadedELF{}, nil, err 671 } 672 673 if interp.interpreter != "" { 674 // No recursive interpreters! 675 ctx.Infof("Interpreter requires an interpreter") 676 return loadedELF{}, nil, linuxerr.ENOEXEC 677 } 678 } 679 680 // ELF-specific auxv entries. 681 bin.auxv = arch.Auxv{ 682 arch.AuxEntry{linux.AT_PHDR, bin.phdrAddr}, 683 arch.AuxEntry{linux.AT_PHENT, hostarch.Addr(bin.phdrSize)}, 684 arch.AuxEntry{linux.AT_PHNUM, hostarch.Addr(bin.phdrNum)}, 685 arch.AuxEntry{linux.AT_ENTRY, bin.entry}, 686 } 687 if bin.interpreter != "" { 688 bin.auxv = append(bin.auxv, arch.AuxEntry{linux.AT_BASE, interp.start}) 689 690 // Start in the interpreter. 691 // N.B. AT_ENTRY above contains the *original* entry point. 692 bin.entry = interp.entry 693 } else { 694 // Always add AT_BASE even if there is no interpreter. 695 bin.auxv = append(bin.auxv, arch.AuxEntry{linux.AT_BASE, 0}) 696 } 697 698 return bin, ac, nil 699 }