From 4410ae70c2b934944430afbb86ac29069cd025df Mon Sep 17 00:00:00 2001 From: Neil Macneale IV Date: Mon, 21 Oct 2024 17:54:42 -0700 Subject: [PATCH] Never Ship. Hacked Dolt table file example --- go/store/datas/mangle_commit.go | 24 ++++++ go/store/nbs/mangle_hooks.go | 142 ++++++++++++++++++++++++++++++++ go/utils/mangle/main.go | 66 +++++++++++++++ 3 files changed, 232 insertions(+) create mode 100644 go/store/datas/mangle_commit.go create mode 100644 go/store/nbs/mangle_hooks.go create mode 100644 go/utils/mangle/main.go diff --git a/go/store/datas/mangle_commit.go b/go/store/datas/mangle_commit.go new file mode 100644 index 0000000000..bff2077e4c --- /dev/null +++ b/go/store/datas/mangle_commit.go @@ -0,0 +1,24 @@ +// Copyright 2024 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package datas + +import ( + "github.com/dolthub/dolt/go/gen/fb/serial" + "github.com/dolthub/dolt/go/store/hash" +) + +func ExposeCommitFlatbuffer(vaddr hash.Hash, opts CommitOptions, heights []uint64, parentsClosureAddr hash.Hash) (serial.Message, uint64) { + return commit_flatbuffer(vaddr, opts, heights, parentsClosureAddr) +} diff --git a/go/store/nbs/mangle_hooks.go b/go/store/nbs/mangle_hooks.go new file mode 100644 index 0000000000..ccc143d460 --- /dev/null +++ b/go/store/nbs/mangle_hooks.go @@ -0,0 +1,142 @@ +// Copyright 2024 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package nbs + +import ( + "context" + "fmt" + + "github.com/dolthub/dolt/go/gen/fb/serial" + "github.com/dolthub/dolt/go/store/chunks" + "github.com/dolthub/dolt/go/store/datas" + "github.com/dolthub/dolt/go/store/hash" + "github.com/dolthub/dolt/go/store/types" +) + +func LoopOverTables(ctx context.Context, csgs *GenerationalNBS) error { + stats := Stats{} + + // If the object is in a garbage collection file, we'll need to read it from the oldGen. + // gen := csgs.oldGen.tables.upstream + gen := csgs.newGen.tables.upstream + + vs := types.NewValueStore(csgs) + for tableId, table := range gen { + if tableId.String() == chunks.JournalFileID { + fmt.Println("Skipping Journal File") + continue + } + + idx, err := table.index() + if err != nil { + return err + } + sampleCount := idx.chunkCount() + + objectToHack := hash.Parse("3pdd8aasraqh1tmuedjmcr5nr2fccud2") + + hackedPersister, err := NewCmpChunkTableWriter("") + if err != nil { + return err + } + + for i := uint32(0); i < sampleCount; i++ { + var h hash.Hash + _, err := idx.indexEntry(i, &h) + if err != nil { + return err + } + // We'll read Chunks, then recompress them into CompressedChunks + rawData, err := table.get(ctx, h, &stats) + if err != nil { + return err + } + + chnk := chunks.NewChunkWithHash(h, rawData) + + if h == objectToHack { + // Deserialize the chunk. + origVal, err := types.DecodeValue(chnk, vs) + if err != nil { + return err + } + + hackedVal := origVal + + if isCmt, _ := datas.IsCommit(origVal); isCmt { + commit, err := serial.TryGetRootAsCommit([]byte(origVal.(types.SerialMessage)), serial.MessagePrefixSz) + if err != nil { + return err + } + + rootAddr := hash.New(commit.RootBytes()) + + parentCnt := commit.ParentAddrsLength() / hash.ByteLen + addrs := commit.ParentAddrsBytes() + parents := make([]hash.Hash, 0, parentCnt) + for i := 0; i < parentCnt; i++ { + addr := hash.New(addrs[:hash.ByteLen]) + addrs = addrs[hash.ByteLen:] + parents = append(parents, addr) + } + + opts := datas.CommitOptions{Meta: &datas.CommitMeta{ + Name: string(commit.Name()), + Email: string(commit.Email()), + Timestamp: commit.TimestampMillis() - 300000, // Make it look like the commit was made 5 min before it actually was. + UserTimestamp: commit.UserTimestampMillis() - 300000, + Description: string(commit.Description()), + }, Parents: parents} + + parentClosure := hash.New(commit.ParentClosureBytes()) + + heights := make([]uint64, 1) + heights[0] = commit.Height() - 1 + + altMsg, _ := datas.ExposeCommitFlatbuffer(rootAddr, opts, heights, parentClosure) + hackedVal = types.SerialMessage(altMsg) + chnk = chunks.NewChunkWithHash(objectToHack, []byte(hackedVal.(types.SerialMessage))) + } else { + return fmt.Errorf("object type is not a commit: %s", origVal.HumanReadableString()) + } + + fmt.Println("----------------------- MANGLE -----------------------------") + fmt.Println(fmt.Sprintf("Found object %s in Table File: %s", h.String(), tableId)) + fmt.Println(origVal.HumanReadableString()) + fmt.Println("ALTERED TO:") + fmt.Println(hackedVal.HumanReadableString()) + fmt.Println("------------------------------------------------------------") + } + + cmpChnk := ChunkToCompressedChunk(chnk) + + err = hackedPersister.AddCmpChunk(cmpChnk) + if err != nil { + return err + } + } + _, err = hackedPersister.Finish() + if err != nil { + return err + } + + err = hackedPersister.FlushToFile(fmt.Sprintf("%s.hacked", tableId)) + if err != nil { + return err + } + } + + return nil +} diff --git a/go/utils/mangle/main.go b/go/utils/mangle/main.go new file mode 100644 index 0000000000..4443d0fa08 --- /dev/null +++ b/go/utils/mangle/main.go @@ -0,0 +1,66 @@ +// Copyright 2024 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "context" + "fmt" + "os" + + "github.com/dolthub/dolt/go/cmd/dolt/doltversion" + "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" + "github.com/dolthub/dolt/go/libraries/doltcore/env" + "github.com/dolthub/dolt/go/libraries/utils/filesys" + "github.com/dolthub/dolt/go/store/datas" + "github.com/dolthub/dolt/go/store/nbs" + "github.com/fatih/color" +) + +func main() { + ctx := context.Background() + + var fs filesys.Filesys + fs = filesys.LocalFS + + dataDirFS, err := fs.WithWorkingDir(".") + if err != nil { + fmt.Println(color.RedString("Failed to set the data directory. %v", err)) + os.Exit(1) + } + + dEnv := env.Load(ctx, env.GetCurrentUserHomeDir, dataDirFS, doltdb.LocalDirDoltDB, doltversion.Version) + if dEnv.CfgLoadErr != nil { + fmt.Println(color.RedString("Failed to load the dolt config. %v", dEnv.CfgLoadErr)) + os.Exit(1) + } + if dEnv.DBLoadError != nil { + fmt.Println(color.RedString("Failed to load the database. %v", dEnv.DBLoadError)) + os.Exit(1) + } + + db := doltdb.HackDatasDatabaseFromDoltDB(dEnv.DoltDB) + cs := datas.ChunkStoreFromDatabase(db) + + if gs, ok := cs.(*nbs.GenerationalNBS); ok { + err := nbs.LoopOverTables(ctx, gs) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + } else { + fmt.Println("Not a generational chunk store") + os.Exit(1) + } +}