Skip to content

Commit

Permalink
Fix ksym buffer overrun on 32 bit platforms
Browse files Browse the repository at this point in the history
Commit 78074c5 ("info: expose more prog jited info"), which made its
way into v0.17.0, resulted in random runc CI failures when running i386
binary on an amd64 kernel (see [1]).

Apparently [2], the kernel always returns 64-bit pointers, so uint64
(rather than uintptr) should be used for ksyms slice regardless of
the platform to avoid the buffer overrun.

Now, to keep the public API of (*ProgramInfo).JitedKsymAddrsintact
intact, convert those addresses back to uintptr, as it was done before
commit 78074c5). Except, if the kernel address won't fit into uintptr
(as it is the case when running i386 binary on an amd64 kernel), return
an empty slice and a false, rather than incorrect addresses.

[1]: opencontainers/runc#4594
[2]: https://github.com/torvalds/linux/blob/2014c95afecee3e76ca4a56956a936e23283f05b/kernel/bpf/syscall.c#L4840-L4846

Signed-off-by: Kir Kolyshkin <[email protected]>
  • Loading branch information
kolyshkin committed Feb 6, 2025
1 parent 1bcc12e commit b9e7fb7
Showing 1 changed file with 20 additions and 3 deletions.
23 changes: 20 additions & 3 deletions info.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ type programJitedInfo struct {
// subprograms.
//
// Available from 4.18.
ksyms []uintptr
ksyms []uint64
numKsyms uint32

// insns holds the JITed machine native instructions of the program,
Expand Down Expand Up @@ -344,7 +344,7 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {

if info.NrJitedKsyms > 0 {
pi.jitedInfo.numKsyms = info.NrJitedKsyms
pi.jitedInfo.ksyms = make([]uintptr, info.NrJitedKsyms)
pi.jitedInfo.ksyms = make([]uint64, info.NrJitedKsyms)
info2.JitedKsyms = sys.NewSlicePointer(pi.jitedInfo.ksyms)
info2.NrJitedKsyms = info.NrJitedKsyms
makeSecondCall = true
Expand Down Expand Up @@ -630,8 +630,25 @@ func (pi *ProgramInfo) VerifiedInstructions() (uint32, bool) {
// programs without subprograms (bpf2bpf calls).
//
// The bool return value indicates whether this optional field is available.
//
// When a kernel address can't fit into uintptr (which is usually the case when
// running 32 bit program on a 64 bit kernel), this returns an empty slice and
// a false.
func (pi *ProgramInfo) JitedKsymAddrs() ([]uintptr, bool) {
return pi.jitedInfo.ksyms, len(pi.jitedInfo.ksyms) > 0
ksyms := make([]uintptr, 0, len(pi.jitedInfo.ksyms))
if cap(ksyms) == 0 {
return ksyms, false
}
// Check if a kernel address fits into uintptr (it might not when
// using a 32 bit binary on a 64 bit kernel). This check should work
// with any kernel address, since they have 1s at the highest bits.
if a := pi.jitedInfo.ksyms[0]; uint64(uintptr(a)) != a {
return nil, false
}
for _, ksym := range pi.jitedInfo.ksyms {
ksyms = append(ksyms, uintptr(ksym))
}
return ksyms, true
}

// JitedInsns returns the JITed machine native instructions of the program.
Expand Down

0 comments on commit b9e7fb7

Please sign in to comment.