Bubblewrap/Examples: Difference between revisions

From Alpine Linux
m (Add argument check to mpv)
m (Pkg: Search every arch)
 
(14 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{Draft|Someone more experienced needs to look over this.  I'm not sure it's worth the time to limit {{Path|/usr/lib/*}}.}}
{{Draft|Someone more experienced needs to look over this.}}


{{Todo|Since bubblewrap can make use of [https://en.wikipedia.org/wiki/Seccomp seccomp], restrictive versions should be added.}}
{{Todo|
* Since bubblewrap can make use of [https://en.wikipedia.org/wiki/Seccomp seccomp], restrictive versions should be added.
* {{Ic|imv}}, {{Ic|mpv}} and {{Ic|zathura}} currently only accept 1 mandatory (except {{Ic|imv}}) argument.  This should (hopefully) be temporary, until I figure out how to pass multiple arguments (without including everything else).}}


{{Note|To try and avoid duplicates, everything will be explained for [[Firefox]] and only when it differs (non obviously) for everything else.  Where applicable this assumes: [[Wayland]] only + [[PipeWire]].}}
{{Warning|These were found by going backward; start with a complicated program and as restricted as possible sandbox, allowing more till the program appears to work.  Because of this, complicated and sensitive programs (for example: {{Pkg|firefox|arch=}} and {{Pkg|keepassxc|arch=}}) may be missing some things they need, which might lead to '''LESS SECURITY''', '''LESS PRIVACY''' and '''DATA LOSS'''.}}


{{Note|{{Ic|mpv}} and {{Ic|zathura}} currently only accept 1 (mandatory) argument. This should be temporary, until I figure out how to pass multiple arguments (without including everything else).}}
{{Note|
* This page assumes you have already read [[Bubblewrap]].
* To try and avoid duplicates everything will be explained for [[Firefox]] and only when it differs (non obviously) for everything else.
* Where applicable, this assumes: [[Wayland]] only + [[PipeWire]].
: If Wayland is needed, make sure you have dealt with [[Wayland#XDG_RUNTIME_DIR|XDG_RUNTIME_DIR]].}}


{{TOC right}}
{{TOC right}}
Line 11: Line 17:
== Firefox ==
== Firefox ==


{{Cat|~/.local/bin/bwrap-firefox|#!/usr/bin/env sh
{{Cat|~/.local/bin/bwrap-firefox|#!/bin/sh


# Firefox wrapped in bwrap with network access.
# Firefox wrapped in bwrap with network access.
Line 44: Line 50:
   --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
   --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
   --ro-bind /lib/libblkid.so.1 /lib/libblkid.so.1 \
   --ro-bind /lib/libblkid.so.1 /lib/libblkid.so.1 \
  --ro-bind /lib/libcrypto.so.3 /lib/libcrypto.so.3 \
   --ro-bind /lib/libmount.so.1 /lib/libmount.so.1 \
   --ro-bind /lib/libmount.so.1 /lib/libmount.so.1 \
   --ro-bind /lib/libz.so.1 /lib/libz.so.1 \
   --ro-bind /lib/libz.so.1 /lib/libz.so.1 \
Line 57: Line 64:
   --ro-bind /usr/share/mime/ /usr/share/mime/ \
   --ro-bind /usr/share/mime/ /usr/share/mime/ \
   /usr/lib/firefox/firefox}}
   /usr/lib/firefox/firefox}}
set -u
If the shell tries to expand an unset parameter, it will error (with a
few exceptions).


  XDG_CACHE_HOME="${XDG_CACHE_HOME:=$HOME/.cache}"
  XDG_CACHE_HOME="${XDG_CACHE_HOME:=$HOME/.cache}"
Line 66: Line 77:


  NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}"
  NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}"
{{Path|$XDG_CACHE_HOME}} for the new user.
{{Path|"$XDG_CACHE_HOME"}} for the new user.


  mkdir -pm 0700 "${XDG_DATA_HOME}/firefox/"
  mkdir -pm 0700 "${XDG_DATA_HOME}/firefox/"
Line 84: Line 95:


  --clearenv \
  --clearenv \
Unset all environment variables (except for {{Ic|"$PWD"}}).
Unset all environment variables (except for {{Path|"$PWD"}}).


  --setenv HOME "$NEW_HOME" \
  --setenv HOME "$NEW_HOME" \
Line 115: Line 126:
  ...
  ...
  XDG_CACHE_HOME="${XDG_CACHE_HOME:=$HOME/.cache}"
  XDG_CACHE_HOME="${XDG_CACHE_HOME:=$HOME/.cache}"
  <b>XDG_CONFIG_HOME "${XDG_CONFIG_HOME:=$HOME/.config}"</b>
  '''XDG_CONFIG_HOME "${XDG_CONFIG_HOME:=$HOME/.config}"'''
  XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}"
  XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}"
  ...
  ...
  NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}"
  NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}"
  <b>NEW_XDG_CONFIG_HOME="${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}"</b>
  '''NEW_XDG_CONFIG_HOME="${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}"'''
  ...
  ...
  --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
  --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
  <b>--setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \</b>
  '''--setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \'''
  --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
  --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
  ...
  ...
  --bind-try "${XDG_CACHE_HOME}/mozilla/" "${NEW_XDG_CACHE_HOME}/mozilla/" \
  --bind-try "${XDG_CACHE_HOME}/mozilla/" "${NEW_XDG_CACHE_HOME}/mozilla/" \
  <b>--ro-bind-try "${XDG_CONFIG_HOME}/fontconfig/" "${NEW_XDG_CONFIG_HOME}/fontconfig/" \</b>
  '''--ro-bind-try "${XDG_CONFIG_HOME}/fontconfig/" "${NEW_XDG_CONFIG_HOME}/fontconfig/" \'''
  --bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \
  --bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \
  ...
  ...
Line 133: Line 145:
  ...
  ...
  XDG_CACHE_HOME="${XDG_CACHE_HOME:=$HOME/.cache}"
  XDG_CACHE_HOME="${XDG_CACHE_HOME:=$HOME/.cache}"
  <b>XDG_CONFIG_HOME "${XDG_CONFIG_HOME:=$HOME/.config}"</b>
  '''XDG_CONFIG_HOME "${XDG_CONFIG_HOME:=$HOME/.config}"'''
  XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}"
  XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}"
  ...
  ...
  NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}"
  NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}"
  <b>NEW_XDG_CONFIG_HOME="${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}"</b>
  '''NEW_XDG_CONFIG_HOME="${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}"'''
  ...
  ...
  --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
  --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
  <b>--setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \</b>
  '''--setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \'''
  --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
  --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
  ...
  ...
  --bind-try "${XDG_CACHE_HOME}/mozilla/" "${XDG_CACHE_HOME}/mozilla/" \
  --bind-try "${XDG_CACHE_HOME}/mozilla/" "${XDG_CACHE_HOME}/mozilla/" \
  <b>--ro-bind-try "${XDG_CONFIG_HOME}/user-dirs.dirs" "${NEW_XDG_CONFIG_HOME}/user-dirs.dirs" \</b>
  '''--ro-bind-try "${XDG_CONFIG_HOME}/user-dirs.dirs" "${NEW_XDG_CONFIG_HOME}/user-dirs.dirs" \'''
  --bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \
  --bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \
  ...
  ...
Line 155: Line 168:
   ...
   ...
   --bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \
   --bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \
   <b>--bind-try "${HOME}/downloads/" "${NEW_HOME}/downloads/" \</b>
   '''--bind-try "${HOME}/downloads/" "${NEW_HOME}/downloads/" \'''
   --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
   --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
   ...
   ...
Line 167: Line 180:
  ...
  ...
  NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}"
  NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}"
  <b>NEW_XDG_DATA_HOME="${NEW_HOME}${XDG_DATA_HOME#"$HOME"}"</b>
  '''NEW_XDG_DATA_HOME="${NEW_HOME}${XDG_DATA_HOME#"$HOME"}"'''
  ...
  ...
  --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
  --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
  <b>--setenv XDG_DATA_HOME "$NEW_XDG_DATA_HOME" \</b>
  '''--setenv XDG_DATA_HOME "$NEW_XDG_DATA_HOME" \'''
  --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
  --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
  ...
  ...
  --bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \
  --bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \
  <b>--ro-bind-try "${XDG_DATA_HOME}/fonts/" "${NEW_XDG_DATA_HOME}/fonts/" \</b>
  '''--ro-bind-try "${XDG_DATA_HOME}/fonts/" "${NEW_XDG_DATA_HOME}/fonts/" \'''
  --bind-try "${HOME}/Downloads/" "${NEW_HOME}/Downloads/" \
  --bind-try "${HOME}/Downloads/" "${NEW_HOME}/Downloads/" \
  ...
  ...
Line 184: Line 198:
  --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
  --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
  --ro-bind /lib/libblkid.so.1 /lib/libblkid.so.1 \
  --ro-bind /lib/libblkid.so.1 /lib/libblkid.so.1 \
--ro-bind /lib/libcrypto.so.3 /lib/libcrypto.so.3 \
  --ro-bind /lib/libmount.so.1 /lib/libmount.so.1 \
  --ro-bind /lib/libmount.so.1 /lib/libmount.so.1 \
  --ro-bind /lib/libz.so.1 /lib/libz.so.1 \
  --ro-bind /lib/libz.so.1 /lib/libz.so.1 \
Line 196: Line 211:
  --ro-bind /usr/lib/ /usr/lib/ \
  --ro-bind /usr/lib/ /usr/lib/ \
Object files and libraries.
Object files and libraries.
{{Note|It is not worth the time to limit this, the churn is too great.}}


  --ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \
  --ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \
Line 220: Line 237:
  ...
  ...
  --ro-bind /usr/share/icu/ /usr/share/icu/ \
  --ro-bind /usr/share/icu/ /usr/share/icu/ \
  <b>--ro-bind /usr/share/libdrm/ /usr/share/libdrm/ \</b>
  '''--ro-bind /usr/share/libdrm/ /usr/share/libdrm/ \'''
  --ro-bind /usr/share/mime/ /usr/share/mime/ \
  --ro-bind /usr/share/mime/ /usr/share/mime/ \
  ...
  ...
Line 245: Line 262:
  ...
  ...
  --proc /proc/ \
  --proc /proc/ \
  <b>--ro-bind "${XDG_RUNTIME_DIR}/pulse/" "${XDG_RUNTIME_DIR}/pulse/" \</b>
  '''--ro-bind "${XDG_RUNTIME_DIR}/pulse/" "${XDG_RUNTIME_DIR}/pulse/" \'''
  --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
  --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
  ...
  ...
Line 256: Line 273:
  ...
  ...
  --proc /proc/ \
  --proc /proc/ \
  <b>--ro-bind /sys/bus/pci/ /sys/bus/pci/ \</b>
  '''--ro-bind /sys/bus/pci/ /sys/bus/pci/ \'''
  --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
  --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
  ...
  ...
Line 267: Line 284:
  ...
  ...
  --proc /proc/ \
  --proc /proc/ \
  <b>--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \</b>
  '''--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \'''
  --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
  --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
  ...
  ...
Line 282: Line 299:


== imv ==
== imv ==
{{Cat|~/.local/bin/bwrap-imv|#!/bin/sh
# imv wrapped in bwrap.
set -u
XDG_CONFIG_HOME{{=}}"${XDG_CONFIG_HOME:{{=}}$HOME/.config}"
/usr/bin/bwrap \
  --unshare-all \
  --new-session \
  --die-with-parent \
  --clearenv \
  --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
  --setenv XDG_CONFIG_HOME "$XDG_CONFIG_HOME" \
  --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
  --ro-bind /bin/sh /bin/sh \
  --dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \
  --ro-bind-try "${XDG_CONFIG_HOME}/imv/config" "${XDG_CONFIG_HOME}/imv/config" \
  --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
  --ro-bind /lib/libblkid.so.1 /lib/libblkid.so.1 \
  --ro-bind /lib/libmount.so.1 /lib/libmount.so.1 \
  --ro-bind /lib/libz.so.1 /lib/libz.so.1 \
  --ro-bind /sys/dev/char/ /sys/dev/char/ \
  --ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \
  --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
  --ro-bind /usr/lib/ /usr/lib/ \
  --ro-bind /usr/libexec/imv-wayland /usr/libexec/imv-wayland \
  --ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \
  --ro-bind "${1:-./}" "$(realpath "${1:-./}")" \
  /usr/libexec/imv-wayland "${1:-./}"}}
--ro-bind /bin/sh /bin/sh \
Needed to use {{Path|config}} and have various information in the window
title.
...
'''XDG_CACHE_HOME{{=}}"${XDG_CACHE_HOME:{{=}}$HOME/.cache}"'''
XDG_CONFIG_HOME{{=}}"${XDG_CONFIG_HOME:{{=}}$HOME/.config}"
'''XDG_DATA_HOME{{=}}"${XDG_DATA_HOME:{{=}}$HOME/.local/share}"'''
...
--setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
'''--setenv XDG_CACHE_HOME "$XDG_CACHE_HOME" \'''
--setenv XDG_CONFIG_HOME "$XDG_CONFIG_HOME" \
'''--setenv XDG_DATA_HOME "$XDG_DATA_HOME" \'''
--setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
...
--dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \
'''--ro-bind /etc/fonts/ /etc/fonts/ \'''
'''--bind-try "${XDG_CACHE_HOME}/fontconfig/" "${XDG_CACHE_HOME}/fontconfig/" \'''
'''--ro-bind-try "${XDG_CONFIG_HOME}/fontconfig/" "${XDG_CONFIG_HOME}/fontconfig/" \'''
--ro-bind-try "${XDG_CONFIG_HOME}/imv/config" "${XDG_CONFIG_HOME}/imv/config" \
'''--ro-bind-try "${XDG_DATA_HOME}/fonts/" "${XDG_DATA_HOME}/fonts/" \'''
--ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
...
--ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \
'''--ro-bind /usr/share/fonts/ /usr/share/fonts/ \'''
'''--ro-bind /usr/share/icu/ /usr/share/icu/ \'''
--ro-bind "${1:-./}" "$(realpath "${1:-./}")" \
...
(Optional) To use commands in {{Ic|imv}}.
--ro-bind /sys/dev/char/ /sys/dev/char/ \
Access to character devices.
--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \
Access to PCI resources.
--ro-bind "${1:-./}" "$(realpath "${1:-./}")" \
Get the absolute pathname using {{Ic|realpath}}, so you can pass a
relative argument and still bind the argument.  If you don't pass in
anything it will default to {{Path|./}}, the current directory.
{{Warning|If you don't pass anything and it defaults to the current directory, it will have '''everything''' under that directory shown to {{Ic|imv}}, recursively.}}
== KeePassXC ==
{{Note|I only use the bare minimum functionality, so functionality you need is probably missing.  If you use functionality not here, your contribution will be most appreciated.  To kick things off: {{Ic|Unable to initialize libusb. USB devices may not be detected properly.}} can be silenced with {{Ic|--dev-bind /dev/bus/usb/ /dev/bus/usb/ \}}.}}
{{Cat|~/.local/bin/bwrap-keepassxc|#!/bin/sh
# keepassxc wrapped in bwrap.
set -u
XDG_CONFIG_HOME{{=}}"${XDG_CONFIG_HOME:{{=}}$HOME/.config}"
PASSWORD_DATABASE{{=}}"${HOME}/password database"
NEW_HOME{{=}}'/home/user'
NEW_XDG_CONFIG_HOME{{=}}"${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}"
NEW_PASSWORD_DATABASE{{=}}"${NEW_HOME}${PASSWORD_DATABASE#"$HOME"}"
mkdir -pm 0700 "$PASSWORD_DATABASE"
/usr/bin/bwrap \
  --unshare-all \
  --new-session \
  --die-with-parent \
  --clearenv \
  --setenv HOME "$NEW_HOME" \
  --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
  --setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \
  --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
  --setenv XDG_SESSION_TYPE "$XDG_SESSION_TYPE" \
  --dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \
  --ro-bind /etc/fonts/ /etc/fonts/ \
  --bind-try "${XDG_CONFIG_HOME}/keepassxc/" "${NEW_XDG_CONFIG_HOME}/keepassxc/" \
  --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
  --ro-bind /lib/libcrypto.so.3 /lib/libcrypto.so.3 \
  --ro-bind /lib/libssl.so.3 /lib/libssl.so.3 \
  --ro-bind /lib/libz.so.1 /lib/libz.so.1 \
  --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
  --ro-bind /sys/dev/char/ /sys/dev/char/ \
  --ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \
  --ro-bind /usr/bin/keepassxc /usr/bin/keepassxc \
  --ro-bind /usr/lib/ /usr/lib/ \
  --ro-bind /usr/share/X11/ /usr/share/X11/ \
  --ro-bind /usr/share/fontconfig/ /usr/share/fontconfig/ \
  --ro-bind /usr/share/fonts/ /usr/share/fonts/ \
  --ro-bind /usr/share/keepassxc/ /usr/share/keepassxc/ \
  --bind "$PASSWORD_DATABASE/" "$NEW_PASSWORD_DATABASE/" \
  /usr/bin/keepassxc "$@"}}
PASSWORD_DATABASE="${HOME}/password database"
Directory containing your {{Pkg|keepassxc|arch=}} password database.
{{Tip|This is almost certainly not where '''your''' database is located.  You will need to change it to where you put your password database.}}
--setenv XDG_SESSION_TYPE "$XDG_SESSION_TYPE" \
Session type, since we are assuming Wayland only, this will be "wayland".
--ro-bind /sys/dev/char/ /sys/dev/char/ \
Access to character devices.
--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \
Access to PCI resources.
--bind "$PASSWORD_DATABASE/" "$NEW_PASSWORD_DATABASE/" \
Bind password database.


== mpv ==
== mpv ==


{{Cat|~/.local/bin/bwrap-mpv|#!/usr/bin/env sh
{{Cat|~/.local/bin/bwrap-mpv|#!/bin/sh


# mpv wrapped in bwrap.
# mpv wrapped in bwrap.
Line 342: Line 501:
   /usr/bin/mpv \
   /usr/bin/mpv \
     --player-operation-mode{{=}}pseudo-gui \
     --player-operation-mode{{=}}pseudo-gui \
    --title{{=}}'bwrap {{!}} ${media-title}' \
     "$1"}}
     "$1"}}
--ro-bind /sys/dev/char/ /sys/dev/char/ \
Access to character devices.
--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \
Access to PCI resources.


  --ro-bind "$1" "$(realpath "$1")" \
  --ro-bind "$1" "$(realpath "$1")" \
Line 353: Line 519:


{{Tip|If you followed [[Bubblewrap#.desktop_integration]], you should remove it from {{Path|"${XDG_DATA_HOME}/applications/bwrap-mpv.desktop"}}.}}
{{Tip|If you followed [[Bubblewrap#.desktop_integration]], you should remove it from {{Path|"${XDG_DATA_HOME}/applications/bwrap-mpv.desktop"}}.}}
--title='bwrap | ${media-title}' \
Set the window title, showing at a glance that you are using {{Ic|bwrap}}.


=== mpv-net ===
=== mpv-net ===
Line 361: Line 530:
{{Tip|You can use both {{Ic|bwrap-mpv}} and {{Ic|bwrap-mpv-net}}.  {{Ic|bwrap-mpv}} for local stuff and {{Ic|bwrap-mpv-net}} for watching over the Internet.}}
{{Tip|You can use both {{Ic|bwrap-mpv}} and {{Ic|bwrap-mpv-net}}.  {{Ic|bwrap-mpv}} for local stuff and {{Ic|bwrap-mpv-net}} for watching over the Internet.}}


{{Cat|~/.local/bin/bwrap-mpv-net|#!/usr/bin/env sh
{{Cat|~/.local/bin/bwrap-mpv-net|#!/bin/sh


# mpv wrapped in bwrap with network access.
# mpv wrapped in bwrap with network access.
Line 415: Line 584:
   /usr/bin/mpv \
   /usr/bin/mpv \
     --player-operation-mode{{=}}pseudo-gui \
     --player-operation-mode{{=}}pseudo-gui \
    --title{{=}}'bwrap {{!}} ${media-title}' \
     "$@"}}
     "$@"}}


Line 422: Line 592:
  --ro-bind /etc/ssl/certs/ /etc/ssl/certs/ \
  --ro-bind /etc/ssl/certs/ /etc/ssl/certs/ \
Certificate authorities that are ''trusted''.
Certificate authorities that are ''trusted''.
--ro-bind /sys/dev/char/ /sys/dev/char/ \
Access to character devices.
--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \
Access to PCI resources.


  "$@"
  "$@"
This is so you can pass more options to {{Ic|mpv}}, for example:
This is so you can pass more options to {{Ic|bwrap-mpv-net}}, for example:
  $ bwrap-mpv-net --video=no --sub=no 'URL1' 'URL2'
  $ bwrap-mpv-net --video=no --sub=no 'URL1' 'URL2'


Line 434: Line 610:
=== Screenshots ===
=== Screenshots ===


The default screenshots directory is {{Ic|"$XDG_DESKTOP_DIR"}} (which is
The default screenshots directory is {{Path|"$XDG_DESKTOP_DIR"}} (which is
{{Path|"${HOME}/Desktop"}}, which will fallback to {{Path|"$HOME/"}} if
{{Path|"${HOME}/Desktop/"}}, which will fallback to {{Path|"$HOME/"}} if
{{Path|"${HOME}/Desktop"}} doesn't exist).  That means that by default
{{Path|"${HOME}/Desktop/"}} doesn't exist).  That means that by default
{{Ic|bwrap-mpv[-net]}} won't allow screenshots unless you change a few things.
{{Ic|bwrap-mpv[-net]}} won't allow screenshots unless you change a few things.
Do the following to allow an XDG approved screenshots directory:
Do the following to allow an XDG approved screenshots directory:
Line 442: Line 618:
  ...
  ...
  XDG_CONFIG_HOME="${XDG_CONFIG_HOME:=$HOME/.config}"
  XDG_CONFIG_HOME="${XDG_CONFIG_HOME:=$HOME/.config}"
  <b>XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}"</b>
  '''XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}"'''
  ...
  ...
  NEW_XDG_CONFIG_HOME="${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}"
  NEW_XDG_CONFIG_HOME="${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}"
  <b>NEW_XDG_DATA_HOME="${NEW_HOME}${XDG_DATA_HOME#"$HOME"}"</b>
  '''NEW_XDG_DATA_HOME="${NEW_HOME}${XDG_DATA_HOME#"$HOME"}"'''
'''mkdir -pm 0700 "${XDG_DATA_HOME}/mpv/"'''
   
   
<b>mkdir -pm 0700 "${XDG_DATA_HOME}/mpv/"</b>
  ...
  ...
  --setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \
  --setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \
  <b>--setenv XDG_DATA_HOME "$NEW_XDG_DATA_HOME" \</b>
  '''--setenv XDG_DATA_HOME "$NEW_XDG_DATA_HOME" \'''
  --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
  --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
  ...
  ...
  --ro-bind-try "${XDG_CONFIG_HOME}/mpv/mpv.conf" "${NEW_XDG_CONFIG_HOME}/mpv/mpv.conf" \
  --ro-bind-try "${XDG_CONFIG_HOME}/mpv/mpv.conf" "${NEW_XDG_CONFIG_HOME}/mpv/mpv.conf" \
  <b>--bind "${XDG_DATA_HOME}/mpv/" "${NEW_XDG_DATA_HOME}/mpv/" \</b>
  '''--bind "${XDG_DATA_HOME}/mpv/" "${NEW_XDG_DATA_HOME}/mpv/" \'''
  --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
  --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
  ...
  ...
Line 463: Line 641:
screenshot-template="~/.local/share/mpv/screenshots/%F [%p] %02n"
screenshot-template="~/.local/share/mpv/screenshots/%F [%p] %02n"
...</nowiki>}}
...</nowiki>}}
== yt-dlp ==
{{Cat|~/.local/bin/bwrap-yt-dlp|#!/bin/sh
# yt-dlp wrapped in bwrap with network access.
set -u
XDG_CONFIG_HOME{{=}}"${XDG_CONFIG_HOME:{{=}}$HOME/.config}"
NEW_HOME{{=}}'/home/user'
NEW_XDG_CONFIG_HOME{{=}}"${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}"
mkdir -pm 0700 "${HOME}/Downloads/"
/usr/bin/bwrap \
  --unshare-all \
  --share-net \
  --new-session \
  --die-with-parent \
  --clearenv \
  --setenv HOME "$NEW_HOME" \
  --setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \
  --hostname localhost \
  --ro-bind /etc/resolv.conf /etc/resolv.conf \
  --ro-bind /etc/ssl/certs/ /etc/ssl/certs/ \
  --ro-bind-try "${XDG_CONFIG_HOME}/yt-dlp/config" "${NEW_XDG_CONFIG_HOME}/yt-dlp/config" \
  --bind "${HOME}/Downloads/" "${NEW_HOME}/Downloads/" \
  --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
  --ro-bind /lib/libcrypto.so.3 /lib/libcrypto.so.3 \
  --ro-bind /lib/libssl.so.3 /lib/libssl.so.3 \
  --ro-bind /lib/libz.so.1 /lib/libz.so.1 \
  --ro-bind /usr/bin/ffmpeg /usr/bin/ffmpeg \
  --ro-bind /usr/bin/python3 /usr/bin/python3 \
  --ro-bind /usr/bin/yt-dlp /usr/bin/yt-dlp \
  --ro-bind /usr/lib/ /usr/lib/ \
  /usr/bin/yt-dlp "$@"}}
--bind "${HOME}/Downloads/" "${NEW_HOME}/Downloads/" \
Directory for writing the files.  This should match {{Ic|--output}} that
is either in {{Path|"${XDG_CONFIG_HOME}/yt-dlp/config"}} or passed on
the command line.
/usr/bin/yt-dlp "$@"
This is so you can pass more options to {{Ic|bwrap-yt-dlp}}, for example:
$ bwrap-yt-dlp --no-playlist 'URL1' 'URL2'


== zathura ==
== zathura ==


{{Cat|~/.local/bin/bwrap-zathura|#!/usr/bin/env sh
{{Cat|~/.local/bin/bwrap-zathura|#!/bin/sh


# zathura wrapped in bwrap.
# zathura wrapped in bwrap.

Latest revision as of 07:24, 24 May 2024

This material is work-in-progress ...

Someone more experienced needs to look over this.
(Last edited by Encode on 24 May 2024.)

Todo:
  • Since bubblewrap can make use of seccomp, restrictive versions should be added.
  • imv, mpv and zathura currently only accept 1 mandatory (except imv) argument. This should (hopefully) be temporary, until I figure out how to pass multiple arguments (without including everything else).


Warning: These were found by going backward; start with a complicated program and as restricted as possible sandbox, allowing more till the program appears to work. Because of this, complicated and sensitive programs (for example: firefox and keepassxc) may be missing some things they need, which might lead to LESS SECURITY, LESS PRIVACY and DATA LOSS.


Note:
  • This page assumes you have already read Bubblewrap.
  • To try and avoid duplicates everything will be explained for Firefox and only when it differs (non obviously) for everything else.
  • Where applicable, this assumes: Wayland only + PipeWire.
If Wayland is needed, make sure you have dealt with XDG_RUNTIME_DIR.

Firefox

Contents of ~/.local/bin/bwrap-firefox

#!/bin/sh # Firefox wrapped in bwrap with network access. set -u XDG_CACHE_HOME="${XDG_CACHE_HOME:=$HOME/.cache}" XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}" NEW_HOME='/home/user' NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}" mkdir -pm 0700 "${XDG_DATA_HOME}/firefox/" /usr/bin/bwrap \ --unshare-all \ --share-net \ --new-session \ --die-with-parent \ --clearenv \ --setenv HOME "$NEW_HOME" \ --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \ --setenv XDG_CACHE_HOME "$NEW_XDG_CACHE_HOME" \ --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \ --hostname localhost \ --dev /dev/ \ --ro-bind /etc/fonts/ /etc/fonts/ \ --ro-bind /etc/resolv.conf /etc/resolv.conf \ --bind-try "${XDG_CACHE_HOME}/mozilla/" "${NEW_XDG_CACHE_HOME}/mozilla/" \ --bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \ --bind-try "${HOME}/Downloads/" "${NEW_HOME}/Downloads/" \ --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \ --ro-bind /lib/libblkid.so.1 /lib/libblkid.so.1 \ --ro-bind /lib/libcrypto.so.3 /lib/libcrypto.so.3 \ --ro-bind /lib/libmount.so.1 /lib/libmount.so.1 \ --ro-bind /lib/libz.so.1 /lib/libz.so.1 \ --proc /proc/ \ --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \ --ro-bind /usr/lib/ /usr/lib/ \ --ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \ --ro-bind /usr/share/fontconfig/ /usr/share/fontconfig/ \ --ro-bind /usr/share/fonts/ /usr/share/fonts/ \ --ro-bind /usr/share/glib-2.0/ /usr/share/glib-2.0/ \ --ro-bind /usr/share/icons/ /usr/share/icons/ \ --ro-bind /usr/share/icu/ /usr/share/icu/ \ --ro-bind /usr/share/mime/ /usr/share/mime/ \ /usr/lib/firefox/firefox
set -u

If the shell tries to expand an unset parameter, it will error (with a few exceptions).

XDG_CACHE_HOME="${XDG_CACHE_HOME:=$HOME/.cache}"
XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}"

Take value if already set, else fallback to the XDG default.

NEW_HOME='/home/user'

User to appear as.

NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}"

"$XDG_CACHE_HOME" for the new user.

mkdir -pm 0700 "${XDG_DATA_HOME}/firefox/"

Make sure the new (real) home for Firefox data exist.

--unshare-all \

Unshare all possible namespaces.

--share-net \

Retain the network namespace.

--new-session \

New terminal session for the sandbox.

--die-with-parent \

Child process dies when bwrap parent dies.

--clearenv \

Unset all environment variables (except for "$PWD").

--setenv HOME "$NEW_HOME" \

Pass the path to "$NEW_HOME" for "$HOME".

--setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \

Specify the Wayland display to run clients on.

--setenv XDG_CACHE_HOME "$NEW_XDG_CACHE_HOME" \

User-specific non-essential (cached) data.

--setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \

User-specific non-essential runtime files and other file objects.

--hostname localhost \

Use custom hostname in the sandbox.

--dev /dev/ \

New devtmpfs, access to special or device files.

--ro-bind /etc/fonts/ /etc/fonts/ \

System font configuration directory.

--ro-bind /etc/resolv.conf /etc/resolv.conf \

Needed for DNS resolution.

--bind-try "${XDG_CACHE_HOME}/mozilla/" "${NEW_XDG_CACHE_HOME}/mozilla/" \

Per-user Mozilla cache.

...
XDG_CACHE_HOME="${XDG_CACHE_HOME:=$HOME/.cache}"
XDG_CONFIG_HOME "${XDG_CONFIG_HOME:=$HOME/.config}"
XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}"
...
NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}"
NEW_XDG_CONFIG_HOME="${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}"

...
--setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
--setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \
--setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
...
--bind-try "${XDG_CACHE_HOME}/mozilla/" "${NEW_XDG_CACHE_HOME}/mozilla/" \
--ro-bind-try "${XDG_CONFIG_HOME}/fontconfig/" "${NEW_XDG_CONFIG_HOME}/fontconfig/" \
--bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \
...

(Optional) Per-user font configuration directory.

...
XDG_CACHE_HOME="${XDG_CACHE_HOME:=$HOME/.cache}"
XDG_CONFIG_HOME "${XDG_CONFIG_HOME:=$HOME/.config}"
XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}"
...
NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}"
NEW_XDG_CONFIG_HOME="${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}"

...
--setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
--setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \
--setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
...
--bind-try "${XDG_CACHE_HOME}/mozilla/" "${XDG_CACHE_HOME}/mozilla/" \
--ro-bind-try "${XDG_CONFIG_HOME}/user-dirs.dirs" "${NEW_XDG_CONFIG_HOME}/user-dirs.dirs" \
--bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \
...

(Optional) If you modify "well known" user directories, like ~/Downloads/, you need this to have Firefox pick it up.

Note: If you use "${XDG_CONFIG_HOME}/user-dirs.dirs" you should also add the corresponding path(s).

For example if you set XDG_DOWNLOAD_DIR to "${HOME}/downloads/" you would also add:

 ...
 --bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \
 --bind-try "${HOME}/downloads/" "${NEW_HOME}/downloads/" \
 --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
 ...
--bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \

"${XDG_DATA_HOME}/firefox/" is the location of Firefox data. Shown to Firefox as "${NEW_HOME}/.mozilla/".

Note: This has the added benefit of getting ~/.mozilla/ out of your "$HOME", and conforming more to XDG. This may one day not be necessary: Support for the Freedesktop.org XDG Base Directory Specification (2004-09-14).
...
NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}"
NEW_XDG_DATA_HOME="${NEW_HOME}${XDG_DATA_HOME#"$HOME"}"

...
--setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
--setenv XDG_DATA_HOME "$NEW_XDG_DATA_HOME" \
--setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
...
--bind "${XDG_DATA_HOME}/firefox/" "${NEW_HOME}/.mozilla/" \
--ro-bind-try "${XDG_DATA_HOME}/fonts/" "${NEW_XDG_DATA_HOME}/fonts/" \
--bind-try "${HOME}/Downloads/" "${NEW_HOME}/Downloads/" \
...

(Optional) Per-user directory scanned for font files.

--bind-try "${HOME}/Downloads/" "${NEW_HOME}/Downloads/" \

Default ~/Downloads/ directory.

--ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
--ro-bind /lib/libblkid.so.1 /lib/libblkid.so.1 \
--ro-bind /lib/libcrypto.so.3 /lib/libcrypto.so.3 \
--ro-bind /lib/libmount.so.1 /lib/libmount.so.1 \
--ro-bind /lib/libz.so.1 /lib/libz.so.1 \

Shared libraries.

--proc /proc/ \

New procfs, provides information about running processes and the kernel.

--ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \

Bind the Wayland socket file.

--ro-bind /usr/lib/ /usr/lib/ \

Object files and libraries.

Note: It is not worth the time to limit this, the churn is too great.
--ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \

XKB is a keyboard keymap support library.

Note: Even tho the path has */X11/* Wayland uses it too.
--ro-bind /usr/share/fontconfig/ /usr/share/fontconfig/ \

Font presets.

--ro-bind /usr/share/fonts/ /usr/share/fonts/ \

Global directory scanned for font files.

--ro-bind /usr/share/glib-2.0/ /usr/share/glib-2.0/ \

Needed for "Save Page As…", "Export|Import Bookmarks File", among others.

--ro-bind /usr/share/icons/ /usr/share/icons/ \

Global icons directory.

--ro-bind /usr/share/icu/ /usr/share/icu/ \

International Components for Unicode (ICU) provides support for Unicode and globalization.

...
--ro-bind /usr/share/icu/ /usr/share/icu/ \
--ro-bind /usr/share/libdrm/ /usr/share/libdrm/ \
--ro-bind /usr/share/mime/ /usr/share/mime/ \
...

(Optional) Direct Rendering Manager (DRM), Linux kernel subsystem for interfacing with GPUs of video cards. Programs can use this to have the GPU do hardware-accelerated 3D rendering and video decoding.

--ro-bind /usr/share/mime/ /usr/share/mime/ \

Global XDG MIME directory.

/usr/lib/firefox/firefox

Call Firefox.

Tip: If you use multiple profiles you can have:
/usr/lib/firefox/firefox -P "$@"
this will allow you to pass a profile name and go into that specific one or not pass anything and get prompted for which to choose.

PipeWire audio

Todo:


Pulse audio

...
--proc /proc/ \
--ro-bind "${XDG_RUNTIME_DIR}/pulse/" "${XDG_RUNTIME_DIR}/pulse/" \
--ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
...

(Optional) Pulse audio.

Optional(?) stuff

This material is work-in-progress ...

Are these needed?
(Last edited by Encode on 24 May 2024.)

...
--proc /proc/ \
--ro-bind /sys/bus/pci/ /sys/bus/pci/ \
--ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
...

Information about PCI bus type.

Without this you get

Crash Annotation GraphicsCriticalError: |[0][GFX1-]: glxtest: cannot access /sys/bus/pci (t=0.177033) [GFX1-]: glxtest: cannot access /sys/bus/pci

but it still seems to work.

...
--proc /proc/ \
--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \
--ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
...

Contains a filesystem representation of the kernel device tree.

With --ro-bind /sys/bus/pci/ /sys/bus/pci/ \ but without this you get:

Crash Annotation GraphicsCriticalError: |[0][GFX1-]: glxtest: ManageChildProcess failed
 (t=0.189558) [GFX1-]: glxtest: ManageChildProcess failed
Crash Annotation GraphicsCriticalError: |[0][GFX1-]: glxtest: ManageChildProcess failed
 (t=0.189558) |[1][GFX1-]: No GPUs detected via PCI
 (t=0.18958) [GFX1-]: No GPUs detected via PCI

but it still seems to work.

imv

Contents of ~/.local/bin/bwrap-imv

#!/bin/sh # imv wrapped in bwrap. set -u XDG_CONFIG_HOME="${XDG_CONFIG_HOME:=$HOME/.config}" /usr/bin/bwrap \ --unshare-all \ --new-session \ --die-with-parent \ --clearenv \ --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \ --setenv XDG_CONFIG_HOME "$XDG_CONFIG_HOME" \ --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \ --ro-bind /bin/sh /bin/sh \ --dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \ --ro-bind-try "${XDG_CONFIG_HOME}/imv/config" "${XDG_CONFIG_HOME}/imv/config" \ --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \ --ro-bind /lib/libblkid.so.1 /lib/libblkid.so.1 \ --ro-bind /lib/libmount.so.1 /lib/libmount.so.1 \ --ro-bind /lib/libz.so.1 /lib/libz.so.1 \ --ro-bind /sys/dev/char/ /sys/dev/char/ \ --ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \ --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \ --ro-bind /usr/lib/ /usr/lib/ \ --ro-bind /usr/libexec/imv-wayland /usr/libexec/imv-wayland \ --ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \ --ro-bind "${1:-./}" "$(realpath "${1:-./}")" \ /usr/libexec/imv-wayland "${1:-./}"
--ro-bind /bin/sh /bin/sh \

Needed to use config and have various information in the window title.

...

XDG_CACHE_HOME="${XDG_CACHE_HOME:=$HOME/.cache}"
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:=$HOME/.config}"
XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}"

...
--setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
--setenv XDG_CACHE_HOME "$XDG_CACHE_HOME" \
--setenv XDG_CONFIG_HOME "$XDG_CONFIG_HOME" \
--setenv XDG_DATA_HOME "$XDG_DATA_HOME" \
--setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
...
--dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \
--ro-bind /etc/fonts/ /etc/fonts/ \
--bind-try "${XDG_CACHE_HOME}/fontconfig/" "${XDG_CACHE_HOME}/fontconfig/" \
--ro-bind-try "${XDG_CONFIG_HOME}/fontconfig/" "${XDG_CONFIG_HOME}/fontconfig/" \
--ro-bind-try "${XDG_CONFIG_HOME}/imv/config" "${XDG_CONFIG_HOME}/imv/config" \
--ro-bind-try "${XDG_DATA_HOME}/fonts/" "${XDG_DATA_HOME}/fonts/" \
--ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
...
--ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \
--ro-bind /usr/share/fonts/ /usr/share/fonts/ \
--ro-bind /usr/share/icu/ /usr/share/icu/ \
--ro-bind "${1:-./}" "$(realpath "${1:-./}")" \
...

(Optional) To use commands in imv.

--ro-bind /sys/dev/char/ /sys/dev/char/ \

Access to character devices.

--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \

Access to PCI resources.

--ro-bind "${1:-./}" "$(realpath "${1:-./}")" \

Get the absolute pathname using realpath, so you can pass a relative argument and still bind the argument. If you don't pass in anything it will default to ./, the current directory.

Warning: If you don't pass anything and it defaults to the current directory, it will have everything under that directory shown to imv, recursively.


KeePassXC

Note: I only use the bare minimum functionality, so functionality you need is probably missing. If you use functionality not here, your contribution will be most appreciated. To kick things off: Unable to initialize libusb. USB devices may not be detected properly. can be silenced with --dev-bind /dev/bus/usb/ /dev/bus/usb/ \.

Contents of ~/.local/bin/bwrap-keepassxc

#!/bin/sh # keepassxc wrapped in bwrap. set -u XDG_CONFIG_HOME="${XDG_CONFIG_HOME:=$HOME/.config}" PASSWORD_DATABASE="${HOME}/password database" NEW_HOME='/home/user' NEW_XDG_CONFIG_HOME="${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}" NEW_PASSWORD_DATABASE="${NEW_HOME}${PASSWORD_DATABASE#"$HOME"}" mkdir -pm 0700 "$PASSWORD_DATABASE" /usr/bin/bwrap \ --unshare-all \ --new-session \ --die-with-parent \ --clearenv \ --setenv HOME "$NEW_HOME" \ --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \ --setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \ --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \ --setenv XDG_SESSION_TYPE "$XDG_SESSION_TYPE" \ --dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \ --ro-bind /etc/fonts/ /etc/fonts/ \ --bind-try "${XDG_CONFIG_HOME}/keepassxc/" "${NEW_XDG_CONFIG_HOME}/keepassxc/" \ --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \ --ro-bind /lib/libcrypto.so.3 /lib/libcrypto.so.3 \ --ro-bind /lib/libssl.so.3 /lib/libssl.so.3 \ --ro-bind /lib/libz.so.1 /lib/libz.so.1 \ --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \ --ro-bind /sys/dev/char/ /sys/dev/char/ \ --ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \ --ro-bind /usr/bin/keepassxc /usr/bin/keepassxc \ --ro-bind /usr/lib/ /usr/lib/ \ --ro-bind /usr/share/X11/ /usr/share/X11/ \ --ro-bind /usr/share/fontconfig/ /usr/share/fontconfig/ \ --ro-bind /usr/share/fonts/ /usr/share/fonts/ \ --ro-bind /usr/share/keepassxc/ /usr/share/keepassxc/ \ --bind "$PASSWORD_DATABASE/" "$NEW_PASSWORD_DATABASE/" \ /usr/bin/keepassxc "$@"
PASSWORD_DATABASE="${HOME}/password database"

Directory containing your keepassxc password database.

Tip: This is almost certainly not where your database is located. You will need to change it to where you put your password database.
--setenv XDG_SESSION_TYPE "$XDG_SESSION_TYPE" \

Session type, since we are assuming Wayland only, this will be "wayland".

--ro-bind /sys/dev/char/ /sys/dev/char/ \

Access to character devices.

--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \

Access to PCI resources.

--bind "$PASSWORD_DATABASE/" "$NEW_PASSWORD_DATABASE/" \

Bind password database.

mpv

Contents of ~/.local/bin/bwrap-mpv

#!/bin/sh # mpv wrapped in bwrap. set -u if [ "$#" != 1 ] then printf 'Run mpv wrapped in bwrap. Usage: $ bwrap-mpv VIDEO\n' exit 1 fi XDG_CACHE_HOME="${XDG_CACHE_HOME:=$HOME/.cache}" XDG_CONFIG_HOME="${XDG_CONFIG_HOME:=$HOME/.config}" NEW_HOME='/home/user' NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}" NEW_XDG_CONFIG_HOME="${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}" /usr/bin/bwrap \ --unshare-all \ --new-session \ --die-with-parent \ --clearenv \ --setenv HOME "$NEW_HOME" \ --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \ --setenv XDG_CACHE_HOME "$NEW_XDG_CACHE_HOME" \ --setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \ --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \ --hostname localhost \ --dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \ --ro-bind /etc/fonts/ /etc/fonts/ \ --ro-bind /etc/mpv/ /etc/mpv/ \ --bind-try "${XDG_CACHE_HOME}/mesa_shader_cache/" "${NEW_XDG_CACHE_HOME}/mesa_shader_cache/" \ --ro-bind-try "${XDG_CONFIG_HOME}/mpv/mpv.conf" "${NEW_XDG_CONFIG_HOME}/mpv/mpv.conf" \ --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \ --ro-bind /lib/libacl.so.1 /lib/libacl.so.1 \ --ro-bind /lib/libcrypto.so.3 /lib/libcrypto.so.3 \ --ro-bind /lib/libssl.so.3 /lib/libssl.so.3 \ --ro-bind /lib/libz.so.1 /lib/libz.so.1 \ --proc /proc/ \ --ro-bind /sys/dev/char/ /sys/dev/char/ \ --ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \ --ro-bind "${XDG_RUNTIME_DIR}/pipewire-0" "${XDG_RUNTIME_DIR}/pipewire-0" \ --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \ --ro-bind /usr/bin/mpv /usr/bin/mpv \ --ro-bind /usr/lib/ /usr/lib/ \ --ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \ --ro-bind /usr/share/fontconfig/ /usr/share/fontconfig/ \ --ro-bind /usr/share/fonts/ /usr/share/fonts/ \ --ro-bind /usr/share/pipewire/ /usr/share/pipewire/ \ --ro-bind "$1" "$(realpath "$1")" \ /usr/bin/mpv \ --player-operation-mode=pseudo-gui \ --title='bwrap | ${media-title}' \ "$1"
--ro-bind /sys/dev/char/ /sys/dev/char/ \

Access to character devices.

--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \

Access to PCI resources.

--ro-bind "$1" "$(realpath "$1")" \

Get the absolute pathname using realpath, so you can pass a relative argument and still bind the argument.

--player-operation-mode=pseudo-gui \

Because --new-session is used, this is needed to have a way to control mpv when it would otherwise not show a GUI.

Tip: If you followed Bubblewrap#.desktop_integration, you should remove it from "${XDG_DATA_HOME}/applications/bwrap-mpv.desktop".
--title='bwrap | ${media-title}' \

Set the window title, showing at a glance that you are using bwrap.

mpv-net

If you want to use mpv to stream over the Internet, you will need a few things more.

Tip: You can use both bwrap-mpv and bwrap-mpv-net. bwrap-mpv for local stuff and bwrap-mpv-net for watching over the Internet.

Contents of ~/.local/bin/bwrap-mpv-net

#!/bin/sh # mpv wrapped in bwrap with network access. set -u XDG_CACHE_HOME="${XDG_CACHE_HOME:=$HOME/.cache}" XDG_CONFIG_HOME="${XDG_CONFIG_HOME:=$HOME/.config}" NEW_HOME='/home/user' NEW_XDG_CACHE_HOME="${NEW_HOME}${XDG_CACHE_HOME#"$HOME"}" NEW_XDG_CONFIG_HOME="${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}" /usr/bin/bwrap \ --unshare-all \ --share-net \ --new-session \ --die-with-parent \ --clearenv \ --setenv HOME "$NEW_HOME" \ --setenv PATH /usr/bin/ \ --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \ --setenv XDG_CACHE_HOME "$NEW_XDG_CACHE_HOME" \ --setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \ --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \ --hostname localhost \ --dev /dev/ \ --dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \ --ro-bind /etc/fonts/ /etc/fonts/ \ --ro-bind /etc/mpv/ /etc/mpv/ \ --ro-bind /etc/resolv.conf /etc/resolv.conf \ --ro-bind /etc/ssl/certs/ /etc/ssl/certs/ \ --bind-try "${XDG_CACHE_HOME}/mesa_shader_cache/" "${NEW_XDG_CACHE_HOME}/mesa_shader_cache/" \ --ro-bind-try "${XDG_CONFIG_HOME}/mpv/mpv.conf" "${NEW_XDG_CONFIG_HOME}/mpv/mpv.conf" \ --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \ --ro-bind /lib/libacl.so.1 /lib/libacl.so.1 \ --ro-bind /lib/libcrypto.so.3 /lib/libcrypto.so.3 \ --ro-bind /lib/libssl.so.3 /lib/libssl.so.3 \ --ro-bind /lib/libz.so.1 /lib/libz.so.1 \ --proc /proc/ \ --ro-bind /sys/dev/char/ /sys/dev/char/ \ --ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \ --ro-bind "${XDG_RUNTIME_DIR}/pipewire-0" "${XDG_RUNTIME_DIR}/pipewire-0" \ --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \ --ro-bind /usr/bin/mpv /usr/bin/mpv \ --ro-bind /usr/bin/python3 /usr/bin/python3 \ --ro-bind /usr/bin/yt-dlp /usr/bin/yt-dlp \ --ro-bind /usr/lib/ /usr/lib/ \ --ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \ --ro-bind /usr/share/fontconfig/ /usr/share/fontconfig/ \ --ro-bind /usr/share/fonts/ /usr/share/fonts/ \ --ro-bind /usr/share/pipewire/ /usr/share/pipewire/ \ /usr/bin/mpv \ --player-operation-mode=pseudo-gui \ --title='bwrap | ${media-title}' \ "$@"
--setenv PATH /usr/bin/ \
Todo: Document why this is needed.


--ro-bind /etc/ssl/certs/ /etc/ssl/certs/ \

Certificate authorities that are trusted.

--ro-bind /sys/dev/char/ /sys/dev/char/ \

Access to character devices.

--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \

Access to PCI resources.

"$@"

This is so you can pass more options to bwrap-mpv-net, for example:

$ bwrap-mpv-net --video=no --sub=no 'URL1' 'URL2'

Pulse audio

--ro-bind "${XDG_RUNTIME_DIR}/pulse" "${XDG_RUNTIME_DIR}/pulse" \

Pulse audio.

Screenshots

The default screenshots directory is "$XDG_DESKTOP_DIR" (which is "${HOME}/Desktop/", which will fallback to "$HOME/" if "${HOME}/Desktop/" doesn't exist). That means that by default bwrap-mpv[-net] won't allow screenshots unless you change a few things. Do the following to allow an XDG approved screenshots directory:

...
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:=$HOME/.config}"
XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}"

...
NEW_XDG_CONFIG_HOME="${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}"
NEW_XDG_DATA_HOME="${NEW_HOME}${XDG_DATA_HOME#"$HOME"}"

mkdir -pm 0700 "${XDG_DATA_HOME}/mpv/"

...
--setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \
--setenv XDG_DATA_HOME "$NEW_XDG_DATA_HOME" \
--setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
...
--ro-bind-try "${XDG_CONFIG_HOME}/mpv/mpv.conf" "${NEW_XDG_CONFIG_HOME}/mpv/mpv.conf" \
--bind "${XDG_DATA_HOME}/mpv/" "${NEW_XDG_DATA_HOME}/mpv/" \
--ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
...

Now make mpv use that directory:

Contents of "${XDG_CONFIG_HOME}/mpv/mpv.conf"

... # Something like this, change to match "$XDG_DATA_HOME" screenshot-template="~/.local/share/mpv/screenshots/%F [%p] %02n" ...

yt-dlp

Contents of ~/.local/bin/bwrap-yt-dlp

#!/bin/sh # yt-dlp wrapped in bwrap with network access. set -u XDG_CONFIG_HOME="${XDG_CONFIG_HOME:=$HOME/.config}" NEW_HOME='/home/user' NEW_XDG_CONFIG_HOME="${NEW_HOME}${XDG_CONFIG_HOME#"$HOME"}" mkdir -pm 0700 "${HOME}/Downloads/" /usr/bin/bwrap \ --unshare-all \ --share-net \ --new-session \ --die-with-parent \ --clearenv \ --setenv HOME "$NEW_HOME" \ --setenv XDG_CONFIG_HOME "$NEW_XDG_CONFIG_HOME" \ --hostname localhost \ --ro-bind /etc/resolv.conf /etc/resolv.conf \ --ro-bind /etc/ssl/certs/ /etc/ssl/certs/ \ --ro-bind-try "${XDG_CONFIG_HOME}/yt-dlp/config" "${NEW_XDG_CONFIG_HOME}/yt-dlp/config" \ --bind "${HOME}/Downloads/" "${NEW_HOME}/Downloads/" \ --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \ --ro-bind /lib/libcrypto.so.3 /lib/libcrypto.so.3 \ --ro-bind /lib/libssl.so.3 /lib/libssl.so.3 \ --ro-bind /lib/libz.so.1 /lib/libz.so.1 \ --ro-bind /usr/bin/ffmpeg /usr/bin/ffmpeg \ --ro-bind /usr/bin/python3 /usr/bin/python3 \ --ro-bind /usr/bin/yt-dlp /usr/bin/yt-dlp \ --ro-bind /usr/lib/ /usr/lib/ \ /usr/bin/yt-dlp "$@"
--bind "${HOME}/Downloads/" "${NEW_HOME}/Downloads/" \

Directory for writing the files. This should match --output that is either in "${XDG_CONFIG_HOME}/yt-dlp/config" or passed on the command line.

/usr/bin/yt-dlp "$@"

This is so you can pass more options to bwrap-yt-dlp, for example:

$ bwrap-yt-dlp --no-playlist 'URL1' 'URL2'

zathura

Contents of ~/.local/bin/bwrap-zathura

#!/bin/sh # zathura wrapped in bwrap. set -u if [ "$#" != 1 ] then printf 'Run zathura wrapped in bwrap. Usage: $ bwrap-zathura PDF\n' exit 1 fi XDG_CONFIG_HOME="${XDG_CONFIG_HOME:=$HOME/.config}" XDG_DATA_HOME="${XDG_DATA_HOME:=$HOME/.local/share}" mkdir -pm 0700 "${XDG_DATA_HOME}/zathura/" /usr/bin/bwrap \ --unshare-all \ --new-session \ --die-with-parent \ --clearenv \ --setenv HOME "$HOME" \ --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \ --setenv XDG_CONFIG_HOME "$XDG_CONFIG_HOME" \ --setenv XDG_DATA_HOME "$XDG_DATA_HOME" \ --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \ --ro-bind /etc/fonts/ /etc/fonts/ \ --ro-bind-try "${XDG_CONFIG_HOME}/zathura/zathurarc" "${XDG_CONFIG_HOME}/zathura/zathurarc" \ --bind "${XDG_DATA_HOME}/zathura/" "${XDG_DATA_HOME}/zathura/" \ --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \ --ro-bind /lib/libblkid.so.1 /lib/libblkid.so.1 \ --ro-bind /lib/libmount.so.1 /lib/libmount.so.1 \ --ro-bind /lib/libz.so.1 /lib/libz.so.1 \ --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \ --ro-bind /usr/bin/zathura /usr/bin/zathura \ --ro-bind /usr/lib/ /usr/lib/ \ --ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \ --ro-bind /usr/share/fonts/ /usr/share/fonts/ \ --ro-bind /usr/share/misc/magic.mgc /usr/share/misc/magic.mgc \ --ro-bind "$1" "$(realpath "$1")" \ /usr/bin/zathura "$1"
mkdir -pm 0700 "${XDG_DATA_HOME}/zathura/"

Have to premake the directory for zathura data.

--bind "${XDG_DATA_HOME}/zathura/" "${XDG_DATA_HOME}/zathura/" \

Allow writing of: bookmarks, history, input history.

--ro-bind /usr/share/misc/magic.mgc /usr/share/misc/magic.mgc \

Used for identifying what type a file should be. Read the file(1) man page for more information.

--ro-bind "$1" "$(realpath "$1")" \

Get the absolute pathname using realpath, so you can pass a relative argument and still bind the argument.