aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Unterwurzacher2024-05-05 22:46:17 +0200
committerJakob Unterwurzacher2024-05-05 22:46:17 +0200
commita38507978442f28ace42ec0003c4a2bf61cb4a91 (patch)
treeddeaca750ba9c260249448d8817a321dab6c4e45
parentbbfbf37bd73f4aac333c7a65f80d5d977a548e20 (diff)
reverse: use incrementing inode number for gocryptfs.longname.*.name files
ed0a12b7337c2d88c027329f64e73070da17d5b3 already fixed the kernel side, now we also want the .name files to NOT appear hardlinked when just looking at the inode number. Relates-to: https://github.com/rfjakob/gocryptfs/issues/802
-rw-r--r--internal/fusefrontend_reverse/virtualnode.go11
-rw-r--r--tests/reverse/correctness_test.go16
-rw-r--r--tests/reverse/inomap_test.go4
3 files changed, 27 insertions, 4 deletions
diff --git a/internal/fusefrontend_reverse/virtualnode.go b/internal/fusefrontend_reverse/virtualnode.go
index 688f536..922cfa7 100644
--- a/internal/fusefrontend_reverse/virtualnode.go
+++ b/internal/fusefrontend_reverse/virtualnode.go
@@ -86,8 +86,15 @@ func (n *Node) newVirtualMemNode(content []byte, parentStat *syscall.Stat_t, ino
// Adjust inode number and size
rn := n.rootNode()
st := parentStat
- q := inomap.NewQIno(uint64(st.Dev), inoTag, uint64(st.Ino))
- st.Ino = rn.inoMap.Translate(q)
+ if inoTag == inoTagNameFile {
+ // No stable mapping for gocryptfs.longname.*.name files, instead use an
+ // incrementing counter. We don't want two of those files to ever have the
+ // same inode number, even for hard-linked files.
+ st.Ino = rn.inoMap.NextSpillIno()
+ } else {
+ q := inomap.NewQIno(uint64(st.Dev), inoTag, uint64(st.Ino))
+ st.Ino = rn.inoMap.Translate(q)
+ }
st.Size = int64(len(content))
st.Mode = virtualFileMode
st.Nlink = 1
diff --git a/tests/reverse/correctness_test.go b/tests/reverse/correctness_test.go
index 930048f..b335456 100644
--- a/tests/reverse/correctness_test.go
+++ b/tests/reverse/correctness_test.go
@@ -298,6 +298,10 @@ func TestSeekData(t *testing.T) {
// gocryptfs.longname.*.name of hardlinked files should not appear hardlinked (as the
// contents are different).
//
+// This means that
+// 1) They have a different NodeID, hence the kernel knows it's different files
+// 2) They have a different inode number, hence userspace knows they are not hard-linked.
+//
// https://github.com/rfjakob/gocryptfs/issues/802
func TestHardlinkedLongname(t *testing.T) {
if plaintextnames {
@@ -335,4 +339,16 @@ func TestHardlinkedLongname(t *testing.T) {
if test_helpers.Md5fn(matches[0]) == test_helpers.Md5fn(matches[1]) {
t.Errorf("Files %q are identical - that's wrong!", matches)
}
+
+ var st0 syscall.Stat_t
+ if err := syscall.Stat(matches[0], &st0); err != nil {
+ t.Fatal(err)
+ }
+ var st1 syscall.Stat_t
+ if err := syscall.Stat(matches[1], &st1); err != nil {
+ t.Fatal(err)
+ }
+ if st0.Ino == st1.Ino {
+ t.Errorf("Files %q have the same inode number - that's wrong!", matches)
+ }
}
diff --git a/tests/reverse/inomap_test.go b/tests/reverse/inomap_test.go
index aadb782..ff78f4c 100644
--- a/tests/reverse/inomap_test.go
+++ b/tests/reverse/inomap_test.go
@@ -143,7 +143,7 @@ func TestVirtualFileIno(t *testing.T) {
if origInos.child == cipherInos.name {
t.Errorf("name ino collision: %d == %d", origInos.child, cipherInos.name)
}
- if origInos.child&mask != cipherInos.name&mask {
- t.Errorf("name ino mismatch: %#x vs %#x", origInos.child, cipherInos.name)
+ if cipherInos.name < 1<<63 {
+ t.Errorf("name ino should be in spill space, but is actually %#x", cipherInos.name)
}
}