Skip to main content
On this page

D-Bus Proxy

Most containers either get the whole session bus or nothing. podbox sits in the middle: a small proxy (xdg-dbus-proxy, run as a companion systemd unit) forwards only the D-Bus services you allow. Notifications and link-opening work through their portal interfaces; everything else stays unreachable unless you add it under [dbus].

How it works

When [dbus] talk/own rules are configured, or notify/xdg_open need portal access:

  • podbox enable writes an additional file: ~/.config/containers/systemd/<name>-proxy.service
  • The generated .container quadlet gains: Requires=<name>-proxy.service After=<name>-proxy.service
  • Instead of Volume=%t/bus:%t/bus, the container gets the proxy socket: Volume=%t/podbox/<name>-dbus.sock:/run/podbox/dbus.sock:ro Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/podbox/dbus.sock
  • The proxy service runs xdg-dbus-proxy, which forwards only the explicitly allowed D-Bus services to the container.

Configuration

toml
1[dbus]
2talk = [
3 "org.freedesktop.Notifications",
4 "org.mpris.MediaPlayer2.*",
5]
6own = [
7 "org.mpris.MediaPlayer2.podbox_app",
8]
KeyTypeDescription
talkstring[]D-Bus services the container can call (two-way communication)
ownstring[]D-Bus services the container can register on the host bus

Wildcards (*) are supported per the xdg-dbus-proxy filtering rules.

Warning: adding org.freedesktop.portal.* (or any org.freedesktop.portal.* / org.freedesktop.impl.portal.* name) to talk re-grants the full portal bus surface, including host-privileged interfaces like DynamicLauncher, Screenshot, ScreenCast and Settings. Prefer the built-in interface-scoped rules described below; podbox prints a warning when it sees a portal-family talk entry.

Portal access model

The portal preset (applied by default when [dbus] has no explicit rules) does not add org.freedesktop.portal.* to the talk list. Instead, the generated proxy exposes org.freedesktop.portal.Desktop through interface-scoped rules, one per enabled capability:

CapabilityRule granted
integration.notify--call=org.freedesktop.portal.Desktop=org.freedesktop.portal.Notification.*@/org/freedesktop/portal/desktop
integration.xdg_open--call=org.freedesktop.portal.Desktop=org.freedesktop.portal.OpenURI.*@/org/freedesktop/portal/desktop
either--call=org.freedesktop.portal.Desktop=org.freedesktop.portal.Request.*@/org/freedesktop/portal/desktop/request/* (async Request pattern, incl. Request.Close)
either--broadcast=org.freedesktop.portal.Desktop=org.freedesktop.portal.Request.*@/org/freedesktop/portal/desktop/request/* (Request.Response result signals)
either--call=org.freedesktop.portal.Desktop=org.freedesktop.DBus.Introspectable.*@/org/freedesktop/portal/* (read-only introspection, needed by GIO clients to parse call arguments)

Because xdg-dbus-proxy treats any granted method on a name as TALK for that name, these rules expose exactly those portal interfaces — nothing else. A disabled capability contributes no rules.

Behavior matrix

integration.dbus[dbus] configWhat the container gets
falseanyNo D-Bus access
truedefault (empty), no capabilities onUnfiltered Volume=%t/bus:%t/bus
truenotify/xdg_open on, or preset / talk / own setProxied via xdg-dbus-proxy with those rules plus interface-scoped portal rules for the enabled capabilities
truepreset = "", empty talk + ownUnfiltered Volume=%t/bus:%t/bus

Generated proxy unit

When rules are present, a companion systemd service is generated at ~/.config/containers/systemd/<name>-proxy.service:

ini
1[Unit]
2Description=D-Bus Proxy for podbox container <name>
3PartOf=<name>.service
4 
5[Service]
6Type=simple
7RuntimeDirectory=podbox
8ExecStart=/usr/bin/xdg-dbus-proxy \
9 unix:path=%t/bus \
10 %t/podbox/<name>-dbus.sock \
11 --talk=org.freedesktop.Notifications \
12 --talk=org.mpris.MediaPlayer2.* \
13 --call=org.freedesktop.portal.Desktop=org.freedesktop.portal.Notification.*@/org/freedesktop/portal/desktop \
14 --call=org.freedesktop.portal.Desktop=org.freedesktop.portal.OpenURI.*@/org/freedesktop/portal/desktop \
15 --call=org.freedesktop.portal.Desktop=org.freedesktop.portal.Request.*@/org/freedesktop/portal/desktop/request/* \
16 --call=org.freedesktop.portal.Desktop=org.freedesktop.DBus.Introspectable.*@/org/freedesktop/portal/* \
17 --broadcast=org.freedesktop.portal.Desktop=org.freedesktop.portal.Request.*@/org/freedesktop/portal/desktop/request/* \
18 --own=org.mpris.MediaPlayer2.podbox_app
19Restart=on-failure
20 
21[Install]
22WantedBy=<name>.service

Stopping the container stops the proxy; restarting restarts it (PartOf=<name>.service).

Requirements

  • xdg-dbus-proxy must be installed on the host system (package xdg-dbus-proxy, commonly shipped with Flatpak)
  • integration.dbus = true (the master switch)
  • A D-Bus session bus socket must be present on the host (auto-detected)

Verification

Test an allowed service

bash
gdbus call --session \
--dest org.freedesktop.Notifications \
--object-path /org/freedesktop/Notifications \
--method org.freedesktop.Notifications.Notify \
"podbox" 0 "" "Hello" "Proxied message." [] {} 5000

Should succeed and show a host notification.

Test isolation

bash
gdbus call --session \
--dest org.freedesktop.systemd1 \
--object-path /org/freedesktop/systemd1 \
--method org.freedesktop.DBus.Peer.Ping

Should fail with access denied — the proxy blocks unapproved services.

Portal surface audit

Audited from inside a container against the proxied socket. Allowed:

InterfaceResult
org.freedesktop.portal.Notification.AddNotification() (host notification shown)
org.freedesktop.portal.OpenURI.OpenURIrequest handle returned
org.freedesktop.DBus.Introspectable.Introspectintrospection XML (needed by GIO clients)
Denied interfaces (all return AccessDenied)
Interface
Screenshot.Screenshot
ScreenCast.CreateSession
RemoteDesktop.CreateSession
InputCapture.CreateSession
Settings.Read
Documents.Add
Account.GetUserInformation
GameMode.QueryStatus
Lockdown.GetDisabled
Print.PreparePrint
Wallpaper.SetWallpaperURI
DynamicLauncher.RequestInstallToken
FileChooser.OpenFile

Denial happens at the proxy before anything reaches the host — screen capture, screenshots, file access, and launcher install stay unreachable unless the matching capability is enabled.

podbox — declarative Linux container environments
Licensed under MIT. Open Source by bethropolis.