mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 22:42:24 -05:00 
			
		
		
		
	Bumps [github.com/KimMachineGun/automemlimit](https://github.com/KimMachineGun/automemlimit) from 0.2.4 to 0.2.5. - [Release notes](https://github.com/KimMachineGun/automemlimit/releases) - [Commits](https://github.com/KimMachineGun/automemlimit/compare/v0.2.4...v0.2.5) --- updated-dependencies: - dependency-name: github.com/KimMachineGun/automemlimit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
		
			
				
	
	
		
			150 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package internal
 | |
| 
 | |
| import (
 | |
| 	"debug/elf"
 | |
| 	"encoding/binary"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"math"
 | |
| 	"os"
 | |
| 
 | |
| 	"github.com/cilium/ebpf/internal/unix"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	errAuxvNoVDSO = errors.New("no vdso address found in auxv")
 | |
| )
 | |
| 
 | |
| // vdsoVersion returns the LINUX_VERSION_CODE embedded in the vDSO library
 | |
| // linked into the current process image.
 | |
| func vdsoVersion() (uint32, error) {
 | |
| 	// Read data from the auxiliary vector, which is normally passed directly
 | |
| 	// to the process. Go does not expose that data, so we must read it from procfs.
 | |
| 	// https://man7.org/linux/man-pages/man3/getauxval.3.html
 | |
| 	av, err := os.Open("/proc/self/auxv")
 | |
| 	if err != nil {
 | |
| 		return 0, fmt.Errorf("opening auxv: %w", err)
 | |
| 	}
 | |
| 	defer av.Close()
 | |
| 
 | |
| 	vdsoAddr, err := vdsoMemoryAddress(av)
 | |
| 	if err != nil {
 | |
| 		return 0, fmt.Errorf("finding vDSO memory address: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// Use /proc/self/mem rather than unsafe.Pointer tricks.
 | |
| 	mem, err := os.Open("/proc/self/mem")
 | |
| 	if err != nil {
 | |
| 		return 0, fmt.Errorf("opening mem: %w", err)
 | |
| 	}
 | |
| 	defer mem.Close()
 | |
| 
 | |
| 	// Open ELF at provided memory address, as offset into /proc/self/mem.
 | |
| 	c, err := vdsoLinuxVersionCode(io.NewSectionReader(mem, int64(vdsoAddr), math.MaxInt64))
 | |
| 	if err != nil {
 | |
| 		return 0, fmt.Errorf("reading linux version code: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	return c, nil
 | |
| }
 | |
| 
 | |
| // vdsoMemoryAddress returns the memory address of the vDSO library
 | |
| // linked into the current process image. r is an io.Reader into an auxv blob.
 | |
| func vdsoMemoryAddress(r io.Reader) (uint64, error) {
 | |
| 	const (
 | |
| 		_AT_NULL         = 0  // End of vector
 | |
| 		_AT_SYSINFO_EHDR = 33 // Offset to vDSO blob in process image
 | |
| 	)
 | |
| 
 | |
| 	// Loop through all tag/value pairs in auxv until we find `AT_SYSINFO_EHDR`,
 | |
| 	// the address of a page containing the virtual Dynamic Shared Object (vDSO).
 | |
| 	aux := struct{ Tag, Val uint64 }{}
 | |
| 	for {
 | |
| 		if err := binary.Read(r, NativeEndian, &aux); err != nil {
 | |
| 			return 0, fmt.Errorf("reading auxv entry: %w", err)
 | |
| 		}
 | |
| 
 | |
| 		switch aux.Tag {
 | |
| 		case _AT_SYSINFO_EHDR:
 | |
| 			if aux.Val != 0 {
 | |
| 				return aux.Val, nil
 | |
| 			}
 | |
| 			return 0, fmt.Errorf("invalid vDSO address in auxv")
 | |
| 		// _AT_NULL is always the last tag/val pair in the aux vector
 | |
| 		// and can be treated like EOF.
 | |
| 		case _AT_NULL:
 | |
| 			return 0, errAuxvNoVDSO
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // format described at https://www.man7.org/linux/man-pages/man5/elf.5.html in section 'Notes (Nhdr)'
 | |
| type elfNoteHeader struct {
 | |
| 	NameSize int32
 | |
| 	DescSize int32
 | |
| 	Type     int32
 | |
| }
 | |
| 
 | |
| // vdsoLinuxVersionCode returns the LINUX_VERSION_CODE embedded in
 | |
| // the ELF notes section of the binary provided by the reader.
 | |
| func vdsoLinuxVersionCode(r io.ReaderAt) (uint32, error) {
 | |
| 	hdr, err := NewSafeELFFile(r)
 | |
| 	if err != nil {
 | |
| 		return 0, fmt.Errorf("reading vDSO ELF: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	sections := hdr.SectionsByType(elf.SHT_NOTE)
 | |
| 	if len(sections) == 0 {
 | |
| 		return 0, fmt.Errorf("no note section found in vDSO ELF")
 | |
| 	}
 | |
| 
 | |
| 	for _, sec := range sections {
 | |
| 		sr := sec.Open()
 | |
| 		var n elfNoteHeader
 | |
| 
 | |
| 		// Read notes until we find one named 'Linux'.
 | |
| 		for {
 | |
| 			if err := binary.Read(sr, hdr.ByteOrder, &n); err != nil {
 | |
| 				if errors.Is(err, io.EOF) {
 | |
| 					// We looked at all the notes in this section
 | |
| 					break
 | |
| 				}
 | |
| 				return 0, fmt.Errorf("reading note header: %w", err)
 | |
| 			}
 | |
| 
 | |
| 			// If a note name is defined, it follows the note header.
 | |
| 			var name string
 | |
| 			if n.NameSize > 0 {
 | |
| 				// Read the note name, aligned to 4 bytes.
 | |
| 				buf := make([]byte, Align(int(n.NameSize), 4))
 | |
| 				if err := binary.Read(sr, hdr.ByteOrder, &buf); err != nil {
 | |
| 					return 0, fmt.Errorf("reading note name: %w", err)
 | |
| 				}
 | |
| 
 | |
| 				// Read nul-terminated string.
 | |
| 				name = unix.ByteSliceToString(buf[:n.NameSize])
 | |
| 			}
 | |
| 
 | |
| 			// If a note descriptor is defined, it follows the name.
 | |
| 			// It is possible for a note to have a descriptor but not a name.
 | |
| 			if n.DescSize > 0 {
 | |
| 				// LINUX_VERSION_CODE is a uint32 value.
 | |
| 				if name == "Linux" && n.DescSize == 4 && n.Type == 0 {
 | |
| 					var version uint32
 | |
| 					if err := binary.Read(sr, hdr.ByteOrder, &version); err != nil {
 | |
| 						return 0, fmt.Errorf("reading note descriptor: %w", err)
 | |
| 					}
 | |
| 					return version, nil
 | |
| 				}
 | |
| 
 | |
| 				// Discard the note descriptor if it exists but we're not interested in it.
 | |
| 				if _, err := io.CopyN(io.Discard, sr, int64(Align(int(n.DescSize), 4))); err != nil {
 | |
| 					return 0, err
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0, fmt.Errorf("no Linux note in ELF")
 | |
| }
 |