Skip to content

Commit dab673c

Browse files
committed
asm: allow negative constants for builtin function calls
The work to encode a platform into various constant types made it so that decoding a call to a builtin helper with a negative value fails with decoding instructions for section <sectionname>: offset <offset>: invalid constant 0xffffffff for a BPF instruction of "call -1". This is because we can't represent -1 as a tagged platform constant. Allow negative constants by not transforming them into a platform constant at all. Adjust the platform tag size so that we never generate a platform constant with the high bit set. This avoids confusing it with a negative number when reinterpreting it as a signed number and ensures that trying to marshal such an instruction gives an error. Fixes: #1797 Signed-off-by: Lorenz Bauer <[email protected]>
1 parent 9958a4f commit dab673c

File tree

4 files changed

+22
-6
lines changed

4 files changed

+22
-6
lines changed

asm/instruction.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,17 @@ func (ins *Instruction) Unmarshal(r io.Reader, bo binary.ByteOrder, platform str
6767
ins.Constant = int64(int32(bo.Uint32(data[4:8])))
6868

6969
if ins.IsBuiltinCall() {
70-
fn, err := BuiltinFuncForPlatform(platform, uint32(ins.Constant))
71-
if err != nil {
72-
return err
70+
if ins.Constant >= 0 {
71+
// Leave negative constants from the instruction stream
72+
// unchanged. These are sometimes used as placeholders for later
73+
// patching.
74+
// This relies on not having a valid platform tag with a high bit set.
75+
fn, err := BuiltinFuncForPlatform(platform, uint32(ins.Constant))
76+
if err != nil {
77+
return err
78+
}
79+
ins.Constant = int64(fn)
7380
}
74-
ins.Constant = int64(fn)
7581
} else if ins.OpCode.Class().IsALU() {
7682
switch ins.OpCode.ALUOp() {
7783
case Div:

asm/instruction_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,16 @@ func TestInstructionWithMetadata(t *testing.T) {
180180
}
181181
}
182182

183+
func TestReadCallToNegativeOne(t *testing.T) {
184+
raw := []byte{
185+
0x85, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
186+
}
187+
var ins Instruction
188+
err := ins.Unmarshal(bytes.NewReader(raw), binary.LittleEndian, platform.Linux)
189+
qt.Assert(t, qt.IsNil(err))
190+
qt.Assert(t, qt.Equals(ins.Constant, -1))
191+
}
192+
183193
// You can use format flags to change the way an eBPF
184194
// program is stringified.
185195
func ExampleInstructions_Format() {

internal/platform/constants.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const (
1111
)
1212

1313
const (
14-
platformMax = 0xf
14+
platformMax = 1<<3 - 1 // most not exceed 3 bits to avoid setting the high bit
1515
platformShift = 28
1616
platformMask = platformMax << platformShift
1717
)

internal/platform/constants_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
)
88

99
func TestConstant(t *testing.T) {
10-
const maxConstant = ^uint32(platformMask)
10+
const maxConstant = uint32(1<<platformShift - 1)
1111
for _, plat := range []string{
1212
Linux,
1313
Windows,

0 commit comments

Comments
 (0)