Looks interesting! I have a couple of security-related questions. Now, I've only skimmed the code, so you may have addressed these already, but I was hoping you could clarify a few things:
* Do you take any measures to ensure that the gpg binary loaded is the "correct" gpg binary? Could an attacker trick the filesystem into using a poisoned gpg binary that leaks secrets?
* Do you deal with the keys in any way? If so, do you mlock() them so they won't get swapped to disk unencrypted?
* Do you ensure that data written into your filesystem can't get swapped to disk before it's encrypted? For example, you might have to mlockall() before handling writes.
* Do you take any measures to prevent file descriptor exhaustion attacks? In your subprocess module, you fork() and exec() without closing the file descriptors held by your filesystem (including e.g. ones fed into your page_buffer implementation). Since the gpg binary would inherit the descriptors from the parent, could the gpg binary do Bad Things to your filesystem with them? Also, could gpg be e.g. unable to open /dev/random, or other important files, due to file descriptor exhaustion?
* If the "wrong" GPG binary is loaded, the game is likely already up: If an attacker has that degree of control over your machine, they're already on the other side of this airtight hatchway. They can attach to your running programs, read memory contents, and so forth, so compromising the GPG binary isn't necessary.
* Keys are handled by GPG, which normally should mlock key material.
* Part of my plan to switch to handling pages (rather than allowing data to be managed via a std::string) was to be able to use mlock() properly. I'll be adding that soon.
* Since the GPG binary is running as you, it could do Bad Things to the underlying filesystem (or filesystem exported by FUSE), but you do raise a point about closing file descriptors for general cleanliness.
Thanks for your reply. Just a couple of other things:
First, I see from your code that you don't specify an absolute path to gpg. If I can write to a directory in your PATH that gets searched before the location of your desired gpg binary, then I win. Depending on your PATH, I don't need privileges or even a user account--for example, using a browser exploit or some social engineering, I could drop a poisoned gpg into your Downloads directory (or anywhere in your /home or /tmp), and if your PATH searches in your /home first (or searches '.' first), I could get you to use my gpg instead.
Second, regarding preventing plaintext from getting swapped to disk before writing, you have to keep in mind that libfuse will obtain the plaintext from the kernel and then call your write() callback--you're not safe if you only mlock() the data that FUSE gives you, since the data could have swapped to disk between libfuse reading from the kernel and calling write(). Now, I don't know if libfuse mlock's the write buffer first (maybe it's a side-effect of FUSE splicing pages between the kernel and application?), but it is something to keep in mind.
Looks interesting! I have a couple of security-related questions. Now, I've only skimmed the code, so you may have addressed these already, but I was hoping you could clarify a few things:
* Do you take any measures to ensure that the gpg binary loaded is the "correct" gpg binary? Could an attacker trick the filesystem into using a poisoned gpg binary that leaks secrets?
* Do you deal with the keys in any way? If so, do you mlock() them so they won't get swapped to disk unencrypted?
* Do you ensure that data written into your filesystem can't get swapped to disk before it's encrypted? For example, you might have to mlockall() before handling writes.
* Do you take any measures to prevent file descriptor exhaustion attacks? In your subprocess module, you fork() and exec() without closing the file descriptors held by your filesystem (including e.g. ones fed into your page_buffer implementation). Since the gpg binary would inherit the descriptors from the parent, could the gpg binary do Bad Things to your filesystem with them? Also, could gpg be e.g. unable to open /dev/random, or other important files, due to file descriptor exhaustion?
Thanks!