bwscripts icon indicating copy to clipboard operation
bwscripts copied to clipboard

Isolating D-Bus

Open WhyNotHugo opened this issue 2 years ago • 5 comments

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!

WhyNotHugo avatar Dec 12 '22 23:12 WhyNotHugo

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?

WhyNotHugo avatar Dec 12 '22 23:12 WhyNotHugo

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.

valoq avatar Dec 19 '22 14:12 valoq

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

darrenldl avatar Jan 03 '23 01:01 darrenldl

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 like playerctl 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 avatar Jan 11 '23 12:01 WhyNotHugo

@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

StandingPadAnimations avatar Aug 26 '23 21:08 StandingPadAnimations