Repository: google/gvisor
File: pkg/sentry/loader/elf.go (Go)

Code before:
			Perms:    prot,
			MaxPerms: hostarch.AnyAccess,
		}
		defer func() {
			if mopts.MappingIdentity != nil {
				mopts.MappingIdentity.DecRef(ctx)
			}
		}()
		if err := fd.ConfigureMMap(ctx, &mopts); err != nil {
			ctx.Infof("File is not memory-mappable: %v", err)
			return err
		}
		if _, err := m.MMap(ctx, mopts); err != nil {
			ctx.Infof("Error mapping PT_LOAD segment %+v at %#x: %v", phdr, addr, err)
			return err
		}

		// We need to clear the end of the phdr.Memsz that exceeds dr.Filesz so
		// we don't map part of the file beyond dr.Filesz to phdr.Memsz.
		//
		// Note that:
		//   1) Linux *does not* clear the portion of the first page before phdr.Off;
		//   2) There are cases when other sections (eg. DYNAMIC) falls outside of
		//      LOAD's phdr.Memsz, but within the extended memory region towards
		//      mmap-ed page boundary. Linux *does not* clear this portion, thus we
		//      do not as well.
		if phdr.Memsz > phdr.Filesz {
			zeroAddr, ok := addr.AddLength(fileSize)
			if !ok {
				panic(fmt.Sprintf("successfully mmaped address overflows? %#x + %#x", addr, fileSize))
			}
			zeroSize := int64(mapSize - fileSize)
			if zeroSize < 0 {
				panic(fmt.Sprintf("zeroSize too big? %#x", uint64(zeroSize)))
			}
			if _, err := m.ZeroOut(ctx, zeroAddr, zeroSize, usermem.IOOpts{IgnorePermissions: true}); err != nil {
				ctx.Warningf("Failed to zero end of page [%#x, %#x): %v", zeroAddr, zeroAddr+hostarch.Addr(zeroSize), err)
				return err
			}
		}
	}

	memSize := phdr.Memsz + adjust
	if memSize < phdr.Memsz {
		ctx.Infof("Computed segment mem size overflows: %#x + %#x", phdr.Memsz, adjust)
		return linuxerr.ENOEXEC
	}

	// Allocate more anonymous pages if necessary.
	if mapSize < memSize {
		anonAddr, ok := addr.AddLength(mapSize)

Review comment (suggestion):
IIUC, the original comment is still correct. It is still the end of the last page that is being cleared; `phdr.Memsz` isn't used in determining what range is zeroed below, and this is consistent with Linux's non-use of `eppnt->p_memsz` and `zero_end` in the call to `padzero()`. It's just that this zeroing is skipped entirely if `phdr.Memsz <= phdr.Filesz`.

Code after:
			Perms:    prot,
			MaxPerms: hostarch.AnyAccess,
		}
		defer func() {
			if mopts.MappingIdentity != nil {
				mopts.MappingIdentity.DecRef(ctx)
			}
		}()
		if err := fd.ConfigureMMap(ctx, &mopts); err != nil {
			ctx.Infof("File is not memory-mappable: %v", err)
			return err
		}
		if _, err := m.MMap(ctx, mopts); err != nil {
			ctx.Infof("Error mapping PT_LOAD segment %+v at %#x: %v", phdr, addr, err)
			return err
		}

		// When phdr.Memsz > phdr.Filesz, we need to clear the end of the last page that
		// exceeds fileSize so we don't map part of the file beyond fileSize.
		//
		// Note that:
		//   1) Linux *does not* clear the portion of the first page before phdr.Off;
		//   2) There are cases when other sections (eg. DYNAMIC) falls outside of
		//      LOAD's phdr.Memsz, but within the extended memory region towards
		//      last page's ending boundary. Linux *does not* clear this portion when
		//      phdr.Memsz <= phdr.Filesz, thus we do not as well.
		if phdr.Memsz > phdr.Filesz && mapSize > fileSize {
			zeroAddr, ok := addr.AddLength(fileSize)
			if !ok {
				panic(fmt.Sprintf("successfully mmaped address overflows? %#x + %#x", addr, fileSize))
			}
			zeroSize := int64(mapSize - fileSize)
			if zeroSize < 0 {
				panic(fmt.Sprintf("zeroSize too big? %#x", uint64(zeroSize)))
			}
			if _, err := m.ZeroOut(ctx, zeroAddr, zeroSize, usermem.IOOpts{IgnorePermissions: true}); err != nil {
				ctx.Warningf("Failed to zero end of page [%#x, %#x): %v", zeroAddr, zeroAddr+hostarch.Addr(zeroSize), err)
				return err
			}
		}
	}

	memSize := phdr.Memsz + adjust
	if memSize < phdr.Memsz {
		ctx.Infof("Computed segment mem size overflows: %#x + %#x", phdr.Memsz, adjust)
		return linuxerr.ENOEXEC
	}

	// Allocate more anonymous pages if necessary.
	if mapSize < memSize {
		anonAddr, ok := addr.AddLength(mapSize)