diff --git a/changelog/13282.txt b/changelog/13282.txt new file mode 100644 index 000000000..2c32209c0 --- /dev/null +++ b/changelog/13282.txt @@ -0,0 +1,3 @@ +```release-note:bug +storage/raft: Fix a panic when trying to write a key > 32KB +``` diff --git a/physical/raft/raft.go b/physical/raft/raft.go index 8c59fd07a..8d3621862 100644 --- a/physical/raft/raft.go +++ b/physical/raft/raft.go @@ -1288,6 +1288,9 @@ func (b *RaftBackend) Get(ctx context.Context, path string) (*physical.Entry, er // or if the call to applyLog fails. func (b *RaftBackend) Put(ctx context.Context, entry *physical.Entry) error { defer metrics.MeasureSince([]string{"raft-storage", "put"}, time.Now()) + if len(entry.Key) > bolt.MaxKeySize { + return fmt.Errorf("%s, max key size for integrated storage is %d", physical.ErrKeyTooLarge, bolt.MaxKeySize) + } if err := ctx.Err(); err != nil { return err diff --git a/physical/raft/raft_test.go b/physical/raft/raft_test.go index 35813ae11..f6211d0b7 100644 --- a/physical/raft/raft_test.go +++ b/physical/raft/raft_test.go @@ -15,6 +15,8 @@ import ( "testing" "time" + "github.com/hashicorp/go-secure-stdlib/base62" + "github.com/go-test/deep" "github.com/golang/protobuf/proto" hclog "github.com/hashicorp/go-hclog" @@ -224,6 +226,34 @@ func TestRaft_Backend(t *testing.T) { physical.ExerciseBackend(t, b) } +func TestRaft_Backend_LargeKey(t *testing.T) { + b, dir := getRaft(t, true, true) + defer os.RemoveAll(dir) + + key, err := base62.Random(bolt.MaxKeySize + 1) + if err != nil { + t.Fatal(err) + } + entry := &physical.Entry{Key: key, Value: []byte(key)} + + err = b.Put(context.Background(), entry) + if err == nil { + t.Fatal("expected error for put entry") + } + + if !strings.Contains(err.Error(), physical.ErrKeyTooLarge) { + t.Fatalf("expected %q, got %v", physical.ErrKeyTooLarge, err) + } + + out, err := b.Get(context.Background(), entry.Key) + if err != nil { + t.Fatalf("unexpected error after failed put: %v", err) + } + if out != nil { + t.Fatal("expected response entry to be nil after a failed put") + } +} + func TestRaft_Backend_LargeValue(t *testing.T) { b, dir := getRaft(t, true, true) defer os.RemoveAll(dir) diff --git a/sdk/physical/physical.go b/sdk/physical/physical.go index 8cc4e9ab1..808abd50f 100644 --- a/sdk/physical/physical.go +++ b/sdk/physical/physical.go @@ -21,6 +21,7 @@ const ( const ( ErrValueTooLarge = "put failed due to value being too large" + ErrKeyTooLarge = "put failed due to key being too large" ) // Backend is the interface required for a physical