diff options
| author | Alexander Potapenko <glider@google.com> | 2023-11-27 17:46:34 +0100 |
|---|---|---|
| committer | Aleksandr Nogikh <nogikh@google.com> | 2024-01-17 09:28:44 +0000 |
| commit | c9a1c95bf02421042abda563e4ec488384157409 (patch) | |
| tree | 3cfbeacc8843daa4db9e6d711d2aa9bbfeeeada7 /pkg | |
| parent | edd756a5fa6390fb08e2b515e507253a59b22d70 (diff) | |
pkg/cover/backend: adjust module base address by .text offset
Modules' .text sections are not necessarily loaded at the address shown
in /proc/modules. If there are other non-init code sections preceding them
in the ELF binary, .text is loaded at non-zero address.
For example, for a module with the following sections:
Idx Name Size VMA LMA File off Algn
...
5 .plt 00000001 0000000000000000 0000000000000000 00000500 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
6 .init.ddplt 00000001 0000000000000000 0000000000000000 00000501 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
7 .text.ftrace_trampoline 00000001 0000000000000000 0000000000000000 00000502 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
8 .hyp.text 00002000 0000000000000000 0000000000000000 00001000 2**12
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
...
13 .text 00001aac 0000000000000000 0000000000000000 00005048 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
the base address displayed in /proc/modules points to the beginning of
.plt, and other sections have the following offsets:
.init.plt - ignored
.text.ftrace_trampoline - 0x1
.hyp.text - 0x1000
.text - 0x3000
This patch calculates the offset of the .text section and uses it to
adjust the address obtained from /proc/modules.
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/cover/backend/dwarf.go | 3 | ||||
| -rw-r--r-- | pkg/cover/backend/elf.go | 42 | ||||
| -rw-r--r-- | pkg/cover/backend/modules.go | 12 |
3 files changed, 52 insertions, 5 deletions
diff --git a/pkg/cover/backend/dwarf.go b/pkg/cover/backend/dwarf.go index 4db2f2ad4..75063f9e0 100644 --- a/pkg/cover/backend/dwarf.go +++ b/pkg/cover/backend/dwarf.go @@ -34,6 +34,7 @@ type dwarfParams struct { readTextData func(*Module) ([]byte, error) readModuleCoverPoints func(*targets.Target, *Module, *symbolInfo) ([2][]uint64, error) readTextRanges func(*Module) ([]pcRange, []*CompileUnit, error) + getModuleOffset func(string) uint64 } type Arch struct { @@ -91,7 +92,7 @@ func makeDWARFUnsafe(params *dwarfParams) (*Impl, error) { objDir := params.objDir srcDir := params.srcDir buildDir := params.buildDir - modules, err := discoverModules(target, objDir, params.moduleObj, params.hostModules) + modules, err := discoverModules(target, objDir, params.moduleObj, params.hostModules, params.getModuleOffset) if err != nil { return nil, err } diff --git a/pkg/cover/backend/elf.go b/pkg/cover/backend/elf.go index 57975a9d5..5398d64bb 100644 --- a/pkg/cover/backend/elf.go +++ b/pkg/cover/backend/elf.go @@ -28,6 +28,7 @@ func makeELF(target *targets.Target, objDir, srcDir, buildDir string, readTextData: elfReadTextData, readModuleCoverPoints: elfReadModuleCoverPoints, readTextRanges: elfReadTextRanges, + getModuleOffset: elfGetModuleOffset, }) } @@ -175,3 +176,44 @@ func elfReadModuleCoverPoints(target *targets.Target, module *Module, info *symb } return pcs, nil } + +// Calculate the offset of the module .text section in the kernel memory. +// /proc/modules only contains the base address, which corresponds to the +// beginning of the first code section, but that section does not have to +// be .text (e.g. on Android it may be .plt). +// The offset is calculated by summing up the aligned sizes of sections +// that: +// - precede .text; +// - are not .init/.exit sections; +// - have the SHF_ALLOC and SHF_EXECINSTR flags. +func elfGetModuleOffset(path string) uint64 { + file, err := elf.Open(path) + if err != nil { + return 0 + } + defer file.Close() + ts := file.Section(".text") + if ts == nil { + return 0 + } + off := uint64(0) + const textFlagsMask = elf.SHF_ALLOC | elf.SHF_EXECINSTR + for _, s := range file.Sections { + if (s.Flags&textFlagsMask == textFlagsMask) && !strings.HasPrefix(s.SectionHeader.Name, ".init") && + !strings.HasPrefix(s.SectionHeader.Name, ".exit") { + off = alignUp(off, s.SectionHeader.Addralign) + if s == ts { + return off + } + off += s.SectionHeader.Size + } + } + return 0 +} + +func alignUp(addr, align uint64) uint64 { + if align == 0 { + return addr + } + return (addr + align - 1) & ^(align - 1) +} diff --git a/pkg/cover/backend/modules.go b/pkg/cover/backend/modules.go index 4da73d3ad..ac3326236 100644 --- a/pkg/cover/backend/modules.go +++ b/pkg/cover/backend/modules.go @@ -16,14 +16,16 @@ import ( "github.com/google/syzkaller/sys/targets" ) -func discoverModules(target *targets.Target, objDir string, moduleObj []string, hostModules []host.KernelModule) ( +func discoverModules(target *targets.Target, objDir string, moduleObj []string, + hostModules []host.KernelModule, getModuleOffset func(string) uint64) ( []*Module, error) { modules := []*Module{ // A dummy module representing the kernel itself. {Path: filepath.Join(objDir, target.KernelObject)}, } if target.OS == targets.Linux { - modules1, err := discoverModulesLinux(append([]string{objDir}, moduleObj...), hostModules) + modules1, err := discoverModulesLinux(append([]string{objDir}, moduleObj...), + hostModules, getModuleOffset) if err != nil { return nil, err } @@ -34,7 +36,8 @@ func discoverModules(target *targets.Target, objDir string, moduleObj []string, return modules, nil } -func discoverModulesLinux(dirs []string, hostModules []host.KernelModule) ([]*Module, error) { +func discoverModulesLinux(dirs []string, hostModules []host.KernelModule, + getModuleOffset func(string) uint64) ([]*Module, error) { paths, err := locateModules(dirs) if err != nil { return nil, err @@ -47,9 +50,10 @@ func discoverModulesLinux(dirs []string, hostModules []host.KernelModule) ([]*Mo continue } log.Logf(0, "module %v -> %v", mod.Name, path) + offset := getModuleOffset(path) modules = append(modules, &Module{ Name: mod.Name, - Addr: mod.Addr, + Addr: mod.Addr + offset, Path: path, }) } |
