diff options
author | axtloss <axtlos@getcryst.al> | 2024-01-27 19:07:09 +0100 |
---|---|---|
committer | axtloss <axtlos@getcryst.al> | 2024-01-27 19:07:09 +0100 |
commit | 158e9d6eb8a74bc6ce3c3f2a9709de081568dc02 (patch) | |
tree | 607a25db5c5764fe7f10a746aee1a4e9420e8d81 | |
parent | 1b50046a214d81fe98c94a1220f7cbc1eeac669b (diff) | |
download | fsverify-158e9d6eb8a74bc6ce3c3f2a9709de081568dc02.tar.gz fsverify-158e9d6eb8a74bc6ce3c3f2a9709de081568dc02.tar.bz2 |
Add go project
Signed-off-by: axtloss <axtlos@getcryst.al>
Diffstat (limited to '')
-rw-r--r-- | Cargo.lock | 376 | ||||
-rw-r--r-- | Cargo.toml | 10 | ||||
-rw-r--r-- | cmd/root.go | 22 | ||||
-rw-r--r-- | cmd/verify.go | 32 | ||||
-rw-r--r-- | core/crypt.go | 25 | ||||
-rw-r--r-- | core/storage.go | 133 | ||||
-rw-r--r-- | fsverify-paper.md | 107 | ||||
-rw-r--r-- | go.mod | 8 | ||||
-rw-r--r-- | go.sum | 14 | ||||
-rw-r--r-- | main.go | 13 | ||||
-rw-r--r-- | src/core/mod.rs | 1 | ||||
-rw-r--r-- | src/core/storage.rs | 36 | ||||
-rw-r--r-- | src/main.rs | 5 | ||||
-rw-r--r-- | test.part | 5 |
14 files changed, 359 insertions, 428 deletions
diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 0c8f5f3..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,376 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "build_const" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "crc" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -dependencies = [ - "build_const", -] - -[[package]] -name = "darling" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbffa8f8e38810422f320ca457a93cf1cd0056dc9c06c556b867558e0d471463" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e172685d94b7b83800e3256a63261537b9d6129e10f21c8e13ddf9dba8c64d" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0618ac802792cebd1918ac6042a6ea1eeab92db34b35656afaa577929820788" -dependencies = [ - "darling_core", - "quote", - "syn", -] - -[[package]] -name = "data-encoding" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "fsverify" -version = "0.1.0" -dependencies = [ - "structsy", - "structsy-derive", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "libc" -version = "0.2.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "persy" -version = "0.11.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e315a205e09e7620071a71a98363fccc7a6b1463d6aac8fe1af052b9275562df" -dependencies = [ - "byteorder", - "crc", - "data-encoding", - "fs2", - "linked-hash-map", - "rand 0.7.3", - "unsigned-varint", - "zigzag", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro2" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.12", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "structsy" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20911814a42fc6d75d58cd6874f964df1dc48b36a5be89a72c764b9d7415f2c6" -dependencies = [ - "byteorder", - "data-encoding", - "persy", - "rand 0.8.5", -] - -[[package]] -name = "structsy-derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd60c3a557ca183247bbe8271f8b87927735974f1815ce126e2a31f924c441b0" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "unsigned-varint" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fdeedbf205afadfe39ae559b75c3240f24e257d0ca27e85f85cb82aa19ac35" - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "zigzag" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70b40401a28d86ce16a330b863b86fd7dbee4d7c940587ab09ab8c019f9e3fdf" -dependencies = [ - "num-traits", -] diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index ec29f99..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "fsverify" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -structsy="0.3" -structsy-derive="0.3"
\ No newline at end of file diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..d212e4e --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,22 @@ +package cmd + +import ( + "github.com/spf13/cobra" + "os" +) + +var rootCmd = &cobra.Command{ + Use: "fsverify", +} + +func init() { + rootCmd.AddCommand(NewVerifyCommand()) +} + +func Execute() { + // cobra does not exit with a non-zero return code when failing + // solution from https://github.com/spf13/cobra/issues/221 + if err := rootCmd.Execute(); err != nil { + os.Exit(1) + } +} diff --git a/cmd/verify.go b/cmd/verify.go new file mode 100644 index 0000000..3ceabbe --- /dev/null +++ b/cmd/verify.go @@ -0,0 +1,32 @@ +package cmd + +import ( + "github.com/axtloss/fsverify/core" + "github.com/spf13/cobra" +) + +func NewVerifyCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "verify", + Short: "Verify the root filesystem based on the given verification", + RunE: ValidateCommand, + SilenceUsage: true, + } + + return cmd +} + +func ValidateCommand(_ *cobra.Command, args []string) error { + node := core.Node{ + BlockStart: 0, + BlockEnd: 4 * 1000, + BlockSum: "test", + PrevNodeSum: "aaaa", + } + err := core.AddNode(node, nil) + if err != nil { + return err + } + _, err = core.ReadHeader("./test.part") + return err +} diff --git a/core/crypt.go b/core/crypt.go new file mode 100644 index 0000000..6de70e6 --- /dev/null +++ b/core/crypt.go @@ -0,0 +1,25 @@ +package core + +import ( + "crypto/sha256" + "fmt" + "io" + "os" + "strings" +) + +func calculateStringHash(a string) (string, error) { + hash := sha256.New() + hash.Write([]byte(a)) + hashInBytes := hash.Sum(nil)[:20] + return strings.TrimSpace(fmt.Sprintf("%x", hashInBytes)), nil +} + +func calculateFileHash(file *os.File) (string, error) { + hash := sha256.New() + if _, err := io.Copy(hash, file); err != nil { + return "", err + } + hashInBytes := hash.Sum(nil)[:20] + return strings.TrimSpace(fmt.Sprintf("%x", hashInBytes)), nil +} diff --git a/core/storage.go b/core/storage.go new file mode 100644 index 0000000..7475bef --- /dev/null +++ b/core/storage.go @@ -0,0 +1,133 @@ +package core + +import ( + "bufio" + "encoding/binary" + "encoding/json" + "fmt" + "os" + + bolt "go.etcd.io/bbolt" +) + +type Header struct { + MagicNumber int + Signature string + FilesystemSize int + TableSize int +} + +type Node struct { + BlockStart int + BlockEnd int + BlockSum string + PrevNodeSum string +} + +func ReadHeader(partition string) (Header, error) { + _, exist := os.Stat(partition) + if os.IsNotExist(exist) { + return Header{}, fmt.Errorf("Cannot find partition %s", partition) + } + part, err := os.Open(partition) + if err != nil { + return Header{}, err + } + defer part.Close() + + header := Header{} + reader := bufio.NewReader(part) + MagicNumber := make([]byte, 2) + Signature := make([]byte, 302) + FileSystemSize := make([]byte, 4) + TableSize := make([]byte, 4) + + _, err = reader.Read(MagicNumber) + MagicNum := binary.BigEndian.Uint16(MagicNumber) + if MagicNum != 0xACAB { // The Silliest of magic numbers + return Header{}, err + } + header.MagicNumber = int(MagicNum) + + _, err = reader.Read(Signature) + if err != nil { + return Header{}, err + } + _, err = reader.Read(FileSystemSize) + if err != nil { + return Header{}, err + } + _, err = reader.Read(TableSize) + if err != nil { + return Header{}, err + } + + header.Signature = string(Signature) + header.FilesystemSize = int(binary.BigEndian.Uint16(FileSystemSize)) + header.TableSize = int(binary.BigEndian.Uint16(TableSize)) + return header, nil +} + +func OpenDB() (*bolt.DB, error) { + _, exist := os.Stat("my.db") // TODO: use configuration file for db path + if os.IsNotExist(exist) { + os.Create("my.db") + } + db, err := bolt.Open("my.db", 0777, nil) + if err != nil { + return nil, err + } + return db, nil +} + +func AddNode(node Node, db *bolt.DB) error { + var err error + var deferDB bool + if db == nil { + db, err = OpenDB() + if err != nil { + return err + } + deferDB = true + } + err = db.Update(func(tx *bolt.Tx) error { + nodes, err := tx.CreateBucketIfNotExists([]byte("Nodes")) + if err != nil { + return err + } + if buf, err := json.Marshal(node); err != nil { + return err + } else if err := nodes.Put([]byte(node.PrevNodeSum), buf); err != nil { + return err + } + return nil + + }) + if deferDB { + defer db.Close() + } + return err +} + +func GetNode(checksum string, db *bolt.DB) (Node, error) { + var err error + var deferDB bool + if db == nil { + db, err = OpenDB() + if err != nil { + return Node{}, err + } + deferDB = true + } + var node Node + err = db.View(func(tx *bolt.Tx) error { + nodes := tx.Bucket([]byte("Nodes")) + app := nodes.Get([]byte(checksum)) + err := json.Unmarshal(app, &node) + return err + }) + if deferDB { + defer db.Close() + } + return node, err +} diff --git a/fsverify-paper.md b/fsverify-paper.md new file mode 100644 index 0000000..6093752 --- /dev/null +++ b/fsverify-paper.md @@ -0,0 +1,107 @@ +# Fsverify Partition +The FsVerify partition contains a header with the necessary metadata for the filesystem verification, and a bbolt database containing all File and Directory nodes to be checked. + +## Partition Header +`<magic number> <signature> <filesystem size> <table size>` + +Field|Size|Purpose|Value +-----|----|-------|----- +magic number|2 bytes|sanity check|0xACAB +signature|302 bytes|minisign signature| +filesystem size|4 bytes|size of the original filesystem in gb +table size|4 bytes| size of the table in mb + +Due to the filesystem and table size field, which can go up to 0xFFFFFFFF (16777215), the maximum supported partition size and table size is 16777215gb (~16pb) + +The entire Head should be a total of 312 bytes long, reaching from 0x0 to 0x138 + +## Partition Contents / Database +The main database containing the checksums is a [bbolt](https://github.com/etcd-io/bbolt) datbase consisting of a single bucket called `Nodes` + +Each element in this Bucket is a json serialization of the `Node` struck: +```go +type Node struct { + BlockStart int + BlockEnd int + BlockSum string + PrevNodeSum string +} +``` + +Field|Purpose +----|---- +BlockStart|The Hex offset at which the block begins +BlockEnd|The Hex offset at which the block ends +BlockSum|The checksum of the block +PrevNodeSum|The checksum of all the fields of the previous field as a checksum + +Each block is 4kb big, if the partition size does not allow an even split in 4kb sectors, the partition will be split as good as possible, with a smaller block as the last sector. + +Beyond beign signed with minisign, each Node is verified through the PrevNodeSum Field, which gets generated by adding all fields of the previous block together and calculating the checksum of the resulting string: +``` ++-----+ +------+ +------+ +------+ +|0x000| |0xFA0 | |0x1F40| |0x3E80| +|0xFA0| --> |0x1F40| --> |0x3E80| -----> |0x4E20| +|aFcDb| |cDfaB | |4aD01 | |2FdCa | +| | |adBfa | |1Ab3d | |bAd31 | ++-----+ +------+ +------+ +------+ +``` +through this, the slightest change in one of the nodes will result in a wrong hash for every node following the modified one: +``` + Checksum do not match + | ++-----+ +------+ +------+ | +------+ +|0x000| |0xFA0 | |0x1F40| | |0x3E80| +|0xFA0| --> |0x1F40| --> |0x3E80| --|--> |0x4E20| +|aFcDb| |AAAAA | <-+ |4aD01 | | |2FdCa | +| | |adBfa | | |1Ab3d | <-+--> |bAd31 | ++-----+ +------+ | +------+ +------+ + | + Modified value +``` + + +# Verification Process +The verification step consists of multiple steps: + +1. Reading the signature and public key +2. Reading the database +3. Verifying the database using the previously read keys +4. Verifying the target partition using the database + +## Reading the Signature and Public Key +Reading the signature is quite simple, it is part of the Fsverify partition header and is read at an offset starting at 0x4 up to 0x132 (total 302 Bytes). + +The Public Key however is not stored in the partition, instead it can be stored in multiple ways +- A different partition that has been verified in a different way +- An external storage device that can always be trusted +- The TPM2 +- Secureboot verified UKI + +The most secure option for most average Desktop computers would be the TPM2 or a secureboot verified UKI, embedded devices however would greatly benefit from a partition that cannot be modified in any way, in which the key is stored + +In the case that the hardware itself cannot be trusted, read-only external storage can be used to store the key, this can ensure that the public key is never modified, assuming the person carrying said storage device does not loose it. + +## Reading the database +The Database is simply read from 0x13A until the size of the table is reached as specified in the headers. If the table would be 1mb big, it would reach from 0x13A until 0xF437A (1000000bytes/1mb) + +## Verifying the database using the previously read keys +Now that the signature, public key and database are read, they can be verified using [minisign](https://jedisct1.github.io/minisign/). + +If the verification fails, a protected rootfs is used to display a warning to the user and/or completely shut down the device. + +## Verifying the target partition using the database +If the database was verified succesfully, it can now be used to verify the actual partition. + +Each entry in the database is read and the according data in the specified offset area is verified to the hash. At the same time, the database verifies itself by using the `PrevNodeSum` property of the `Node` object. + +If the verification fails, be it due to a mismatch in `PrevNodeSum` or a mismatch in the Block checksum, the same protected rootfs as with the database verification is used to display a warning to the user and/or completely shut down the device. + +# When/how to run fsverify +Fsverify can theoretically be run at any point of the boot process, however it is the most useful when run +- before the init system (systemd, openrc, runit, etc.) launches, but after the initramfs is exited +- while the system is still inside the initramfs and the real system is not even mounted yet + +The second option is the preffered option, as it not only makes the modification of fsverify more difficult, but also, in the case that secureboot and UKI is set up correctly, can not be modified whatsoever without failing the secureboot checks, allowing for an extra layer of verification that the fsverify binary has not been manipulated. + +If neither UKI nor secureboot are implemented however, the first option will work just as well and could possibly be easier to implement, as it simply takes an init script that executes the fsverify binary before the init system launches. This order is important, to ensure that no extra binaries are executed before it is ensured that they can be trusted. @@ -1,3 +1,11 @@ module github.com/axtloss/fsverify go 1.21.6 + +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/cobra v1.8.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + go.etcd.io/bbolt v1.3.8 // indirect + golang.org/x/sys v0.4.0 // indirect +) @@ -0,0 +1,14 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= +go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -0,0 +1,13 @@ +package main + +import ( + "github.com/axtloss/fsverify/cmd" +) + +var ( + Version = "0.1.0" +) + +func main() { + cmd.Execute() +} diff --git a/src/core/mod.rs b/src/core/mod.rs deleted file mode 100644 index e626ba5..0000000 --- a/src/core/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod storage;
\ No newline at end of file diff --git a/src/core/storage.rs b/src/core/storage.rs deleted file mode 100644 index a4bb1bb..0000000 --- a/src/core/storage.rs +++ /dev/null @@ -1,36 +0,0 @@ - -use structsy::{Structsy, StructsyError, StructsyTx}; -use structsy_derive::{Persistent, queries}; - -#[derive(Persistent)] -struct DirectoryNode { - dirname: string, - path: string, - files: Vec<FileNode> -} - -#[derive(PersistentEmbedded)] -struct FileNode { - filename: string, - path: string, - hash: string, - combined_hash: string, -} -#[queries(MyData)] -trait FileNode { - fn search(self, name:&str) -> Self; -} - -pub fn open_db(path: string) -> Result<Structsy, StructsyError> { - let db = Structsy::open(path)?; - db.define::<DirectoryNode>()? -} - - -pub fn add(dir: DirectoryNode) -> Result<(), StructsyError> { - let db = open_db("my_db.db")?; - let mut tx = db.begin()?; - tx.insert(&dir)?; - tx.commit()?; - Ok(()) -}
\ No newline at end of file diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index bcab8e7..0000000 --- a/src/main.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod core; - -fn main() { - -}
\ No newline at end of file diff --git a/test.part b/test.part new file mode 100644 index 0000000..47eaf53 --- /dev/null +++ b/test.part @@ -0,0 +1,5 @@ +¬«untrusted comment: signature from minisign secret key +RUS8zzN9EH8E8LhaWGpMxonFWnskIIagVGUtqA5+46zTNTx3vCXUq8/WcFvVHn4GA9TFJG9SY0D3eRxT7taAlkuXSiJPcBWQlg4= +trusted comment: timestamp:1706374640 file:fsverif hashed +2ct2SBg/JWLG5awSlfVnlid/PIWcw2P72JvgXpGqMSXvVG+p0kOCT53xIfzAFLoHrH6sJmfke77JLnWIA8kVCg== +ªªªªÿÿÿÿ
\ No newline at end of file |