Security review of 912f7c1: the mkfs wrapper trusts no sibling claim; the internal-place helper fails closed
gates / gates (push) Successful in 25s

- felhom-mkfs-guarded: the 0.158.0 exemption for a sibling part mounted at /mnt/<name> + under /mnt/felhom-drives is
  removed — the agent can make that corroborating mount itself. Every mount of every node outside /mnt/felhom-drives
  refuses (kernel mount table); an unlistable disk refuses. CandidatePartition.Formattable is false for every part of a
  disk with a mounted node, so it is never offered for formatting (attach still is).
- felhom-internal-place: a failed lvs listing, a listing without the pool, or a blkid exit other than 0/2 refuses
  (they read as "nothing promised" / "no signature" before).
Every new test was seen failing against the 0.158.0 versions.

Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
This commit is contained in:
2026-10-16 04:02:00 +02:00
parent 888a98571b
commit 98f3cdd76a
7 changed files with 120 additions and 33 deletions
+20 -1
View File
@@ -13,7 +13,8 @@ import (
// A disk that passed the WHOLE-disk unclaimed filter (classifyClaim: not the system disk, no LVM/ZFS/RAID/LUKS/swap
// member on any node, no foreign mount on any node) also lists its partitions, each with its own state:
//
// empty no filesystem, no children → „format this part" (self-serve: the agent's probe says blank)
// empty no filesystem, no children → „format this part" (self-serve: the agent's probe says blank) —
// only while NO part of the disk is mounted (Formattable)
// filesystem ext4/xfs (mountable) or another fs → „use this part" when mountable; „format this part" only through
// the customer-confirmed data-bearing path (the agent's own probe)
// in_use already Felhom's own drive → shown, never offered (it is a registered drive already)
@@ -32,6 +33,10 @@ type CandidatePartition struct {
Mountable bool `json:"mountable"`
DurableID string `json:"durable_id,omitempty"` // uuid:<fs-uuid> — the attach key ("" when empty)
MountedAt string `json:"mounted_at,omitempty"` // in_use: Felhom's own mount
// Formattable is false when ANY node of the disk is mounted (another part in use): the root mkfs wrapper refuses
// every mount outside /mnt/felhom-drives on the disk and deliberately does not trust a sibling that claims to be
// Felhom's own (a compromised agent could fake that). Such a part can still be USED (attach erases nothing).
Formattable bool `json:"formattable"`
}
const (
@@ -55,6 +60,19 @@ func candidatePartitions(lsblkJSON []byte, wholeName string, sizeOf func(string)
if d.Name != wholeName {
continue
}
diskMounted := d.MountPoint != ""
var walk func(n lsblkDev)
walk = func(n lsblkDev) {
if n.MountPoint != "" {
diskMounted = true
}
for _, c := range n.Children {
walk(c)
}
}
for _, c := range d.Children {
walk(c)
}
for _, p := range d.Children {
if len(p.Children) > 0 || memberFSTypes[p.FSType] {
continue // LVM/mapper on it, or a member: not a place (the disk filter refuses these anyway)
@@ -74,6 +92,7 @@ func candidatePartitions(lsblkJSON []byte, wholeName string, sizeOf func(string)
c.DurableID = "uuid:" + u
}
}
c.Formattable = c.State != PartInUse && !diskMounted
out = append(out, c)
}
}
+18
View File
@@ -71,3 +71,21 @@ func TestPartitions_UncorroboratedMountIsNotOffered(t *testing.T) {
}
}
}
// The root wrapper refuses any format on a disk with a mounted node (and trusts no „it is Felhom's own" claim), so a
// part next to a mounted one is never offered for formatting — only for use. Positive control: an unmounted disk.
func TestPartitions_FormattableOnlyWhenNothingOnTheDiskIsMounted(t *testing.T) {
m := listParts(map[string]bool{"/mnt/films": true})
for dev, p := range m {
if p.Formattable {
t.Fatalf("%s: a part of a disk with a mounted part must not be formattable: %+v", dev, p)
}
}
free := `{"blockdevices":[{"name":"sdc","fstype":null,"mountpoint":null,"children":[
{"name":"sdc1","fstype":null,"mountpoint":null},{"name":"sdc2","fstype":"ext4","mountpoint":null}]}]}`
got := candidatePartitions([]byte(free), "sdc", func(string) int64 { return 1 << 30 }, func(string) int { return 1 },
func(string) (string, bool) { return "u", true }, nil)
if len(got) != 2 || !got[0].Formattable || !got[1].Formattable {
t.Fatalf("parts of an unmounted disk are formattable, got %+v", got)
}
}