Bubblewrap: Difference between revisions
m (Add fallback for "$XDG_CACHE_HOME" & "$XDG_DATA_HOME".) |
m (Use default values, instead of assign default values. Doesn't matter in this situation, but will lead to surprising results in most situations.) |
||
(6 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 {{ | {{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 | {{Tip|Look at [[Bubblewrap/Examples]] to see various ways {{Ic|bwrap}} can be used.}} | ||
=== Prerequisites === | === Prerequisites === | ||
Line 46: | Line 46: | ||
{{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. | ||
Line 60: | Line 60: | ||
/usr/bin/imv: POSIX shell script, ASCII text executable}} | /usr/bin/imv: POSIX shell script, ASCII text executable}} | ||
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 82: | 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 | is located. | ||
As the argument to {{Ic|/usr/libexec/imv-wayland}}, put | |||
{{Ic|"${1:-./}"}}, this will pass '''only''' the first argument and if | |||
there is none, will default to {{Path|./}}, the current directory. We | |||
will also need {{Ic|--ro-bind "${1:-./}" "$(realpath "${1:-./}")" \}}, | |||
since we are not passing the whole filesystem. This 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?}} | |||
Find necessary shared libraries, except ones loaded at runtime: | |||
{{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: | Since this is a shell script, lets use a helpful command: | ||
Line 99: | Line 123: | ||
few exceptions). | 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" \ | --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \ | ||
for determining the directory for the wayland socket; | for determining the directory for the wayland socket; | ||
Line 118: | Line 145: | ||
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. | ||
We might also have a {{Path|config}} file: | We might also have a {{Path|config}} file: | ||
Line 137: | Line 156: | ||
[https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html XDG Base Directory] | [https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html XDG Base Directory] | ||
default: | default: | ||
XDG_CONFIG_HOME="${XDG_CONFIG_HOME: | XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" | ||
this will use {{Path|"$XDG_CONFIG_HOME"}} if it's set, otherwise | this will use {{Path|"$XDG_CONFIG_HOME"}} if it's set, otherwise | ||
fallback to the default of {{Path|"$HOME/.config"}}. | fallback to the default of {{Path|"$HOME/.config"}}. | ||
--ro-bind /bin/sh /bin/sh \ | --ro-bind /bin/sh /bin/sh \ | ||
to | Needed to use {{Path|config}} and have various information in the window | ||
title. | |||
{{Todo| | {{Todo|This was found using: [[Bubblewrap#Can't_find_what_path_is_missing]], any better way?}} | ||
{{Path|~/.local/bin/bwrap-imv}} now looks like: | {{Path|~/.local/bin/bwrap-imv}} now looks like: | ||
{{Cat|~/.local/bin/bwrap-imv|#! | {{Cat|~/.local/bin/bwrap-imv|#!/bin/sh | ||
# imv wrapped in bwrap. | # imv wrapped in bwrap. | ||
Line 157: | Line 174: | ||
set -u | set -u | ||
XDG_CONFIG_HOME{{=}}"${XDG_CONFIG_HOME: | XDG_CONFIG_HOME{{=}}"${XDG_CONFIG_HOME:-$HOME/.config}" | ||
/usr/bin/bwrap \ | /usr/bin/bwrap \ | ||
Line 167: | Line 184: | ||
--setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \ | --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \ | ||
--ro-bind /bin/sh /bin/sh \ | --ro-bind /bin/sh /bin/sh \ | ||
--ro-bind-try "${XDG_CONFIG_HOME}/imv/config" "${XDG_CONFIG_HOME}/imv/config" \ | --ro-bind-try "${XDG_CONFIG_HOME}/imv/config" "${XDG_CONFIG_HOME}/imv/config" \ | ||
--ro-bind /lib/ /lib/ \ | --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 "${ | --ro-bind "${1:-./}" "$(realpath "${1:-./}")" \ | ||
/usr/libexec/imv-wayland "${ | /usr/libexec/imv-wayland "${1:-./}"}} | ||
Now lets run {{Ic|bwrap-imv}} | 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)}} | ||
Line 190: | 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 199: | Line 224: | ||
libEGL warning: wayland-egl: drmGetMagic failed}} | libEGL warning: wayland-egl: drmGetMagic failed}} | ||
--ro-bind /sys/dev/char/ /sys/dev/char/ \ | |||
Access to character devices. | |||
--ro-bind /sys/dev/char/ /sys/dev/char/ \}} | |||
{{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/ \ | --ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \ | ||
Access to PCI resources. | |||
{{Todo| | {{Todo|This was found using: [[Bubblewrap#Can't_find_what_path_is_missing]], any better way?}} | ||
--clearenv \ | --clearenv \ | ||
can | Finally we can unset all environment variables, except for | ||
except for {{Path|"$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|#! | {{Cat|~/.local/bin/bwrap-imv|#!/bin/sh | ||
# imv wrapped in bwrap. | # imv wrapped in bwrap. | ||
Line 221: | Line 248: | ||
set -u | set -u | ||
XDG_CONFIG_HOME{{=}}"${XDG_CONFIG_HOME: | XDG_CONFIG_HOME{{=}}"${XDG_CONFIG_HOME:-$HOME/.config}" | ||
/usr/bin/bwrap \ | /usr/bin/bwrap \ | ||
Line 233: | Line 260: | ||
--ro-bind /bin/sh /bin/sh \ | --ro-bind /bin/sh /bin/sh \ | ||
--dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \ | --dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \ | ||
--ro-bind-try "${XDG_CONFIG_HOME}/imv/config" "${XDG_CONFIG_HOME}/imv/config" \ | --ro-bind-try "${XDG_CONFIG_HOME}/imv/config" "${XDG_CONFIG_HOME}/imv/config" \ | ||
--ro-bind /lib/ /lib/ \ | --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/dev/char/ /sys/dev/char/ \ | ||
--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \ | --ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \ | ||
Line 242: | Line 271: | ||
--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 "${ | --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}} | {{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 255: | Line 284: | ||
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. | 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/ \ | ||
Line 264: | Line 293: | ||
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/"}}. | {{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/" \ | ||
Pass {{Path|"$XDG_DATA_HOME"}} to sandbox: | Pass {{Path|"$XDG_DATA_HOME"}} to sandbox: | ||
--setenv XDG_DATA_HOME "$XDG_DATA_HOME" \ | --setenv XDG_DATA_HOME "$XDG_DATA_HOME" \ | ||
Line 274: | Line 304: | ||
[https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html XDG Base Directory] | [https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html XDG Base Directory] | ||
default: | default: | ||
XDG_DATA_HOME="${XDG_DATA_HOME: | XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}" | ||
use {{Path|"$XDG_DATA_HOME"}} if set, else use {{Path|"$HOME/.local/share"}}. | use {{Path|"$XDG_DATA_HOME"}} if set, else use {{Path|"$HOME/.local/share"}}. | ||
Line 280: | Line 310: | ||
{{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/" \ | ||
Pass {{Path|"$XDG_CACHE_HOME"}} to sandbox: | 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 | just like for {{Path|"$XDG_CONFIG_HOME"}}, this isn't always defined, so | ||
fallback to | fallback to | ||
[https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html XDG Base Directory] | [https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html XDG Base Directory] | ||
default: | default: | ||
XDG_CACHE_HOME="${XDG_CACHE_HOME: | XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}" | ||
use {{Path|"$XDG_CACHE_HOME"}} if set, else use {{Path|"$HOME/.cache"}}. | use {{Path|"$XDG_CACHE_HOME"}} if set, else use {{Path|"$HOME/.cache"}}. | ||
Line 296: | Line 324: | ||
process. ICU provides Unicode and Globalization support. | process. ICU provides Unicode and Globalization support. | ||
{{Todo|This was found | {{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|#! | {{Cat|~/.local/bin/bwrap-imv|#!/bin/sh | ||
# imv wrapped in bwrap. | # imv wrapped in bwrap. | ||
Line 306: | Line 334: | ||
set -u | set -u | ||
XDG_CACHE_HOME{{=}}"${XDG_CACHE_HOME: | XDG_CACHE_HOME{{=}}"${XDG_CACHE_HOME:-$HOME/.cache}" | ||
XDG_CONFIG_HOME{{=}}"${XDG_CONFIG_HOME: | XDG_CONFIG_HOME{{=}}"${XDG_CONFIG_HOME:-$HOME/.config}" | ||
XDG_DATA_HOME{{=}}"${XDG_DATA_HOME: | XDG_DATA_HOME{{=}}"${XDG_DATA_HOME:-$HOME/.local/share}" | ||
/usr/bin/bwrap \ | /usr/bin/bwrap \ | ||
Line 322: | Line 350: | ||
--ro-bind /bin/sh /bin/sh \ | --ro-bind /bin/sh /bin/sh \ | ||
--dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \ | --dev-bind /dev/dri/renderD128 /dev/dri/renderD128 \ | ||
-- | --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/config" "${XDG_CONFIG_HOME}/imv/config" \ | --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 / | --ro-bind /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 \ | ||
--ro-bind /lib/ /lib/ \ | --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/dev/char/ /sys/dev/char/ \ | ||
--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \ | --ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \ | ||
Line 337: | Line 367: | ||
--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 "${ | --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 "${ | {{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 "${ | --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 377: | Line 409: | ||
{{Cat|~/.local/bin/bwrap-imv| ... | {{Cat|~/.local/bin/bwrap-imv| ... | ||
--ro-bind "${ | --ro-bind "${1:-./}" "$(realpath "${1:-./}")" \ | ||
/usr/libexec/imv-wayland "${ | /usr/libexec/imv-wayland "${1:-./}"}} | ||
All done with a basic | All done with a basic {{Ic|bwrap}} wrapper. | ||
=== Seccomp === | === Seccomp === | ||
Line 390: | Line 422: | ||
{{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 410: | 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 | type + corresponding entry in | ||
Line 416: | Line 448: | ||
{{Path|"${XDG_DATA_HOME}/applications/mimeinfo.cache"}}. | {{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}}: |
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. |
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
bwrap
.How to workout what a program needs
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
Will need to relog for this to apply.
Basic bwrap setup
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
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:-./}"
imv
, recursively.
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/ \
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:
--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.
~/.local/bin/bwrap-imv now looks like:
Contents of ~/.local/bin/bwrap-imv
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.
--ro-bind /sys/devices/pci0000:00/ /sys/devices/pci0000:00/ \
Access to PCI resources.
--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
If you do use commands however, you will notice it is only showing substitute characters.
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.
The updated ~/.local/bin/bwrap-imv should look like this:
Contents of ~/.local/bin/bwrap-imv
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
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
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 |
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"
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.