rfjakob/gocryptfs

shared storage flag causes getcwd to fail

harporoeder opened this issue · 9 comments

When utilizing the -sharedstorage flag creating a new shell inside a nested directory causes getcwd / pwd to start failing. This very specifically seems to be a problem with the first level of directories inside a decrypted directory. It does not happen with deeper directories. It does not happen without -sharedstorage. In my testing I used a totally fresh gocryptfs -init test bed that was not shared with anything like syncthing. This happens with both bash and sh.

Version: gocryptfs v2.0.1; go-fuse [vendored]; 2021-06-07 go1.16.5 linux/amd64

Here is an example:

> cd decrypted
> pwd
/home/user/decrypted
> bash (new shell here)
> pwd
/home/user/decrypted
> exit (exit the shell we just started)

> cd first
> pwd
/home/user/decrypted/first
> bash
> pwd
pwd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
> exit
> pwd
/home/user/decrypted/first

> cd second
> pwd
/home/user/decrypted/first/second
> bash
> pwd
/home/user/decrypted/first/second
> exit

Hi, thanks for the report, could you try latest master? We have better caching now, and as a part of that the directory handling has been refactored.

As for the increasing inode number, this is expected, and prevents hard links from being detected (possibly incorrectly due to concurrent modifications)

Hello @rfjakob

I tested again with master and have the same result.

> gocryptfs -version
gocryptfs v2.0.1-31-g2a9d70d; go-fuse v2.1.1-0.20210611132105-24a1dfe6b4f8; 2021-07-20 go1.16.5 linux/amd64

Another interesting case with -sharedstorage enabled:

> cd decrypted/first
> bash
> pwd
pwd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
> cd ..
> pwd
..
> cd first
> pwd
/home/user/decrypted/first

I did a little more digging. I see that stat . and stat .. always return the same inode value if you do it a bunch of times however if you stat directory that counter will update. The shell pwd built in is doing some caching magic so I tried with /usr/bin/pwd. Reading the source of /usr/bin/pwd it does get the inode from stat . then does a search of .. for the file that matches that inode. I am able to get this to happen now just using /usr/bin/pwd and stat now instead of opening a new shell. I can't fully explain the behavior still.

Perhaps changing stat . to update the inode in the same way that stat dir does would fix the issue.

> /usr/bin/pwd
/usr/bin/pwd: couldn't find directory entry in ‘..’ with matching i-node

Thanks for the analysis! Yes that explains it. The unstable inode number breaks the pwd algorithm. Actually, directories cannot have hard links, so I could make those stable.

That the ino of . and .. are stable is strange.

Interstingly, I cannot reproduce this here.

"/tmp/plain" is the mountpoint:

0 jakob@brikett:/tmp/plain$ /usr/bin/pwd
/tmp/plain
0 jakob@brikett:/tmp/plain$ cd subdir/
0 jakob@brikett:/tmp/plain/subdir$ /usr/bin/pwd
/tmp/plain/subdir

"strace /usr/bin/pwd" shows:

getcwd("/tmp/plain/subdir", 4096)       = 18

in other words, pwd asked the kernel instead of doing the ino comparison itself. But why doesn't your pwd do that?

I can repro now (don't know why):

1 jakob@brikett:/tmp/plain/subdir$ /usr/bin/pwd
/usr/bin/pwd: couldn't find directory entry in ‘..’ with matching i-node

strace:

getcwd(0x555b239a6500, 4096)            = -1 ENOENT (No such file or directory)

I found a much better way to disable hard links, preserving the original inode numbers. This should also fix the getcwd problem.

@rfjakob Thanks for the quick fix! I'll try out master and see how things go. I utilize gocryptfs + syncthing (and have other backups just in case something goes horribly wrong) for lots of my system state, and this should make the experience much better.