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