| 1 | package rootstate |
| 2 | |
| 3 | import "testing" |
| 4 | |
| 5 | func TestPlan14PersistentIdentityBootLocalNumbers(t *testing.T) { |
| 6 | p := FileIdentity{Boot: "boot-one", Filesystem: "fs", Handle: "handle", MountRoot: "/", MountPoint: "/", MountNamespace: "mnt:[1]", Device: 1, Inode: 2, Mount: 3, UID: 4, GID: 5, Mode: 0100000} |
| 7 | if !p.Same(p) { |
| 8 | t.Fatal("same identity refused") |
| 9 | } |
| 10 | unknown := FileIdentity{Device: 1, Inode: 2} |
| 11 | if unknown.Same(unknown) { |
| 12 | t.Fatal("numeric identity without a boot acquired authority") |
| 13 | } |
| 14 | next := p |
| 15 | next.Boot = "boot-two" |
| 16 | next.Device = 7 |
| 17 | next.Mount = 8 |
| 18 | if !p.Same(next) { |
| 19 | t.Fatal("cross-boot device numbers used as identity") |
| 20 | } |
| 21 | next.Boot = p.Boot |
| 22 | if p.Same(next) { |
| 23 | t.Fatal("same-boot replacement accepted") |
| 24 | } |
| 25 | for _, field := range []string{"filesystem", "handle", "mount", "inode", "uid", "gid", "type", "mode", "absent"} { |
| 26 | next = p |
| 27 | next.Boot = "boot-two" |
| 28 | switch field { |
| 29 | case "filesystem": |
| 30 | next.Filesystem = "other" |
| 31 | case "handle": |
| 32 | next.Handle = "other" |
| 33 | case "mount": |
| 34 | next.MountPoint = "other" |
| 35 | case "inode": |
| 36 | next.Inode++ |
| 37 | case "uid": |
| 38 | next.UID++ |
| 39 | case "gid": |
| 40 | next.GID++ |
| 41 | case "type": |
| 42 | next.Mode ^= 0040000 |
| 43 | case "mode": |
| 44 | next.Mode++ |
| 45 | case "absent": |
| 46 | next.Boot = "" |
| 47 | } |
| 48 | if p.Same(next) { |
| 49 | t.Fatal("substitution accepted", field) |
| 50 | } |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | func TestPlan14PersistentDeviceIdentity(t *testing.T) { |
| 55 | a := FileIdentity{Device: 259, Inode: 7, Boot: "before", Filesystem: "ext4:fs", Handle: "abcd", HandleType: 1, Mount: 64, MountRoot: "/", MountPoint: "/", MountNamespace: "mnt:[1]", Mode: 0100644} |
| 56 | b := a |
| 57 | b.Boot, b.Device, b.Mount = "after", 513, 127 |
| 58 | if !a.Same(b) { |
| 59 | t.Fatal("device renumbering rejected persistent identity") |
| 60 | } |
| 61 | for _, mutate := range []func(*FileIdentity){ |
| 62 | func(b *FileIdentity) { b.Boot = a.Boot }, |
| 63 | func(b *FileIdentity) { b.Handle = "reused-inode" }, |
| 64 | func(b *FileIdentity) { b.Filesystem = "other" }, |
| 65 | func(b *FileIdentity) { b.MountRoot = "/replacement" }, |
| 66 | func(b *FileIdentity) { b.MountPoint = "/etc" }, |
| 67 | func(b *FileIdentity) { b.UID = 1000 }, |
| 68 | func(b *FileIdentity) { b.Mode = 0100664 }, |
| 69 | } { |
| 70 | bad := b |
| 71 | mutate(&bad) |
| 72 | if a.Same(bad) { |
| 73 | t.Fatal("substitution accepted", bad) |
| 74 | } |
| 75 | } |
| 76 | clone := a |
| 77 | clone.MountNamespace = "mnt:[2]" |
| 78 | clone.Mount++ |
| 79 | if !a.Same(clone) { |
| 80 | t.Fatal("root namespace clone lost persistent identity") |
| 81 | } |
| 82 | clone.MountPoint = "/etc" |
| 83 | if a.Same(clone) { |
| 84 | t.Fatal("namespace clone hid substituted mount") |
| 85 | } |
| 86 | old := FileIdentity{Device: a.Device, Inode: a.Inode} |
| 87 | if old.Same(a) || a.Same(old) { |
| 88 | t.Fatal("historical identity acquired inferred proof") |
| 89 | } |
| 90 | } |
| 91 | |