Skip to content

Commit b9e7fb7

Browse files
committed
Fix ksym buffer overrun on 32 bit platforms
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 <kolyshkin@gmail.com>
1 parent 1bcc12e commit b9e7fb7

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

info.go

+20-3
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ type programJitedInfo struct {
185185
// subprograms.
186186
//
187187
// Available from 4.18.
188-
ksyms []uintptr
188+
ksyms []uint64
189189
numKsyms uint32
190190

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

345345
if info.NrJitedKsyms > 0 {
346346
pi.jitedInfo.numKsyms = info.NrJitedKsyms
347-
pi.jitedInfo.ksyms = make([]uintptr, info.NrJitedKsyms)
347+
pi.jitedInfo.ksyms = make([]uint64, info.NrJitedKsyms)
348348
info2.JitedKsyms = sys.NewSlicePointer(pi.jitedInfo.ksyms)
349349
info2.NrJitedKsyms = info.NrJitedKsyms
350350
makeSecondCall = true
@@ -630,8 +630,25 @@ func (pi *ProgramInfo) VerifiedInstructions() (uint32, bool) {
630630
// programs without subprograms (bpf2bpf calls).
631631
//
632632
// The bool return value indicates whether this optional field is available.
633+
//
634+
// When a kernel address can't fit into uintptr (which is usually the case when
635+
// running 32 bit program on a 64 bit kernel), this returns an empty slice and
636+
// a false.
633637
func (pi *ProgramInfo) JitedKsymAddrs() ([]uintptr, bool) {
634-
return pi.jitedInfo.ksyms, len(pi.jitedInfo.ksyms) > 0
638+
ksyms := make([]uintptr, 0, len(pi.jitedInfo.ksyms))
639+
if cap(ksyms) == 0 {
640+
return ksyms, false
641+
}
642+
// Check if a kernel address fits into uintptr (it might not when
643+
// using a 32 bit binary on a 64 bit kernel). This check should work
644+
// with any kernel address, since they have 1s at the highest bits.
645+
if a := pi.jitedInfo.ksyms[0]; uint64(uintptr(a)) != a {
646+
return nil, false
647+
}
648+
for _, ksym := range pi.jitedInfo.ksyms {
649+
ksyms = append(ksyms, uintptr(ksym))
650+
}
651+
return ksyms, true
635652
}
636653

637654
// JitedInsns returns the JITed machine native instructions of the program.

0 commit comments

Comments
 (0)