bubblejail
bubblejail copied to clipboard
Add encrypted 'home' support
Description
Hi, I'm currently using 'gocryptfs' and I feel that it could be nicely integrated into bubblejail, specially for automatically umount it after closing the sandbox (maybe it could auto close due inactivty?).
I open this issue for share some comments about it. I would like to do some draft for gocrypts having in mind that I should be easily integrated with other alternatives.
Gocrypts (and most encrypt fs) uses a folder for save the data encrypted, so it could just be saved on '~/.local/share/bubblejail/instances/instance/secret' and then mounted on its respective 'home'.
Hello.
What do you think the UI/UX would be?
If a user tries to run the instance that has an encrypted home they should be prompted a password entry?
Or should the password be stored somewhere? Kind of not very useful if the password would be stored in the instance configuration directory.
There is actually a freedesktop-secrets API that can be used to securely store passwords. It can be implemented to store the directories keys. I made the binds for it with my D-Bus library that I plan to integrate but I have heard that Alpine Linux does not like D-Bus.
I had an idea of some generic mechanism of instance home preprocessors. For example, creating a BtrFs subvolme.
BTW there is Open a blank issue.
option when creating a new issue but it is kind of small and hard to notice so I guess I will add a template Suggestion/Idea
Keepassxc implemented the secrets API in 2.5.0: https://keepassxc.org/blog/2019-10-26-2.5.0-released/
(so it is not GNOME/KDE specific)
Hello.
What do you think the UI/UX would be?
If a user tries to run the instance that has an encrypted home they should be prompted a password entry?
On creation the instance should be flagged as 'encrypted' and the password prompted for initalization. Then, on run it should check the 'encrypted' option and handle the mounting/unmounting before/after launching bwrap.
Or should the password be stored somewhere? Kind of not very useful if the password would be stored in the instance configuration directory.
There is actually a freedesktop-secrets API that can be used to securely store passwords. It can be implemented to store the directories keys. I made the binds for it with my D-Bus library that I plan to integrate but I have heard that Alpine Linux does not like D-Bus.
I think that there are two use cases for this. The first is having a last security layer in case the whole system gets compromised or stolen while it's unlocked. So having the encrypted sandbox stopped and unlock password saved outside seems mandatory.
The other use case is a secure way for share/backup some folder in public clouds like dropbox. In this scenario running it 24h or having a passworldess start seems ok.
I had an idea of some generic mechanism of instance home preprocessors. For example, creating a BtrFs subvolme.
I think that it would be nice, and probably very easy to achieve with it. But for some users maybe a more clearly UI just for encryption it's nice.
On creation the instance should be flagged as 'encrypted' and the password prompted for initalization.
It is possible. There is even python module to enter passwords: https://docs.python.org/3/library/getpass.html#getpass.getpass
The other use case is a secure way for share/backup some folder in public clouds like dropbox. In this scenario running it 24h or having a passworldess start seems ok.
To be honest this sounds like something backup script or software should be taking care of. There are instruction on how to run gocryptfs in reverse mode: https://wiki.archlinux.org/title/Gocryptfs#Example_using_reverse_mode
But for some users maybe a more clearly UI just for encryption it's nice.
This is what secrets API should be taking care of. Unless you think there should be another Qt application that should come with bubblejail which should popup when asks for password. But that would be very difficult to implement and maintain.
The other use case is a secure way for share/backup some folder in public clouds like dropbox. In this scenario running it 24h or having a passworldess start seems ok.
To be honest this sounds like something backup script or software should be taking care of. There are instruction on how to run gocryptfs in reverse mode: https://wiki.archlinux.org/title/Gocryptfs#Example_using_reverse_mode
Yes, reverse mode has more sense in this scenario. Maybe it could be seen as a different bubblejail freature (remote backup?). I'm really only interested on extra protection for sensitive data, so asking for the password on each run seems better.
Maybe it's out of bubblejail scope but would be nice that it notifies if some process outside the sandbox tries to read/write something. It will probably need root permissions.
But for some users maybe a more clearly UI just for encryption it's nice.
This is what secrets API should be taking care of. Unless you think there should be another Qt application that should come with bubblejail which should popup when asks for password. But that would be very difficult to implement and maintain.
I would try to do a first draft without secrets/password storage.
@donob4n I created 11a886c0cc542224cd8a7023fea8fc7afdf31c9a in the branch gocryptfs-test
It is a very rough draft. The command line arguments are not final.
Creating instance with gocryptfs home directory:
create --profile generic --no-desktop-entry --home-plugin gocryptfs_home -- test
The gocryptfs will ask for password to create a new encrypted dir.
Running it:
bubblejail run test chromium
You can only run it from terminal currently because it depends on gocryptfs asking for password. In release version it definitely will need D-Bus Secrets API.
If you use ext4 you can use a transparent encryption [folder-only-encrpytion] with a custom pass for every folder in the ext4 system.
I wouldn't recomment gocryptfs!!!
But I am not sure, if this work if you use the systemd-homed encrypted by ext4 plus the subfolder encryption by ext4! But you could add a ext4 filesystem and mount them in the:
~/.local/share/bubblejail/instances/
and add then for every instances an custom password!
@donob4n I created 11a886c in the branch gocryptfs-test
It is a very rough draft. The command line arguments are not final. ... Running it:
bubblejail run test chromium
Wow I just tested it and looks great.
You can only run it from terminal currently because it depends on gocryptfs asking for password. In release version it definitely will need D-Bus Secrets API.
Well, probably is the best option for normal users (maybe the more pytonic way too?), but as an intent of minimalist user I like pinentry[1] concept wich has gtk and qt backends and even a dmenu. It also has at least one python package[2].
It looks that using -extpass CMD
gocrypts should call pinentry easily. So it doesn't require even python handling of it.
[1] - https://www.gnupg.org/related_software/pinentry/index.html [2] - https://pypi.org/project/pynentry/
If you use ext4 you can use a transparent encryption [folder-only-encrpytion] with a custom pass for every folder in the ext4 system.
Well, I'm currently using btrfs and also feel that this option would loose some portability.
I wouldn't recomment gocryptfs!!!
Probably this is not the best place for discussing this but if you have some sources supporting it I will take a look.
It looks that using
-extpass CMD
gocrypts should call pinentry easily. So it doesn't require even python handling of it
Good find.
Should be pretty simple to implement.
Well, pinentry process options or commands from STDIN. So an basic execution for a 'foo' password looks like:
echo "GETPIN" | pinentry
OK pinentry-bemenu 0.9.0
D foo
OK
So maybe passing it to sed (I'm trying but I haven't got it yet), or maybe handling the stdout with python.
EDIT:
I get this working:
echo "GETPIN" | pinentry | sed -nr '/^D (.+)/s//\1/p'
But not sure how to pass to subprocess.call, maybe gocryptfs doesn't support a shell command and needs to wrapper it on a script.
It seems that others instances fail due missing home_plugins dir:
FileNotFoundError: [Errno 2] No such file or directory: '/home/donoban/.local/share/bubblejail/instances/..../home_plugins
It seems that others instances fail due missing home_plugins dir:
FileNotFoundError: [Errno 2] No such file or directory: '/home/donoban/.local/share/bubblejail/instances/..../home_plugins
Do you have entire stack trace?
It seems that others instances fail due missing home_plugins dir:
FileNotFoundError: [Errno 2] No such file or directory: '/home/donoban/.local/share/bubblejail/instances/..../home_plugins
Do you have entire stack trace?
Traceback (most recent call last):
File "/usr/bin/bubblejail", line 14, in <module>
bubblejail_main()
File "/usr/lib/python3.10/site-packages/bubblejail/bubblejail_cli.py", line 418, in bubblejail_main
args.func(args)
File "/usr/lib/python3.10/site-packages/bubblejail/bubblejail_cli.py", line 125, in run_bjail
run_instace(
File "/usr/lib/python3.10/site-packages/bubblejail/bubblejail_cli.py", line 109, in run_instace
async_run(
File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete
return future.result()
File "/usr/lib/python3.10/site-packages/bubblejail/bubblejail_instance.py", line 265, in async_run_init
async with init:
File "/usr/lib/python3.10/site-packages/bubblejail/bubblejail_instance.py", line 544, in __aenter__
for plugin_path in self.plugins_dir.iterdir():
File "/usr/lib/python3.10/pathlib.py", line 1017, in iterdir
for name in self._accessor.listdir(self):
FileNotFoundError: [Errno 2] No such file or directory: '/home/donoban/.local/share/bubblejail/instances/....../home_plugins'
I forgot that old instances are not going to have home_plugins
. Looks trivial to fix.
Should be fixed now.
https://github.com/igo95862/bubblejail/commit/6aaf100eaceca1c3130e22a6ba08f99a4c378e69#diff-bd0ff776003d17d9b61bf00dea31c1a7621b9074e6780917c5dcf38cc65ba967R545
If you use ext4 you can use a transparent encryption [folder-only-encrpytion] with a custom pass for every folder in the ext4 system.
Well, I'm currently using btrfs and also feel that this option would loose some portability.
I wouldn't recomment gocryptfs!!!
Probably this is not the best place for discussing this but if you have some sources supporting it I will take a look.
Here is an tutorial...
https://wiki.gentoo.org/wiki/Ext4_encryption
Hello all.
I just came to this issue as I would like to lock some apps on my system.
If I understood the patch correctly, it mounts the encrypted filesystem on the host and then binds it to bubblejail instance. This makes the files available to all the processes of the user, until the instance is closed.
I was wondering whether it's possible to mount the encrypted filesystem directly inside the bubblewrap's mount namespace, hiding it from the host system.
I will do some more research and I will post back.
Do you mean something like a FUSE filesystem? Probably possible but I have not experimented with it.
I was wondering whether it's possible to mount the encrypted filesystem directly inside the bubblewrap's mount namespace, hiding it from the host system.
You seem to have a misunderstanding about bubblewraps security model.
- The host it privileged, the child is unprivileged
- The security boundary is oneway
- ==> Everything inside from bubblewrap is accessible/controllable from the host.
- In fact bubblewrap weaks the isolation in the host->child direction.
$ sleep 1m & $ gdb -p $(pidof sleep) ptrace: Operation not permitted. $ bwrap --dev-bind / / sleep 1m & $ gdb -p $(pidof sleep) successfully attached
- The mountnamespace can be inspected from
/proc/<pid>/root
or just by joining it.
I hadn't realized that /proc/$pid/root is accessible by anyone.
I was only aware of nsenter
requiring sudo and thought this idea is secure.
Back to the drawing board...
nsenter
does not require sudo unless your kernel has unpriviledged user namespaces disables.
My kernel (linux-zen on Arch) has unprivileged namespaces enabled (CONFIG_USER_NS_UNPRIVILEGED=y
), but I need sudo
to enter the mount namespace of a bubblejailed app.
$ nsenter --mount=/proc/<pid from bubblejailed app>/ns/mnt bash
> nsenter: reassociate to namespace 'ns/mnt' failed: Operation not permitted
$ sudo nsenter --mount=/proc/<pid from bubblejailed app>/ns/mnt bash
> [root@arch /]#
If you use --user-parent
option that I added to nsenter
you can easily enter bubblejail namespaces:
nsenter --preserve-credentials --user-parent --mount --target <pid of sandboxed app>
When --dev
option is used with bwrap it will create an intermediate user namespace only accessible with ioctl. The --user-parent
option will fetch the parent user namespace from the mount namespace and enter it before entering the mount namespace.
The reason the root works is probably because it holds the CAP_SYS_ADMIN for all descendant namespaces.
Thank you for the explanation on nsenter
.
As it turns out, namespaces may not be a good option for implementing encryption at runtime.
So, I came up with a completely different, hacky, solution.
I remembered how proot
works. It overrides syscalls via LD_PRELOAD
.
My idea is to override the filesystem related calls (stat
, open
, etc.) and handle the encryption and decryption at the application level, without actually mounting anything.
Since, this will override the syscalls, instead of mounting an encrypted filesystem, there will be no way for other programs to read the raw files.
This certainly complicates things a lot and seems very difficult to maintain and secure.
It overrides syscalls via LD_PRELOAD.
LD_PRELOAD
overrides library functions not syscalls. Programs calling the raw syscalls will break.
Since, this will override the syscalls, instead of mounting an encrypted filesystem, there will be no way for other programs to read the raw files.
Read my comment above regarding security model again. The child is less privileged. You can easily ptrace or whatever it.
In order to protect a process from other processes you either have to move the process you want to protect upwards / sidewards or move all processes from whom you want to protect downwards. You can not move a process downwards to secure it. Moving downwards secures everything from it. In practice this means you have to switch to a different UID.
Sorry @rusty-snake, at first I hadn't fully understood your security model comment. Now I get it.
Also, I made a mistake. proot
is based on ptrace
, not LD_PRELOAD
. Source: https://github.com/proot-me/proot/blob/master/doc/proot/manual.rst#description
In practice this means you have to switch to a different UID.
So, the only solution is to daemonize bubblejail as root (or make it setuid) and have it execute the jails as different UID, on the X/Wayland session of the current user?
Your welcome.
to daemonize bubblejail as root (or make it setuid) and have it execute the jails as different UID
Simplified yes. uid switching can be implemented in several ways
So, the only solution is to
SELinux would also be an solution I think. But much more complicated and not supported everywhere.
X
Lets programs control other programs.
Not entirely sure from what you are trying to encrypt files from. Is it against other sandboxes or your user overall?