bubblejail icon indicating copy to clipboard operation
bubblejail copied to clipboard

Add encrypted 'home' support

Open donob4n opened this issue 2 years ago • 32 comments

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'.

donob4n avatar Jun 08 '22 11:06 donob4n

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.

igo95862 avatar Jun 08 '22 11:06 igo95862

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

igo95862 avatar Jun 08 '22 11:06 igo95862

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)

igo95862 avatar Jun 08 '22 12:06 igo95862

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.

donob4n avatar Jun 08 '22 12:06 donob4n

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.

igo95862 avatar Jun 08 '22 14:06 igo95862

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 avatar Jun 08 '22 15:06 donob4n

@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.

igo95862 avatar Jun 19 '22 19:06 igo95862

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!

Nonie689 avatar Jun 22 '22 12:06 Nonie689

@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/

donob4n avatar Jun 26 '22 14:06 donob4n

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.

donob4n avatar Jun 26 '22 14:06 donob4n

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.

igo95862 avatar Jun 26 '22 15:06 igo95862

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.

donob4n avatar Jun 26 '22 15:06 donob4n

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

donob4n avatar Jun 26 '22 16:06 donob4n

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?

igo95862 avatar Jun 26 '22 16:06 igo95862

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'

donob4n avatar Jun 26 '22 17:06 donob4n

I forgot that old instances are not going to have home_plugins. Looks trivial to fix.

igo95862 avatar Jun 26 '22 17:06 igo95862

Should be fixed now.

https://github.com/igo95862/bubblejail/commit/6aaf100eaceca1c3130e22a6ba08f99a4c378e69#diff-bd0ff776003d17d9b61bf00dea31c1a7621b9074e6780917c5dcf38cc65ba967R545

igo95862 avatar Jun 26 '22 17:06 igo95862

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

Nonie689 avatar Aug 05 '22 20:08 Nonie689

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.

jim3692 avatar Jul 08 '24 09:07 jim3692

Do you mean something like a FUSE filesystem? Probably possible but I have not experimented with it.

igo95862 avatar Jul 08 '24 09:07 igo95862

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.

rusty-snake avatar Jul 08 '24 11:07 rusty-snake

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...

jim3692 avatar Jul 09 '24 07:07 jim3692

nsenter does not require sudo unless your kernel has unpriviledged user namespaces disables.

igo95862 avatar Jul 09 '24 07:07 igo95862

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 /]#

jim3692 avatar Jul 09 '24 07:07 jim3692

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.

igo95862 avatar Jul 09 '24 08:07 igo95862

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.

jim3692 avatar Jul 09 '24 09:07 jim3692

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.

rusty-snake avatar Jul 09 '24 10:07 rusty-snake

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?

jim3692 avatar Jul 09 '24 11:07 jim3692

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.

rusty-snake avatar Jul 09 '24 12:07 rusty-snake

Not entirely sure from what you are trying to encrypt files from. Is it against other sandboxes or your user overall?

igo95862 avatar Jul 09 '24 13:07 igo95862