Bubblewrap: Difference between revisions

From Alpine Linux
m (Formatting + desktop category)
m (Use default values, instead of assign default values. Doesn't matter in this situation, but will lead to surprising results in most situations.)
 
(12 intermediate revisions by 2 users not shown)
Line 14: Line 14:
== Installation ==
== Installation ==


Install {{Pkg|bubblewrap}}:
Install {{Pkg|bubblewrap|arch=}}:


{{Cmd|# apk add bubblewrap}}
{{Cmd|# apk add bubblewrap}}


{{Note|The package is {{ic|bubblewrap}} but the command to
{{Note|The package is {{pkg|bubblewrap|arch=}} but the command to
manage it is {{ic|bwrap}}.}}
manage it is {{Ic|bwrap}}.}}


== How to workout what a program needs ==
== How to workout what a program needs ==


Look at [[Bubblewrap/Examples]] to see various ways bubblewrap can be used.
{{Tip|Look at [[Bubblewrap/Examples]] to see various ways {{Ic|bwrap}} can be used.}}


=== Prerequisites ===
=== Prerequisites ===


First make sure to have a user editable directory in {{ic|$PATH}}. This
First make sure to have a user editable directory in {{Path|"$PATH"}}.
page will use {{Path|"${HOME}"/.local/bin}}, create it if it does not
This page will use {{Path|"${HOME}/.local/bin/"}}, create it if it does
exist:
not exist:


{{Cmd|$ mkdir -p ~/.local/bin}}
{{Cmd|$ mkdir -p ~/.local/bin}}
Line 36: Line 36:


{{Cat|~/.profile|...<nowiki>
{{Cat|~/.profile|...<nowiki>
export PATH="${PATH}":"${HOME}"/.local/bin
PATH="${PATH}":"${HOME}/.local/bin"
export PATH
</nowiki>...}}
</nowiki>...}}


Line 43: Line 44:
=== Basic bwrap setup ===
=== Basic bwrap setup ===


{{Note|With how we will be sandboxing everything that doesn't match our owner/group will show as {{ic|nobody}}.}}
{{Note|With how we will be sandboxing everything that doesn't match our owner/group will show as {{Ic|nobody}}.}}


Lets assume you want to sandbox {{Pkg|imv}} and are using [[Wayland]]
Lets assume you want to sandbox {{Pkg|imv|arch=}} and are using [[Wayland]]
only.  Here is how you might go about that.
only.  Here is how you might go about that.


Create {{ic|bwrap-imv}} inside {{Path|"${HOME}"/.local/bin}} and make it
Create {{Ic|bwrap-imv}} inside {{Path|"${HOME}/.local/bin/"}} and make it
executable:
executable:


Line 54: Line 55:
$ chmod 0700 ~/.local/bin/bwrap-imv}}
$ chmod 0700 ~/.local/bin/bwrap-imv}}


Use {{ic|file}} to determine the file type of {{Path|/usr/bin/imv}}:
Use {{Ic|file}} to determine the file type of {{Path|/usr/bin/imv}}:


{{Cmd|$ file /usr/bin/imv
{{Cmd|$ file /usr/bin/imv
/usr/bin/imv: POSIX shell script, ASCII text executable}}
/usr/bin/imv: POSIX shell script, ASCII text executable}}


Use {{ic|less}} to view it:
Since it is just a shell script, we can use {{Ic|less}} to view it:


{{Cmd|$ less /usr/bin/imv}}
{{Cmd|$ less /usr/bin/imv}}
Line 71: Line 72:


Since we are assuming Wayland only we can just skip to
Since we are assuming Wayland only we can just skip to
{{Path|/usr/libexec/imv-wayland}}.  Run {{ic|file}} on it:
{{Path|/usr/libexec/imv-wayland}}.  Run {{Ic|file}} on it:


{{Cmd|$ file /usr/libexec/imv-wayland
{{Cmd|$ file /usr/libexec/imv-wayland
Line 81: Line 82:
{{Path|/lib/ld-musl-x86_64.so.1}}.  We also know we need
{{Path|/lib/ld-musl-x86_64.so.1}}.  We also know we need
{{Path|/usr/libexec/imv-wayland}}, since it has to know where the command
{{Path|/usr/libexec/imv-wayland}}, since it has to know where the command
is located.  As the argument to {{ic|/usr/libexec/imv-wayland}}, put
is located.
{{ic|"${@:-./}"}}, this will generate a separate word for each
positional parameter and if you didn't have any parameters it will
default to current directory.


Running {{ic|ldd}} to find all necessary libs, except ones loaded at
As the argument to {{Ic|/usr/libexec/imv-wayland}}, put
runtime, on {{Path|/usr/libexec/imv-wayland}}, outputs a lot of things but
{{Ic|"${1:-./}"}}, this will pass '''only''' the first argument and if
for the moment all we care about are the directory pathsSpecifically
there is none, will default to {{Path|./}}, the current directory.  We
the starting directories, which are {{ic|/lib/*}} and {{ic|/usr/lib/*}}.
will also need {{Ic|--ro-bind "${1:-./}" "$(realpath "${1:-./}")" \}},
since we are not passing the whole filesystemThis will get the
absolute pathname using {{Ic|realpath}}, so you can pass a relative
argument and still bind the argument:
--ro-bind "${1:-./}" "$(realpath "${1:-./}")" \
/usr/libexec/imv-wayland "${1:-./}"


{{Warning|The {{ic|ldd}} manpage talks about some security implications. It may not apply since they seem to be talking about glibc and {{Pkg|musl-utils}} makes {{Path|/lib/ld-musl-x86_64.so.1}} ldd [https://git.alpinelinux.org/aports/tree/main/musl/APKBUILD#n105].  Is this something to worry about?}}
{{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.}}
{{Todo|How can you pass 2+ arguments?}}


Since this is for [[Wayland]] lets also add some prerequisites:
Find necessary shared libraries, except ones loaded at runtime:
  --setenv XDG_RUNTIME_DIR "${XDG_RUNTIME_DIR}" \
 
{{Cmd|$ ldd /usr/libexec/imv-wayland}}
 
It outputs a lot of things but we only need a few; the directory path of
the majority {{Path|/usr/lib/*}} and the 4 paths that start with
{{Path|/lib/*}}.  Filter the output to see those clearer:
 
{{Cmd|$ ldd /usr/libexec/imv-wayland {{!}} grep ' /lib/'}}
 
In total:
--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 /usr/lib/ /usr/lib/ \
 
{{Note|It is not worth the time to limit {{Path|/usr/lib/*}}, the churn is too great.}}
 
{{Warning|The {{Ic|ldd}} manpage talks about some security implications.  It may not apply since they seem to be talking about glibc and {{Pkg|musl-utils|arch=}} makes {{Path|/lib/ld-musl-x86_64.so.1}} ldd [https://git.alpinelinux.org/aports/tree/main/musl/APKBUILD#n105].  Is this something to worry about?}}
 
Since this is a shell script, lets use a helpful command:
set -u
if the shell tries to expand an unset parameter, it will error (with a
few exceptions).
 
Since this is for a GUI [[Wayland]] program, so lets also add some prerequisites:
 
{{Note|Make sure you have dealt with [[Wayland#XDG_RUNTIME_DIR|XDG_RUNTIME_DIR]].}}
 
  --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
for determining the directory for the wayland socket;
for determining the directory for the wayland socket;
  --setenv WAYLAND_DISPLAY "${WAYLAND_DISPLAY}" \
  --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
for determining the socket;
for determining the socket;
   --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 110: Line 143:
terminal;
terminal;
   --die-with-parent
   --die-with-parent
will ensure child process ({{ic|imv-wayland}} in this case) dies when
will ensure child process ({{Ic|imv-wayland}} in this case) dies when
{{ic|bwrap}} parent dies.
{{Ic|bwrap}} parent dies.
 
Since we are not passing the whole filesystem, we need a way to pass the
arguments given:
--ro-bind "${@:-./}" "$(realpath "${@:-./}")" \
this will take all arguments or the current directory and mount to the
absolute path.
 
{{Warning|This will have '''everything''' under the current directory available to {{ic|imv}} if you don't specify an argument.  I don't know how to limit it so you can specify 2+ and '''not''' have '''everything'''.}}


We might also have a {{Path|config}} file:
We might also have a {{Path|config}} file:
  --ro-bind-try "${XDG_CONFIG_HOME}"/imv "${XDG_CONFIG_HOME}"/imv \
  --ro-bind-try "${XDG_CONFIG_HOME}/imv/config" "${XDG_CONFIG_HOME}/imv/config" \
this will add your local config to {{ic|imv}} if you have one and if not
this will add your local config to {{Ic|imv}} if you have one and if not
will still continue.  Add:
will still continue.
--setenv XDG_CONFIG_HOME "${XDG_CONFIG_HOME}" \
for later.


{{Note|If you have your imv config as a symbolic link, where it points to will also need to be added.  Lets say you had a symbolic link that points to {{Path|~/src/dots/imv/config}}, you would do: <br>
Pass {{Path|"$XDG_CONFIG_HOME"}} to sandbox:
<code>--ro-bind-try "${HOME}/src/dots/imv/config" "${HOME}/src/dots/imv/config" \</code> <br> <code>--ro-bind-try "${XDG_CONFIG_HOME}"/imv "${XDG_CONFIG_HOME}"/imv \</code>}}
--setenv XDG_CONFIG_HOME "$XDG_CONFIG_HOME" \
but this isn't always defined, so lets fallback to the
[https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html XDG Base Directory]
default:
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
this will use {{Path|"$XDG_CONFIG_HOME"}} if it's set, otherwise
fallback to the default of {{Path|"$HOME/.config"}}.


Also need:
--dev-bind /dev/null /dev/null \
and
  --ro-bind /bin/sh /bin/sh \
  --ro-bind /bin/sh /bin/sh \
to make use of your {{Path|config}}.
Needed to use {{Path|config}} and have various information in the window
title.


{{Todo|Document ''why'' this is needed.  This was found by: [[Bubblewrap#Can't_find_what_path_is_missing]], any better way?}}
{{Todo|This was found using: [[Bubblewrap#Can't_find_what_path_is_missing]], any better way?}}


We should also wrap the whole thing in {{ic|(exec ...)}}.  This will
{{Path|~/.local/bin/bwrap-imv}} now looks like:
replace the shell process; no new process is created.  Any changes to
variables are not seen by stuff outside the subshell.


{{Path|~/.local/bin/bwrap-imv}} looks like:
{{Cat|~/.local/bin/bwrap-imv|#!/bin/sh


{{Cat|~/.local/bin/bwrap-imv|#!/usr/bin/env sh
# imv wrapped in bwrap.


# imv wrapped in bwrap.
set -u
 
XDG_CONFIG_HOME{{=}}"${XDG_CONFIG_HOME:-$HOME/.config}"


(exec /usr/bin/bwrap \
/usr/bin/bwrap \
   --unshare-all \
   --unshare-all \
   --new-session \
   --new-session \
   --die-with-parent \
   --die-with-parent \
  --setenv XDG_RUNTIME_DIR "${XDG_RUNTIME_DIR}" \
   --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
   --setenv WAYLAND_DISPLAY "${WAYLAND_DISPLAY}" \
   --setenv XDG_CONFIG_HOME "$XDG_CONFIG_HOME" \
   --setenv XDG_CONFIG_HOME "${XDG_CONFIG_HOME}" \
   --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
   --dev-bind /dev/null /dev/null \
  --ro-bind-try "${XDG_CONFIG_HOME}"/imv "${XDG_CONFIG_HOME}"/imv \
   --ro-bind /bin/sh /bin/sh \
   --ro-bind /bin/sh /bin/sh \
   --ro-bind /lib /lib \
  --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 "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
   --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
   --ro-bind /usr/lib /usr/lib \
   --ro-bind /usr/lib/ /usr/lib/ \
   --ro-bind /usr/libexec/imv-wayland /usr/libexec/imv-wayland \
   --ro-bind /usr/libexec/imv-wayland /usr/libexec/imv-wayland \
   --ro-bind "${@:-./}" "$(realpath "${@:-./}")" \
   --ro-bind "${1:-./}" "$(realpath "${1:-./}")" \
   /usr/libexec/imv-wayland "${@:-./}")}}
   /usr/libexec/imv-wayland "${1:-./}"}}


Now lets run {{ic|bwrap-imv}}; go into a directory with an image:
Now lets run {{Ic|bwrap-imv}}, go into a directory with an image:


{{Cmd|$ bwrap-imv IMAGE
{{Cmd|$ bwrap-imv IMAGE
sh: eval: line 0: can't create /dev/null: nonexistent directory
...
sh: eval: line 0: can't create /dev/null: nonexistent directory
xkbcommon: ERROR: failed to add default include path /usr/share/X11/xkb
xkbcommon: ERROR: failed to add default include path /usr/share/X11/xkb
Assertion failed: keyboard->context (../src/keyboard.c: imv_keyboard_create: 20)}}
Assertion failed: keyboard->context (../src/keyboard.c: imv_keyboard_create: 20)}}


Add:
Add:
   --ro-bind /usr/share/X11/xkb /usr/share/X11/xkb \
   --ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \
to {{ic|bwrap-imv}}.  [https://en.wikipedia.org/wiki/X_keyboard_extension XKB]
to {{Ic|bwrap-imv}}.  [https://en.wikipedia.org/wiki/X_keyboard_extension XKB]
is a keyboard keymap support library.
is a keyboard keymap support library.


Line 180: Line 212:


{{Cmd|$ bwrap-imv IMAGE
{{Cmd|$ bwrap-imv IMAGE
sh: eval: line 0: can't create /dev/null: nonexistent directory
...
sh: eval: line 0: can't create /dev/null: nonexistent directory
libEGL warning: wayland-egl: could not open /dev/dri/renderD128 (No such file or directory)}}
libEGL warning: wayland-egl: could not open /dev/dri/renderD128 (No such file or directory)}}


Line 189: Line 224:
libEGL warning: wayland-egl: drmGetMagic failed}}
libEGL warning: wayland-egl: drmGetMagic failed}}


If you follow [[Bubblewrap#Can't_find_what_path_is_missing]], you will
  --ro-bind /sys/dev/char/ /sys/dev/char/ \
eventually get down to:
Access to character devices.
  --ro-bind /sys/dev/char /sys/dev/char \}}
 
and
{{Todo|This was found using: [[Bubblewrap#Can't_find_what_path_is_missing]], any better way?}}
--ro-bind /sys/devices/pci0000:00 /sys/devices/pci0000:00 \


{{Todo|Document ''why'' this is needed.  This was found by: [[Bubblewrap#Can't_find_what_path_is_missing]], any better way?}}
--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \
Access to PCI resources.
 
{{Todo|This was found using: [[Bubblewrap#Can't_find_what_path_is_missing]], any better way?}}


  --clearenv \
  --clearenv \
can also be added now.  This will unset all environment variables,
Finally we can unset all environment variables, except for
except for {{ic|$PWD}} and any we set with {{ic|--setenv}}.
{{Path|"$PWD"}} and any we set with {{Ic|--setenv}}.


Now {{ic|imv}} should show images and your {{Path|config}} file should
Now {{Ic|imv}} should show images and your {{Path|config}} file should
work.  If you do not use commands, the finished
work (if you have one).  If you do not use commands, the finished
{{Path|~/.local/bin/bwrap-imv}} should look like:
{{Path|~/.local/bin/bwrap-imv}} should look like:


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


# imv wrapped in bwrap.
# imv wrapped in bwrap.


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


If you do use commands however, you will notice it is only showing
If you do use commands however, you will notice it is only showing
[https://en.wikipedia.org/wiki/Substitute_character substitute characters].
[https://en.wikipedia.org/wiki/Substitute_character substitute characters].


{{Tip|Commands in {{ic|imv}} can be entered by pressing {{ic|:}}.}}
{{Tip|Commands in {{Ic|imv}} are entered by pressing {{Ic|:}}.}}


If you try to use a command it will say:
If you try to use a command it will say:
Line 240: Line 283:
  Fontconfig error: Cannot load default config file: No such file: (null)
  Fontconfig error: Cannot load default config file: No such file: (null)


Look at the {{ic|fonts-conf}} manpage (which is from
Look at the {{Ic|fonts-conf}} manpage (which is from
{{Pkg|fontconfig-doc}}) we see that {{Path|/etc/fonts}} is the system
{{Pkg|fontconfig-doc|arch=}}) we see that {{Path|/etc/fonts/}} is the system
font configuration directory and
font configuration directory and
{{Path|"${XDG_CONFIG_HOME}"/fontconfig}} is the per-user configuration
{{Path|"${XDG_CONFIG_HOME}/fontconfig/"}} is the per-user configuration
directory.  Add {{Path|"${XDG_CONFIG_HOME}"/fontconfig/}} with
directory.  {{Path|"${XDG_CONFIG_HOME}/fontconfig/"}} is added with
{{ic|--ro-bind-try}} so it doesn't have to exist:
{{Ic|--ro-bind-try}} so it doesn't have to exist:
  --ro-bind /etc/fonts /etc/fonts \
  --ro-bind /etc/fonts/ /etc/fonts/ \
  --ro-bind-try "${XDG_CONFIG_HOME}"/fontconfig "${XDG_CONFIG_HOME}"/fontconfig \
  --ro-bind-try "${XDG_CONFIG_HOME}/fontconfig/" "${XDG_CONFIG_HOME}/fontconfig/" \


The default directories scanned for font files are
The default directories scanned for font files are
{{Path|/usr/share/fonts/}} and {{Path|"${XDG_DATA_HOME}"/fonts}}. Add
{{Path|/usr/share/fonts/}} and {{Path|"${XDG_DATA_HOME}/fonts/"}}.
{{Path|"${XDG_DATA_HOME}"/fonts}} with {{ic|--ro-bind-try}}:
{{Path|"${XDG_DATA_HOME}/fonts/"}} added with {{Ic|--ro-bind-try}}:
  --ro-bind /usr/share/fonts /usr/share/fonts \
  --ro-bind /usr/share/fonts/ /usr/share/fonts/ \
  --ro-bind-try "${XDG_DATA_HOME}"/fonts "${XDG_DATA_HOME}"/fonts \
  --ro-bind-try "${XDG_DATA_HOME}/fonts/" "${XDG_DATA_HOME}/fonts/" \
Also need:
 
  --setenv XDG_DATA_HOME "${XDG_DATA_HOME}" \
Pass {{Path|"$XDG_DATA_HOME"}} to sandbox:
  --setenv XDG_DATA_HOME "$XDG_DATA_HOME" \
just like for {{Path|"$XDG_CONFIG_HOME"}}, this isn't always defined, so
fallback to
[https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html XDG Base Directory]
default:
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
use {{Path|"$XDG_DATA_HOME"}} if set, else use {{Path|"$HOME/.local/share"}}.


The user cache of font information is also needed, by default
The user cache of font information is also needed, by default
{{Path|"${XDG_CACHE_HOME}"/fontconfig}}:
{{Path|"${XDG_CACHE_HOME}/fontconfig/"}}:
  --bind-try "${XDG_CACHE_HOME}"/fontconfig "${XDG_CACHE_HOME}"/fontconfig \
  --bind-try "${XDG_CACHE_HOME}/fontconfig/" "${XDG_CACHE_HOME}/fontconfig/" \
 
{{Note|It seems to still work with {{ic|--ro-bind-try}}, does it not need to write to it?}}


Also need:
Pass {{Path|"$XDG_CACHE_HOME"}} to sandbox:
  --setenv XDG_CACHE_HOME "${XDG_CACHE_HOME}" \
  --setenv XDG_CACHE_HOME "$XDG_CACHE_HOME" \
just like for {{Path|"$XDG_CONFIG_HOME"}}, this isn't always defined, so
fallback to
[https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html XDG Base Directory]
default:
XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
use {{Path|"$XDG_CACHE_HOME"}} if set, else use {{Path|"$HOME/.cache"}}.


  --ro-bind /usr/share/icu /usr/share/icu \
  --ro-bind /usr/share/icu/ /usr/share/icu/ \
Is also needed or when you do {{ic|:<backspace>}} it will terminate the
Is also needed or when you do {{Ic|:<backspace>}} it will terminate the
process.  ICU provides Unicode and Globalization support.
process.  ICU provides Unicode and Globalization support.


{{Todo|This was found by: [[Bubblewrap#Can't_find_what_path_is_missing]], any better way?}}
{{Todo|This was found using: [[Bubblewrap#Can't_find_what_path_is_missing]], any better way?}}


The updated {{Path|~/.local/bin/bwrap-imv}} should look like this:
The updated {{Path|~/.local/bin/bwrap-imv}} should look like this:


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


# imv wrapped in bwrap.
# imv wrapped in bwrap.


(exec /usr/bin/bwrap \
set -u
 
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}"
 
/usr/bin/bwrap \
   --unshare-all \
   --unshare-all \
   --new-session \
   --new-session \
   --die-with-parent \
   --die-with-parent \
   --clearenv \
   --clearenv \
   --setenv XDG_RUNTIME_DIR "${XDG_RUNTIME_DIR}" \
   --setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \
   --setenv WAYLAND_DISPLAY "${WAYLAND_DISPLAY}" \
   --setenv XDG_CACHE_HOME "$XDG_CACHE_HOME" \
   --setenv XDG_CACHE_HOME "${XDG_CACHE_HOME}" \
   --setenv XDG_CONFIG_HOME "$XDG_CONFIG_HOME" \
   --setenv XDG_CONFIG_HOME "${XDG_CONFIG_HOME}" \
   --setenv XDG_DATA_HOME "$XDG_DATA_HOME" \
   --setenv XDG_DATA_HOME "${XDG_DATA_HOME}" \
   --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
  --ro-bind /bin/sh /bin/sh \
   --dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \
   --dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \
   --dev-bind /dev/null /dev/null \
   --ro-bind /etc/fonts/ /etc/fonts/ \
   --bind-try "${XDG_CACHE_HOME}"/fontconfig "${XDG_CACHE_HOME}"/fontconfig \
   --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}/fontconfig/" "${XDG_CONFIG_HOME}/fontconfig/" \
   --ro-bind-try "${XDG_CONFIG_HOME}"/imv "${XDG_CONFIG_HOME}"/imv \
   --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-try "${XDG_DATA_HOME}/fonts/" "${XDG_DATA_HOME}/fonts/" \
   --ro-bind /bin/sh /bin/sh \
  --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \
   --ro-bind /etc/fonts /etc/fonts \
   --ro-bind /lib/libblkid.so.1 /lib/libblkid.so.1 \
   --ro-bind /lib /lib \
   --ro-bind /lib/libmount.so.1 /lib/libmount.so.1 \
   --ro-bind /sys/dev/char /sys/dev/char \
   --ro-bind /lib/libz.so.1 /lib/libz.so.1 \
   --ro-bind /sys/devices/pci0000:00 /sys/devices/pci0000:00 \
   --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 "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
   --ro-bind /usr/lib /usr/lib \
   --ro-bind /usr/lib/ /usr/lib/ \
   --ro-bind /usr/libexec/imv-wayland /usr/libexec/imv-wayland \
   --ro-bind /usr/libexec/imv-wayland /usr/libexec/imv-wayland \
   --ro-bind /usr/share/X11/xkb /usr/share/X11/xkb \
   --ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \
   --ro-bind /usr/share/fonts /usr/share/fonts \
   --ro-bind /usr/share/fonts/ /usr/share/fonts/ \
   --ro-bind /usr/share/icu /usr/share/icu \
   --ro-bind /usr/share/icu/ /usr/share/icu/ \
   --ro-bind "${@:-./}" "$(realpath "${@:-./}")" \
   --ro-bind "${1:-./}" "$(realpath "${1:-./}")" \
   /usr/libexec/imv-wayland "${@:-./}")}}
   /usr/libexec/imv-wayland "${1:-./}"}}
 
==== See what exists in the sandbox ====


Finally test what all is allowed by replacing
Finally test what all is allowed by replacing
{{ic|/usr/libexec/imv-wayland "${@:-./}")}} with {{ic|/bin/sh}} and
{{Ic|/usr/libexec/imv-wayland "${1:-./}"}} with {{Ic|/bin/sh}} and
adding {{ic|--ro-bind /bin /bin \}}.  Check around and see what the
adding {{Ic|--ro-bind /bin/ /bin/ \}}.  Check around and see what the
filesystem is like:
filesystem is like:


{{Cat|~/.local/bin/bwrap-imv|...
{{Cat|~/.local/bin/bwrap-imv| ...
   --ro-bind "${@:-./}" "$(realpath "${@:-./}")" \
   --ro-bind "${1:-./}" "$(realpath "${1:-./}")" \
   --ro-bind /bin /bin \
   --ro-bind /bin/ /bin/ \
   /bin/sh)}}
   /bin/sh}}


Invoke {{ic|bwrap-imv}}:
Invoke {{Ic|bwrap-imv}}:


{{Cmd|$ bwrap-imv}}
{{Cmd|$ bwrap-imv IMAGE}}


Show what environment variables are active:
Show what environment variables are active:
Line 338: Line 402:
... usr}}
... usr}}


{{ic|exit}} when done:
{{Ic|exit}} when done:


{{Cmd|$ exit}}
{{Cmd|$ exit}}
Line 344: Line 408:
Do not forget to change it back:
Do not forget to change it back:


{{Cat|~/.local/bin/bwrap-imv|...
{{Cat|~/.local/bin/bwrap-imv| ...
   --ro-bind "${@:-./}" "$(realpath "${@:-./}")" \
   --ro-bind "${1:-./}" "$(realpath "${1:-./}")" \
   /usr/libexec/imv-wayland "${@:-./}")}}
   /usr/libexec/imv-wayland "${1:-./}"}}


All done with a basic bubblewrap wrapper.
All done with a basic {{Ic|bwrap}} wrapper.


=== Seccomp ===
=== Seccomp ===


{{Expand|}}
{{Expand|}}
=== Limiting shared objects ===
Earlier we didn't care about limiting the shared objects but now we do.
In the spirit of
[https://en.wikipedia.org/wiki/Principle_of_least_privilege Principle of least privilege],
what is not needed should not exist.  Use the output of
{{ic|$ ldd /usr/libexec/imv-wayland}} to the find necessary libs.
{{Cat|~/.local/bin/bwrap-imv|...
  --ro-bind /etc/fonts /etc/fonts \
  --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 "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
  --ro-bind /usr/lib/libEGL.so.1 /usr/lib/libEGL.so.1 \
  --ro-bind /usr/lib/libGL.so.1 /usr/lib/libGL.so.1 \
  --ro-bind /usr/lib/libX11-xcb.so.1 /usr/lib/libX11-xcb.so.1 \
  --ro-bind /usr/lib/libX11.so.6 /usr/lib/libX11.so.6 \
  --ro-bind /usr/lib/libXau.so.6 /usr/lib/libXau.so.6 \
  --ro-bind /usr/lib/libXdmcp.so.6 /usr/lib/libXdmcp.so.6 \
  --ro-bind /usr/lib/libXext.so.6 /usr/lib/libXext.so.6 \
  --ro-bind /usr/lib/libXfixes.so.3 /usr/lib/libXfixes.so.3 \
  --ro-bind /usr/lib/libXrender.so.1 /usr/lib/libXrender.so.1 \
  --ro-bind /usr/lib/libXxf86vm.so.1 /usr/lib/libXxf86vm.so.1 \
  --ro-bind /usr/lib/libbrotlicommon.so.1 /usr/lib/libbrotlicommon.so.1 \
  --ro-bind /usr/lib/libbrotlidec.so.1 /usr/lib/libbrotlidec.so.1 \
  --ro-bind /usr/lib/libbsd.so.0 /usr/lib/libbsd.so.0 \
  --ro-bind /usr/lib/libbz2.so.1 /usr/lib/libbz2.so.1 \
  --ro-bind /usr/lib/libcairo-gobject.so.2 /usr/lib/libcairo-gobject.so.2 \
  --ro-bind /usr/lib/libcairo.so.2 /usr/lib/libcairo.so.2 \
  --ro-bind /usr/lib/libdrm.so.2 /usr/lib/libdrm.so.2 \
  --ro-bind /usr/lib/libexpat.so.1 /usr/lib/libexpat.so.1 \
  --ro-bind /usr/lib/libffi.so.8 /usr/lib/libffi.so.8 \
  --ro-bind /usr/lib/libfontconfig.so.1 /usr/lib/libfontconfig.so.1 \
  --ro-bind /usr/lib/libfreeimage.so.3 /usr/lib/libfreeimage.so.3 \
  --ro-bind /usr/lib/libfreetype.so.6 /usr/lib/libfreetype.so.6 \
  --ro-bind /usr/lib/libfribidi.so.0 /usr/lib/libfribidi.so.0 \
  --ro-bind /usr/lib/libgbm.so.1 /usr/lib/libgbm.so.1 \
  --ro-bind /usr/lib/libgcc_s.so.1 /usr/lib/libgcc_s.so.1 \
  --ro-bind /usr/lib/libgdk_pixbuf-2.0.so.0 /usr/lib/libgdk_pixbuf-2.0.so.0 \
  --ro-bind /usr/lib/libgio-2.0.so.0 /usr/lib/libgio-2.0.so.0 \
  --ro-bind /usr/lib/libglapi.so.0 /usr/lib/libglapi.so.0 \
  --ro-bind /usr/lib/libglib-2.0.so.0 /usr/lib/libglib-2.0.so.0 \
  --ro-bind /usr/lib/libgmodule-2.0.so.0 /usr/lib/libgmodule-2.0.so.0 \
  --ro-bind /usr/lib/libgobject-2.0.so.0 /usr/lib/libgobject-2.0.so.0 \
  --ro-bind /usr/lib/libgraphite2.so.3 /usr/lib/libgraphite2.so.3 \
  --ro-bind /usr/lib/libharfbuzz.so.0 /usr/lib/libharfbuzz.so.0 \
  --ro-bind /usr/lib/libicudata.so.72 /usr/lib/libicudata.so.72 \
  --ro-bind /usr/lib/libicuuc.so.72 /usr/lib/libicuuc.so.72 \
  --ro-bind /usr/lib/libinih.so.0 /usr/lib/libinih.so.0 \
  --ro-bind /usr/lib/libintl.so.8 /usr/lib/libintl.so.8 \
  --ro-bind /usr/lib/libjpeg.so.8 /usr/lib/libjpeg.so.8 \
  --ro-bind /usr/lib/liblzma.so.5 /usr/lib/liblzma.so.5 \
  --ro-bind /usr/lib/libmd.so.0 /usr/lib/libmd.so.0 \
  --ro-bind /usr/lib/libpango-1.0.so.0 /usr/lib/libpango-1.0.so.0 \
  --ro-bind /usr/lib/libpangocairo-1.0.so.0 /usr/lib/libpangocairo-1.0.so.0 \
  --ro-bind /usr/lib/libpangoft2-1.0.so.0 /usr/lib/libpangoft2-1.0.so.0 \
  --ro-bind /usr/lib/libpcre2-8.so.0 /usr/lib/libpcre2-8.so.0 \
  --ro-bind /usr/lib/libpixman-1.so.0 /usr/lib/libpixman-1.so.0 \
  --ro-bind /usr/lib/libpng16.so.16 /usr/lib/libpng16.so.16 \
  --ro-bind /usr/lib/librsvg-2.so.2 /usr/lib/librsvg-2.so.2 \
  --ro-bind /usr/lib/libstdc++.so.6 /usr/lib/libstdc++.so.6 \
  --ro-bind /usr/lib/libwayland-client.so.0 /usr/lib/libwayland-client.so.0 \
  --ro-bind /usr/lib/libwayland-egl.so.1 /usr/lib/libwayland-egl.so.1 \
  --ro-bind /usr/lib/libwayland-server.so.0 /usr/lib/libwayland-server.so.0 \
  --ro-bind /usr/lib/libxcb-dri2.so.0 /usr/lib/libxcb-dri2.so.0 \
  --ro-bind /usr/lib/libxcb-dri3.so.0 /usr/lib/libxcb-dri3.so.0 \
  --ro-bind /usr/lib/libxcb-glx.so.0 /usr/lib/libxcb-glx.so.0 \
  --ro-bind /usr/lib/libxcb-present.so.0 /usr/lib/libxcb-present.so.0 \
  --ro-bind /usr/lib/libxcb-randr.so.0 /usr/lib/libxcb-randr.so.0 \
  --ro-bind /usr/lib/libxcb-render.so.0 /usr/lib/libxcb-render.so.0 \
  --ro-bind /usr/lib/libxcb-shm.so.0 /usr/lib/libxcb-shm.so.0 \
  --ro-bind /usr/lib/libxcb-sync.so.1 /usr/lib/libxcb-sync.so.1 \
  --ro-bind /usr/lib/libxcb-xfixes.so.0 /usr/lib/libxcb-xfixes.so.0 \
  --ro-bind /usr/lib/libxcb.so.1 /usr/lib/libxcb.so.1 \
  --ro-bind /usr/lib/libxkbcommon.so.0 /usr/lib/libxkbcommon.so.0 \
  --ro-bind /usr/lib/libxml2.so.2 /usr/lib/libxml2.so.2 \
  --ro-bind /usr/lib/libxshmfence.so.1 /usr/lib/libxshmfence.so.1 \
  --ro-bind /usr/libexec/imv-wayland /usr/libexec/imv-wayland \
...}}
Running that, {{ic|$ bwrap-imv IMAGE}}, we see an error:
lebEGL warning.../usr/lib/xorg/modules/dri/crocus_dri.so
lebEGL warning.../usr/lib/xorg/modules/dri/swrast_dri.so
Running {{ic|ldd}} on both and see they both have the same
shared objects.  Insert them in the above, will look like:
{{Cat|~/.local/bin/bwrap-imv|...
  --ro-bind "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" \
  --ro-bind /usr/lib/libEGL.so.1 /usr/lib/libEGL.so.1 \
  --ro-bind /usr/lib/libGL.so.1 /usr/lib/libGL.so.1 \
  --ro-bind /usr/lib/libLLVM-15.so /usr/lib/libLLVM-15.so \
  --ro-bind /usr/lib/libX11-xcb.so.1 /usr/lib/libX11-xcb.so.1 \
  --ro-bind /usr/lib/libX11.so.6 /usr/lib/libX11.so.6 \
  --ro-bind /usr/lib/libXau.so.6 /usr/lib/libXau.so.6 \
  --ro-bind /usr/lib/libXdmcp.so.6 /usr/lib/libXdmcp.so.6 \
  --ro-bind /usr/lib/libXext.so.6 /usr/lib/libXext.so.6 \
  --ro-bind /usr/lib/libXfixes.so.3 /usr/lib/libXfixes.so.3 \
  --ro-bind /usr/lib/libXrender.so.1 /usr/lib/libXrender.so.1 \
  --ro-bind /usr/lib/libXxf86vm.so.1 /usr/lib/libXxf86vm.so.1 \
  --ro-bind /usr/lib/libbrotlicommon.so.1 /usr/lib/libbrotlicommon.so.1 \
  --ro-bind /usr/lib/libbrotlidec.so.1 /usr/lib/libbrotlidec.so.1 \
  --ro-bind /usr/lib/libbsd.so.0 /usr/lib/libbsd.so.0 \
  --ro-bind /usr/lib/libbz2.so.1 /usr/lib/libbz2.so.1 \
  --ro-bind /usr/lib/libcairo-gobject.so.2 /usr/lib/libcairo-gobject.so.2 \
  --ro-bind /usr/lib/libcairo.so.2 /usr/lib/libcairo.so.2 \
  --ro-bind /usr/lib/libdrm.so.2 /usr/lib/libdrm.so.2 \
  --ro-bind /usr/lib/libdrm_amdgpu.so.1 /usr/lib/libdrm_amdgpu.so.1 \
  --ro-bind /usr/lib/libdrm_intel.so.1 /usr/lib/libdrm_intel.so.1 \
  --ro-bind /usr/lib/libdrm_nouveau.so.2 /usr/lib/libdrm_nouveau.so.2 \
  --ro-bind /usr/lib/libdrm_radeon.so.1 /usr/lib/libdrm_radeon.so.1 \
  --ro-bind /usr/lib/libelf.so.1 /usr/lib/libelf.so.1 \
  --ro-bind /usr/lib/libexpat.so.1 /usr/lib/libexpat.so.1 \
  --ro-bind /usr/lib/libffi.so.8 /usr/lib/libffi.so.8 \
  --ro-bind /usr/lib/libfontconfig.so.1 /usr/lib/libfontconfig.so.1 \
  --ro-bind /usr/lib/libfreeimage.so.3 /usr/lib/libfreeimage.so.3 \
  --ro-bind /usr/lib/libfreetype.so.6 /usr/lib/libfreetype.so.6 \
  --ro-bind /usr/lib/libfribidi.so.0 /usr/lib/libfribidi.so.0 \
  --ro-bind /usr/lib/libgbm.so.1 /usr/lib/libgbm.so.1 \
  --ro-bind /usr/lib/libgcc_s.so.1 /usr/lib/libgcc_s.so.1 \
  --ro-bind /usr/lib/libgdk_pixbuf-2.0.so.0 /usr/lib/libgdk_pixbuf-2.0.so.0 \
  --ro-bind /usr/lib/libgio-2.0.so.0 /usr/lib/libgio-2.0.so.0 \
  --ro-bind /usr/lib/libglapi.so.0 /usr/lib/libglapi.so.0 \
  --ro-bind /usr/lib/libglib-2.0.so.0 /usr/lib/libglib-2.0.so.0 \
  --ro-bind /usr/lib/libgmodule-2.0.so.0 /usr/lib/libgmodule-2.0.so.0 \
  --ro-bind /usr/lib/libgobject-2.0.so.0 /usr/lib/libgobject-2.0.so.0 \
  --ro-bind /usr/lib/libgraphite2.so.3 /usr/lib/libgraphite2.so.3 \
  --ro-bind /usr/lib/libharfbuzz.so.0 /usr/lib/libharfbuzz.so.0 \
  --ro-bind /usr/lib/libicudata.so.72 /usr/lib/libicudata.so.72 \
  --ro-bind /usr/lib/libicuuc.so.72 /usr/lib/libicuuc.so.72 \
  --ro-bind /usr/lib/libinih.so.0 /usr/lib/libinih.so.0 \
  --ro-bind /usr/lib/libintl.so.8 /usr/lib/libintl.so.8 \
  --ro-bind /usr/lib/libjpeg.so.8 /usr/lib/libjpeg.so.8 \
  --ro-bind /usr/lib/liblzma.so.5 /usr/lib/liblzma.so.5 \
  --ro-bind /usr/lib/libmd.so.0 /usr/lib/libmd.so.0 \
  --ro-bind /usr/lib/libpango-1.0.so.0 /usr/lib/libpango-1.0.so.0 \
  --ro-bind /usr/lib/libpangocairo-1.0.so.0 /usr/lib/libpangocairo-1.0.so.0 \
  --ro-bind /usr/lib/libpangoft2-1.0.so.0 /usr/lib/libpangoft2-1.0.so.0 \
  --ro-bind /usr/lib/libpciaccess.so.0 /usr/lib/libpciaccess.so.0 \
  --ro-bind /usr/lib/libpcre2-8.so.0 /usr/lib/libpcre2-8.so.0 \
  --ro-bind /usr/lib/libpixman-1.so.0 /usr/lib/libpixman-1.so.0 \
  --ro-bind /usr/lib/libpng16.so.16 /usr/lib/libpng16.so.16 \
  --ro-bind /usr/lib/librsvg-2.so.2 /usr/lib/librsvg-2.so.2 \
  --ro-bind /usr/lib/libstdc++.so.6 /usr/lib/libstdc++.so.6 \
  --ro-bind /usr/lib/libwayland-client.so.0 /usr/lib/libwayland-client.so.0 \
  --ro-bind /usr/lib/libwayland-egl.so.1 /usr/lib/libwayland-egl.so.1 \
  --ro-bind /usr/lib/libwayland-server.so.0 /usr/lib/libwayland-server.so.0 \
  --ro-bind /usr/lib/libxcb-dri2.so.0 /usr/lib/libxcb-dri2.so.0 \
  --ro-bind /usr/lib/libxcb-dri3.so.0 /usr/lib/libxcb-dri3.so.0 \
  --ro-bind /usr/lib/libxcb-glx.so.0 /usr/lib/libxcb-glx.so.0 \
  --ro-bind /usr/lib/libxcb-present.so.0 /usr/lib/libxcb-present.so.0 \
  --ro-bind /usr/lib/libxcb-randr.so.0 /usr/lib/libxcb-randr.so.0 \
  --ro-bind /usr/lib/libxcb-render.so.0 /usr/lib/libxcb-render.so.0 \
  --ro-bind /usr/lib/libxcb-shm.so.0 /usr/lib/libxcb-shm.so.0 \
  --ro-bind /usr/lib/libxcb-sync.so.1 /usr/lib/libxcb-sync.so.1 \
  --ro-bind /usr/lib/libxcb-xfixes.so.0 /usr/lib/libxcb-xfixes.so.0 \
  --ro-bind /usr/lib/libxcb.so.1 /usr/lib/libxcb.so.1 \
  --ro-bind /usr/lib/libxkbcommon.so.0 /usr/lib/libxkbcommon.so.0 \
  --ro-bind /usr/lib/libxml2.so.2 /usr/lib/libxml2.so.2 \
  --ro-bind /usr/lib/libxshmfence.so.1 /usr/lib/libxshmfence.so.1 \
  --ro-bind /usr/lib/libzstd.so.1 /usr/lib/libzstd.so.1 \
  --ro-bind /usr/lib/xorg/modules/dri/crocus_dri.so /usr/lib/xorg/modules/dri/crocus_dri.so \
  --ro-bind /usr/lib/xorg/modules/dri/swrast_dri.so /usr/lib/xorg/modules/dri/swrast_dri.so \
  --ro-bind /usr/libexec/imv-wayland /usr/libexec/imv-wayland \
...}}
Now it should work as before.


== .desktop integration ==
== .desktop integration ==


{{Obsolete|This should probably be documented in [[Default_applications]] and linked here.  Nothing is unique in using with {{ic|bwrap}}.}}
{{Obsolete|This should probably be documented in [[Default_applications]] and linked here.  Nothing is unique in using with {{Ic|bwrap}}.}}


{{Note|This section is also using {{Pkg|imv}} as the example.}}
{{Note|This section is also using {{Pkg|imv|arch=}} as the example.}}


[https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html XDG Desktop Entry Specification]
[https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html XDG Desktop Entry Specification]
Line 537: Line 428:
launched, how it appears in menus, etc.
launched, how it appears in menus, etc.


The default ''.desktop'' file for {{ic|imv}} is at
The default ''.desktop'' file for {{Ic|imv}} is at
{{Path|/usr/share/applications/imv.desktop}}.  Move it to
{{Path|/usr/share/applications/imv.desktop}}.  Move it to
{{Path|"${XDG_DATA_HOME}"/applications/bwrap-imv.desktop}}.
{{Path|"${XDG_DATA_HOME}/applications/bwrap-imv.desktop"}}.


Only 3 options will need to be changed: Name/Name[en_US], what shows up
Only 3 options will need to be changed: Name/Name[en_US], what shows up
Line 545: Line 436:
installed); Exec, program to execute:
installed); Exec, program to execute:


{{Cat|"${XDG_DATA_HOME}"/applications/bwrap-imv.desktop|...<nowiki>
{{Cat|"${XDG_DATA_HOME}/applications/bwrap-imv.desktop"|...<nowiki>
Name=bwrap-imv
Name=bwrap-imv
Name[en_US]=bwrap-imv
Name[en_US]=bwrap-imv
Line 551: Line 442:
</nowiki>...}}
</nowiki>...}}


The program {{ic|xdg-open}} (from the {{Pkg|xdg-utils}} package) can be
The program {{Ic|xdg-open}} (from the {{Pkg|xdg-utils|arch=}} package) can be
used to open files based on the [https://en.wikipedia.org/wiki/MIME MIME]
used to open files based on the [https://en.wikipedia.org/wiki/MIME MIME]
type + corresponding entry in {{Path|$"{XDG_CONFIG_HOME}"/mimeapps.list}} and
type + corresponding entry in
{{Path|"${XDG_DATA_HOME}"/applications/mimeinfo.cache}}.
{{Path|"${XDG_CONFIG_HOME}/mimeapps.list"}} and
{{Path|"${XDG_DATA_HOME}/applications/mimeinfo.cache"}}.


Install {{Pkg|desktop-file-utils}} if it is not installed already, it
Install {{Pkg|desktop-file-utils|arch=}} if it is not installed already, it
comes with two commands that are needed {{ic|desktop-file-validate}} and
comes with two commands that are needed {{Ic|desktop-file-validate}} and
{{ic|update-desktop-database}}:
{{Ic|update-desktop-database}}:


{{Cmd|# apk add desktop-file-utils}}
{{Cmd|# apk add desktop-file-utils}}
Line 564: Line 456:
=== Validate ===
=== Validate ===


It is a good idea to validate {{ic|imv.desktop}} using
It is a good idea to validate {{Ic|imv.desktop}} using
{{ic|desktop-file-validate}}:
{{Ic|desktop-file-validate}}:


{{Cmd|$ desktop-file-validate "${XDG_DATA_HOME}"/applications/bwrap-imv.desktop}}
{{Cmd|$ desktop-file-validate "${XDG_DATA_HOME}/applications/bwrap-imv.desktop"}}


=== Update database ===
=== Update database ===


This will make entries in {{Path|"${XDG_DATA_HOME}"/applications/}} take
This will make entries in {{Path|"${XDG_DATA_HOME}/applications/"}} take
precedence over system-wide files ({{Path|/usr/share/applications/}}).
precedence over system-wide files ({{Path|/usr/share/applications/}}).
However {{Path|"${XDG_CONFIG_HOME}"/mimeapps.list}} has precedence over
However {{Path|"${XDG_CONFIG_HOME}/mimeapps.list"}} has precedence over
both.
both.


Updating the database, will create
Updating the database, will create
{{Path|"${XDG_DATA_HOME}"/applications/mimeinfo.cache}}:
{{Path|"${XDG_DATA_HOME}/applications/mimeinfo.cache"}}:


{{Cmd|$ update-desktop-database "${XDG_DATA_HOME}"/applications}}
{{Cmd|$ update-desktop-database "${XDG_DATA_HOME}/applications"}}


== Troubleshooting ==
== Troubleshooting ==
Line 586: Line 478:


If all else fails start broad and work toward narrowing.  See if
If all else fails start broad and work toward narrowing.  See if
{{ic|bwrap}} works with the program at all:
{{Ic|bwrap}} works with the program at all:


{{Cmd|$ bwrap \
{{Cmd|$ bwrap \
Line 594: Line 486:


{{Cmd|$ bwrap \
{{Cmd|$ bwrap \
   --ro-bind /bin /bin \
   --ro-bind /bin/ /bin/ \
   --dev-bind /dev /dev \
   --dev-bind /dev/ /dev/ \
   --ro-bind /lib /lib \
   --ro-bind /lib/ /lib/ \
   --ro-bind /sys /sys \
   --ro-bind /sys/ /sys/ \
   --ro-bind /usr /usr \
   --ro-bind /usr/ /usr/ \
   PROGRAM}}
   PROGRAM}}



Latest revision as of 02:45, 5 June 2024

This material is work-in-progress ...

The reasoning is most likely wrong for why to do some stuff. Someone more experienced needs to look it over.
(Last edited by Encode on 5 Jun 2024.)

Bubblewrap is an unprivileged sandboxing tool. Kernel features it also has: User/IPC/PID/Network/UTS/cgroup namespaces and Seccomp filters.

How bubblewrap works, as stated in the README.md:

bubblewrap works by creating a new, completely empty, mount namespace where the root is on a tmpfs that is invisible from the host, and will be automatically cleaned up when the last process exits. You can then use commandline options to construct the root filesystem and process environment and command to run in the namespace.

Installation

Install bubblewrap:

# apk add bubblewrap

Note: The package is bubblewrap but the command to manage it is bwrap.

How to workout what a program needs

Tip: Look at Bubblewrap/Examples to see various ways bwrap can be used.

Prerequisites

First make sure to have a user editable directory in "$PATH". This page will use "${HOME}/.local/bin/", create it if it does not exist:

$ mkdir -p ~/.local/bin

Add it to ~/.profile:

Contents of ~/.profile

... PATH="${PATH}":"${HOME}/.local/bin" export PATH ...

Will need to relog for this to apply.

Basic bwrap setup

Note: With how we will be sandboxing everything that doesn't match our owner/group will show as nobody.

Lets assume you want to sandbox imv and are using Wayland only. Here is how you might go about that.

Create bwrap-imv inside "${HOME}/.local/bin/" and make it executable:

$ touch ~/.local/bin/bwrap-imv $ chmod 0700 ~/.local/bin/bwrap-imv

Use file to determine the file type of /usr/bin/imv:

$ file /usr/bin/imv /usr/bin/imv: POSIX shell script, ASCII text executable

Since it is just a shell script, we can use less to view it:

$ less /usr/bin/imv

Contents of /usr/bin/imv

#!/bin/sh if [ -n "${WAYLAND_DISPLAY}" ]; then exec /usr/libexec/imv-wayland "$@" else exec /usr/libexec/imv-x11 "$@" fi

Since we are assuming Wayland only we can just skip to /usr/libexec/imv-wayland. Run file on it:

$ file /usr/libexec/imv-wayland /usr/libexec/imv-wayland: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, stripped

It is an Executable and Linkable Format (ELF) file. So we know we need the ELF interpreter /lib/ld-musl-x86_64.so.1. We also know we need /usr/libexec/imv-wayland, since it has to know where the command is located.

As the argument to /usr/libexec/imv-wayland, put "${1:-./}", this will pass only the first argument and if there is none, will default to ./, the current directory. We will also need --ro-bind "${1:-./}" "$(realpath "${1:-./}")" \, since we are not passing the whole filesystem. This will get the absolute pathname using realpath, so you can pass a relative argument and still bind the argument:

--ro-bind "${1:-./}" "$(realpath "${1:-./}")" \
/usr/libexec/imv-wayland "${1:-./}"
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.


Todo: How can you pass 2+ arguments?


Find necessary shared libraries, except ones loaded at runtime:

$ ldd /usr/libexec/imv-wayland

It outputs a lot of things but we only need a few; the directory path of the majority /usr/lib/* and the 4 paths that start with /lib/*. Filter the output to see those clearer:

$ ldd /usr/libexec/imv-wayland | grep ' /lib/'

In total:

--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 /usr/lib/ /usr/lib/ \
Note: It is not worth the time to limit /usr/lib/*, the churn is too great.
Warning: The ldd manpage talks about some security implications. It may not apply since they seem to be talking about glibc and musl-utils makes /lib/ld-musl-x86_64.so.1 ldd [1]. Is this something to worry about?


Since this is a shell script, lets use a helpful command:

set -u

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

Since this is for a GUI Wayland program, so lets also add some prerequisites:

Note: Make sure you have dealt with XDG_RUNTIME_DIR.
--setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \

for determining the directory for the wayland socket;

--setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \

for determining the socket;

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

mount readonly.

Lets also add some nice to haves:

--unshare-all \

will create a new user/ipc/pid/net/utc namespaces and try to create a new cgroup namespace if possible;

--new-session

will create a new terminal session for the sandbox, disconnecting from the controlling terminal so for example it can't inject input into the terminal;

 --die-with-parent

will ensure child process (imv-wayland in this case) dies when bwrap parent dies.

We might also have a config file:

--ro-bind-try "${XDG_CONFIG_HOME}/imv/config" "${XDG_CONFIG_HOME}/imv/config" \

this will add your local config to imv if you have one and if not will still continue.

Pass "$XDG_CONFIG_HOME" to sandbox:

--setenv XDG_CONFIG_HOME "$XDG_CONFIG_HOME" \

but this isn't always defined, so lets fallback to the XDG Base Directory default:

XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"

this will use "$XDG_CONFIG_HOME" if it's set, otherwise fallback to the default of "$HOME/.config".

--ro-bind /bin/sh /bin/sh \

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

Todo: This was found using: Bubblewrap#Can't_find_what_path_is_missing, any better way?


~/.local/bin/bwrap-imv now looks like:

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 \ --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 \ --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 "${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 "${1:-./}" "$(realpath "${1:-./}")" \ /usr/libexec/imv-wayland "${1:-./}"

Now lets run bwrap-imv, go into a directory with an image:

$ bwrap-imv IMAGE sh: eval: line 0: can't create /dev/null: nonexistent directory ... sh: eval: line 0: can't create /dev/null: nonexistent directory xkbcommon: ERROR: failed to add default include path /usr/share/X11/xkb Assertion failed: keyboard->context (../src/keyboard.c: imv_keyboard_create: 20)

Add:

 --ro-bind /usr/share/X11/xkb/ /usr/share/X11/xkb/ \

to bwrap-imv. XKB is a keyboard keymap support library.

After adding the above, run it again:

$ bwrap-imv IMAGE sh: eval: line 0: can't create /dev/null: nonexistent directory ... sh: eval: line 0: can't create /dev/null: nonexistent directory libEGL warning: wayland-egl: could not open /dev/dri/renderD128 (No such file or directory)

Add:

--dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \

and run again:

$ bwrap-imv IMAGE libEGL warning: wayland-egl: drmGetMagic failed

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

Access to character devices.

Todo: This was found using: Bubblewrap#Can't_find_what_path_is_missing, any better way?


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

Access to PCI resources.

Todo: This was found using: Bubblewrap#Can't_find_what_path_is_missing, any better way?


--clearenv \

Finally we can unset all environment variables, except for "$PWD" and any we set with --setenv.

Now imv should show images and your config file should work (if you have one). If you do not use commands, the finished ~/.local/bin/bwrap-imv should look like:

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:-./}"

If you do use commands however, you will notice it is only showing substitute characters.

Tip: Commands in imv are entered by pressing :.

If you try to use a command it will say:

Fontconfig error: Cannot load default config file: No such file: (null)

Look at the fonts-conf manpage (which is from fontconfig-doc) we see that /etc/fonts/ is the system font configuration directory and "${XDG_CONFIG_HOME}/fontconfig/" is the per-user configuration directory. "${XDG_CONFIG_HOME}/fontconfig/" is added with --ro-bind-try so it doesn't have to exist:

--ro-bind /etc/fonts/ /etc/fonts/ \
--ro-bind-try "${XDG_CONFIG_HOME}/fontconfig/" "${XDG_CONFIG_HOME}/fontconfig/" \

The default directories scanned for font files are /usr/share/fonts/ and "${XDG_DATA_HOME}/fonts/". "${XDG_DATA_HOME}/fonts/" added with --ro-bind-try:

--ro-bind /usr/share/fonts/ /usr/share/fonts/ \
--ro-bind-try "${XDG_DATA_HOME}/fonts/" "${XDG_DATA_HOME}/fonts/" \

Pass "$XDG_DATA_HOME" to sandbox:

--setenv XDG_DATA_HOME "$XDG_DATA_HOME" \

just like for "$XDG_CONFIG_HOME", this isn't always defined, so fallback to XDG Base Directory default:

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

use "$XDG_DATA_HOME" if set, else use "$HOME/.local/share".

The user cache of font information is also needed, by default "${XDG_CACHE_HOME}/fontconfig/":

--bind-try "${XDG_CACHE_HOME}/fontconfig/" "${XDG_CACHE_HOME}/fontconfig/" \

Pass "$XDG_CACHE_HOME" to sandbox:

--setenv XDG_CACHE_HOME "$XDG_CACHE_HOME" \

just like for "$XDG_CONFIG_HOME", this isn't always defined, so fallback to XDG Base Directory default:

XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"

use "$XDG_CACHE_HOME" if set, else use "$HOME/.cache".

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

Is also needed or when you do :<backspace> it will terminate the process. ICU provides Unicode and Globalization support.

Todo: This was found using: Bubblewrap#Can't_find_what_path_is_missing, any better way?


The updated ~/.local/bin/bwrap-imv should look like this:

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

#!/bin/sh # imv wrapped in bwrap. set -u 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}" /usr/bin/bwrap \ --unshare-all \ --new-session \ --die-with-parent \ --clearenv \ --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" \ --ro-bind /bin/sh /bin/sh \ --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 /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 /usr/share/fonts/ /usr/share/fonts/ \ --ro-bind /usr/share/icu/ /usr/share/icu/ \ --ro-bind "${1:-./}" "$(realpath "${1:-./}")" \ /usr/libexec/imv-wayland "${1:-./}"

See what exists in the sandbox

Finally test what all is allowed by replacing /usr/libexec/imv-wayland "${1:-./}" with /bin/sh and adding --ro-bind /bin/ /bin/ \. Check around and see what the filesystem is like:

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

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

Invoke bwrap-imv:

$ bwrap-imv IMAGE

Show what environment variables are active:

$ printenv

See what directories are at root:

$ ls -la / ... bin ... dev ... etc ... home ... lib ... sys ... tmp ... usr

exit when done:

$ exit

Do not forget to change it back:

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

... --ro-bind "${1:-./}" "$(realpath "${1:-./}")" \ /usr/libexec/imv-wayland "${1:-./}"

All done with a basic bwrap wrapper.

Seccomp

This material needs expanding ...

.desktop integration

This material is obsolete ...

This should probably be documented in Default_applications and linked here. Nothing is unique in using with bwrap. (Discuss)

Note: This section is also using imv as the example.

XDG Desktop Entry Specification are a set of standards describing how a particular program is to be launched, how it appears in menus, etc.

The default .desktop file for imv is at /usr/share/applications/imv.desktop. Move it to "${XDG_DATA_HOME}/applications/bwrap-imv.desktop".

Only 3 options will need to be changed: Name/Name[en_US], what shows up in the application menu in a graphical file manager (if you have one installed); Exec, program to execute:

Contents of "${XDG_DATA_HOME}/applications/bwrap-imv.desktop"

... Name=bwrap-imv Name[en_US]=bwrap-imv Exec=bwrap-imv %F ...

The program xdg-open (from the xdg-utils package) can be used to open files based on the MIME type + corresponding entry in "${XDG_CONFIG_HOME}/mimeapps.list" and "${XDG_DATA_HOME}/applications/mimeinfo.cache".

Install desktop-file-utils if it is not installed already, it comes with two commands that are needed desktop-file-validate and update-desktop-database:

# apk add desktop-file-utils

Validate

It is a good idea to validate imv.desktop using desktop-file-validate:

$ desktop-file-validate "${XDG_DATA_HOME}/applications/bwrap-imv.desktop"

Update database

This will make entries in "${XDG_DATA_HOME}/applications/" take precedence over system-wide files (/usr/share/applications/). However "${XDG_CONFIG_HOME}/mimeapps.list" has precedence over both.

Updating the database, will create "${XDG_DATA_HOME}/applications/mimeinfo.cache":

$ update-desktop-database "${XDG_DATA_HOME}/applications"

Troubleshooting

Can't find what path is missing

If all else fails start broad and work toward narrowing. See if bwrap works with the program at all:

$ bwrap \ --dev-bind / / PROGRAM

If that works start to narrow:

$ bwrap \ --ro-bind /bin/ /bin/ \ --dev-bind /dev/ /dev/ \ --ro-bind /lib/ /lib/ \ --ro-bind /sys/ /sys/ \ --ro-bind /usr/ /usr/ \ PROGRAM

Keep going till you have narrowed as much as possible.

See also