bwscripts
bwscripts copied to clipboard
Isolating D-Bus
I'm using an approach similar to yours to sandbox a few applications with bubblewrap. It's still somewhat experimental, but I've managed to isolate D-Bus pretty well using xdg-dbus-proxy
.
Here's an example for telegram-desktop:
https://git.sr.ht/~whynothugo/dotfiles/tree/main/item/home/.local/bin/telegram-desktop
It picks up dark mode changes (via portal), can show notifications, and grabs media keys to play/pause (useful when playing voice clips).
I hope this sample serves as a reference!
BTW: thanks for publishing this repo, these samples helped me figure out how to unbreak multiple apps that suddenly broke and need access to /dev/dri
, /sys/dev/char
and /sys/devices/pci0000:00
. I guess for the last two it would be ideal to narrow it down to only gpu-related files, right?
BTW: thanks for publishing this repo, these samples helped me figure out how to unbreak multiple apps that suddenly broke and need access to
/dev/dri
,/sys/dev/char
and/sys/devices/pci0000:00
. I guess for the last two it would be ideal to narrow it down to only gpu-related files, right?
The dev mounts were mostly added for fido2 support in order to allow WebAuthn, but some may be required for performance reasons as well.
@WhyNotHugo Thanks! This is massively helpful!
Could I ask how do you infer what parameters to provide to xdg-dbus-proxy
though? Do you do it via the --log
option in xdg-dbus-proxy
?
(I recently wrote a tool for summarising syscall parameters relevant to sandboxing, see here for example json - I am thinking if a similar tool for going through dbus logs would be useful too.)
The dev mounts were mostly added for fido2 support in order to allow WebAuthn, but some may be required for performance reasons as well.
Odd, I had keepassxc
and telegram-desktop
fail to start without them (failing to initialise something related to opengl). Adding these fixed the issue. /dev/dri
is definitely graphics related.
Could I ask how do you infer what parameters to provide to xdg-dbus-proxy though? Do you do it via the --log option in xdg-dbus-proxy?
I was familiar with these D-Bus interfaces already. Telegram-desktop tries to use other D-Bus interfaces too, but I only allowed the ones I care about:
-
--talk=org.freedesktop.Notifications
: allows talking to the notification daemon. -
--call="org.freedesktop.portal.Desktop=org.freedesktop.portal.Settings.Read@/org/freedesktop/portal/desktop"
: allows reading a settings from the xdg-desktop-portal (but not using other method on the same interface). In particular, I want telegram to be able to read the dark mode / light mode setting (which I control via darkman). Qt and GTK also use this under the hood for things like detecting the current theme. -
--broadcast="org.freedesktop.portal.Desktop=org.freedesktop.portal.Settings.SettingChanged@/org/freedesktop/portal/desktop"
: Allows receiving signals when the above changes. -
--own=org.mpris.MediaPlayer2.tdesktop
: Allows telegram to expose itself as an mpris client. That is: it presents itself as a media player. Other desktop utilities that can pause the currently playing media likeplayerctl
can then control telegram. I use this to pause audio clips with the playpause buttons on my headset.
The org.freedesktop.portal.Desktop
interface is a delicate one (which is why I've been so granular on it). The same service also exposes things like screencasting, camera and a bunch of other things.
@WhyNotHugo first off, massive thanks for releasing examples, they've been useful.
After a lot of work with file portals however, there is one thing I need to add: the sandboxes for both xdg-dbus-proxy
and the program in question need to have a file called /.flatpak-info
if you want portals like FileChooser
to work properly. Otherwise, xdg-desktop-portal
will just assume the program has full access to the file system. Here's an example with Vivaldi that implements this workaround:
#! /usr/bin/sh
APP_NAME="net.vivaldi.Vivaldi"
APP_FOLDER="$XDG_RUNTIME_DIR/app/$APP_NAME"
mkdir -p "$APP_FOLDER"
if [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; then
export DBUS_SESSION_BUS_ADDRESS="unix:path=$XDG_RUNTIME_DIR/bus"
fi
# A sandboxed dbus filter that
# makes things a little safer
#
# Bwrap was initially for --die-with-parent,
# but was expanded to fix bugs related to portals
set_up_dbus_proxy() {
bwrap \
--new-session \
--symlink /usr/lib64 /lib64 \
--ro-bind /usr/lib /usr/lib \
--ro-bind /usr/lib64 /usr/lib64 \
--ro-bind /usr/bin /usr/bin \
--bind "$XDG_RUNTIME_DIR" "$XDG_RUNTIME_DIR" \
--ro-bind-data 3 "/.flatpak-info" \
--die-with-parent \
-- \
env -i xdg-dbus-proxy \
"$DBUS_SESSION_BUS_ADDRESS" \
"$APP_FOLDER/bus" \
--filter \
--log \
--talk=org.freedesktop.portal.Documents \
--talk=org.freedesktop.portal.Flatpak \
--talk=org.freedesktop.portal.Desktop \
--talk=org.freedesktop.portal.Notifications \
--talk=org.freedesktop.portal.FileChooser \
--call="org.freedesktop.portal.Desktop=org.freedesktop.portal.Settings.Read@/org/freedesktop/portal/desktop" \
--broadcast="org.freedesktop.portal.Desktop=org.freedesktop.portal.Settings.SettingChanged@/org/freedesktop/portal/desktop" 3<<EOF
[Application]
name=$APP_NAME
EOF
}
set_up_dbus_proxy &
sleep 0.1
bwrap \
--unshare-all \
--share-net \
--as-pid-1 \
--new-session \
--symlink /usr/lib /lib \
--symlink /usr/lib64 /lib64 \
--symlink /usr/bin /bin \
--symlink /usr/bin /sbin \
--ro-bind /usr/lib /usr/lib \
--ro-bind /usr/lib64 /usr/lib64 \
--ro-bind /usr/bin /usr/bin \
--ro-bind /etc /etc \
--ro-bind /usr/share /usr/share \
--ro-bind /opt/vivaldi /opt/vivaldi \
--dev /dev \
--dev-bind /dev/dri /dev/dri \
--proc /proc \
--ro-bind /sys/dev/char /sys/dev/char \
--ro-bind /sys/devices /sys/devices \
--ro-bind /run/dbus /run/dbus \
--bind "$XDG_RUNTIME_DIR" "$XDG_RUNTIME_DIR" \
--ro-bind "$XDG_RUNTIME_DIR/wayland-1" "$XDG_RUNTIME_DIR/wayland-1" \
--ro-bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0" \
--ro-bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse" \
--bind "$XDG_RUNTIME_DIR/doc" "$XDG_RUNTIME_DIR/doc" \
--bind "$APP_FOLDER/bus" "$XDG_RUNTIME_DIR/bus" \
--bind-try "$XDG_RUNTIME_DIR/app/org.keepassxc.KeePassXC/org.keepassxc.KeePassXC.BrowserServer" "$XDG_RUNTIME_DIR/app/org.keepassxc.KeePassXC/org.keepassxc.KeePassXC.BrowserServer" \
--tmpfs /tmp \
--dir "$HOME" \
--dir "$HOME"/.cache \
--bind "$HOME"/.config/vivaldi "$HOME"/.config/vivaldi \
--bind "$HOME"/VivaldiDownloads "$HOME"/Downloads \
--ro-bind "$HOME"/.icons "$HOME"/.icons \
--ro-bind-data 3 "/.flatpak-info" \
--setenv XCURSOR_PATH "/run/host/user-share/icons:/run/host/share/icons:$HOME/.icons" \
--setenv GTK_USE_PORTAL 1 \
--cap-drop ALL \
-- \
/usr/bin/vivaldi-stable --enable-features=UseOzonePlatform --ozone-platform=wayland "${@}" \
3<<EOF
[Application]
name=$APP_NAME
EOF
With this workaround, you can eliminate any access to the home directory, just like the Firefox Flatpak does (here though I've kept access to .config
). I have more info in a (albeit basic and somewhat rushed) write-up on my website.
~~EDIT: I know my example gives access to all portals, but I've tried without success to narrow them down. From what I can tell, it's a Chromium issue. By giving access to all portals, regular dbus calls will use portals (this is affirmed in Flatpak's documentation)~~
EDIT 2: I've gotten limited portal access working, I just needed to add --talk=org.freedesktop.portal.Flatpak
to the list of portals Vivaldi can "talk" to