Bubblewrap

来自高山Linux
此材料正在进行中...

对于为什么要进行某些操作,推理很可能是不正确的。需要更有经验的人来检查一下。
(最后编辑者 Encode 于 2024 年 6 月 5 日。)

Bubblewrap 是一个非特权沙箱工具。内核特性也包括:用户/IPC/PID/网络/UTS/cgroup 命名空间Seccomp 过滤器。

Bubblewrap 的工作原理,如 README.md 中所述

bubblewrap 的工作原理是创建一个新的、完全空的挂载命名空间,其中根目录位于 tmpfs 上,该 tmpfs 对主机不可见,并且将在最后一个进程退出时自动清理。然后,您可以使用命令行选项来构建根文件系统和进程环境,以及在命名空间中运行的命令。

安装

安装 bubblewrap

# apk add bubblewrap

注意: 软件包是 bubblewrap,但管理它的命令是 bwrap

如何确定程序需要什么

提示: 查看 Bubblewrap/Examples 以了解 bwrap 的各种使用方法。

前提条件

首先确保在 "$PATH" 中有一个用户可编辑的目录。此页面将使用 "${HOME}/.local/bin/",如果它不存在,则创建它

$ mkdir -p ~/.local/bin

将其添加到 ~/.profile

内容为 ~/.profile

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

需要重新登录才能应用。

基础 bwrap 设置

注意: 由于我们将对所有不匹配我们所有者/组的内容进行沙箱化,因此将显示为 nobody

假设您要沙箱化 imv 并且仅使用 Wayland。以下是您可能执行的操作。

"${HOME}/.local/bin/" 中创建 bwrap-imv 并使其可执行

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

使用 file 确定 /usr/bin/imv 的文件类型

$ file /usr/bin/imv /usr/bin/imv: POSIX shell 脚本,ASCII 文本可执行文件

由于它只是一个 shell 脚本,我们可以使用 less 查看它

$ less /usr/bin/imv

内容为 /usr/bin/imv

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

由于我们假设仅 Wayland,我们可以跳到 /usr/libexec/imv-wayland。在其上运行 file

$ file /usr/libexec/imv-wayland /usr/libexec/imv-wayland: ELF 64 位 LSB pie 可执行文件,x86-64,版本 1 (SYSV),动态链接,解释器 /lib/ld-musl-x86_64.so.1,已剥离

它是一个 可执行和可链接格式 (ELF) 文件。所以我们知道我们需要 ELF 解释器 /lib/ld-musl-x86_64.so.1。我们也知道我们需要 /usr/libexec/imv-wayland,因为它必须知道命令的位置。

作为 /usr/libexec/imv-wayland 的参数,放置 "${1:-./}",这将只传递第一个参数,如果没有参数,将默认为 ./,当前目录。我们还需要 --ro-bind "${1:-./}" "$(realpath "${1:-./}")" \,因为我们没有传递整个文件系统。这将使用 realpath 获取绝对路径名,因此您可以传递相对参数并仍然绑定参数

--ro-bind "${1:-./}" "$(realpath "${1:-./}")" \
/usr/libexec/imv-wayland "${1:-./}"
警告: 如果您不传递任何内容,并且它默认为当前目录,它将使 imv 显示该目录下的所有内容,递归地。


待办事项: 如何传递 2+ 个参数?


查找必要的共享库,除了运行时加载的那些

$ ldd /usr/libexec/imv-wayland

它输出很多内容,但我们只需要几个;大部分的目录路径 /usr/lib/* 和以 /lib/* 开头的 4 个路径。过滤输出以更清楚地查看这些

$ ldd /usr/libexec/imv-wayland | grep ' /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 /usr/lib/ /usr/lib/ \
注意: 限制 /usr/lib/* 不值得花费时间,变动太大了。
警告: ldd 手册页谈到了一些安全隐患。这可能不适用,因为他们似乎在谈论 glibc 和 musl-utils 使 /lib/ld-musl-x86_64.so.1 ldd [1]。这是有什么好担心的吗?


由于这是一个 shell 脚本,让我们使用一个有用的命令

set -u

如果 shell 尝试扩展未设置的参数,它将报错(少数例外)。

由于这是用于 GUI Wayland 程序,所以让我们也添加一些前提条件

注意: 确保您已处理 XDG_RUNTIME_DIR
--setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \

用于确定 wayland 套接字的目录;

--setenv WAYLAND_DISPLAY "$WAYLAND_DISPLAY" \

用于确定套接字;

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

只读挂载。

让我们也添加一些锦上添花的功能

--unshare-all \

将创建一个新的 user/ipc/pid/net/utc 命名空间,并尝试在可能的情况下创建一个新的 cgroup 命名空间;

--new-session

将为沙箱创建一个新的终端会话,从控制终端断开连接,例如它无法将输入注入到终端中;

 --die-with-parent

将确保子进程(在本例中为 imv-wayland)在 bwrap 父进程死亡时死亡。

我们可能还有一个 config 文件

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

如果您有本地配置,这将添加到 imv,如果没有,则仍然继续。

"$XDG_CONFIG_HOME" 传递到沙箱

--setenv XDG_CONFIG_HOME "$XDG_CONFIG_HOME" \

但这并不总是定义的,所以让我们回退到 XDG 基本目录 默认值

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

如果设置了 "$XDG_CONFIG_HOME",这将使用它,否则回退到 "$HOME/.config" 的默认值。

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

需要使用 config 并在窗口标题中显示各种信息。

待办事项: 这是使用:Bubblewrap#找不到缺少的路径 找到的,有更好的方法吗?


~/.local/bin/bwrap-imv 现在看起来像

内容为 ~/.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:-./}"

现在让我们运行 bwrap-imv,进入一个带有图像的目录

$ 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)

添加

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

bwrap-imvXKB 是一个键盘键映射支持库。

添加上述内容后,再次运行它

$ 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)

添加

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

并再次运行

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

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

访问字符设备。

待办事项: 这是使用:Bubblewrap#找不到缺少的路径 找到的,有更好的方法吗?


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

访问 PCI 资源。

待办事项: 这是使用:Bubblewrap#找不到缺少的路径 找到的,有更好的方法吗?


--clearenv \

最后,我们可以取消设置所有环境变量,除了 "$PWD" 和我们使用 --setenv 设置的任何变量。

现在 imv 应该显示图像,并且您的 config 文件应该可以工作(如果您有)。如果您不使用命令,完成的 ~/.local/bin/bwrap-imv 应该看起来像

内容为 ~/.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:-./}"

但是,如果您确实使用命令,您会注意到它仅显示 替换字符

提示: imv 中的命令通过按 : 输入。

如果您尝试使用命令,它会说

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

查看 fonts-conf 手册页(来自 fontconfig-doc),我们看到 /etc/fonts/ 是系统字体配置目录,"${XDG_CONFIG_HOME}/fontconfig/" 是每用户配置目录。"${XDG_CONFIG_HOME}/fontconfig/" 使用 --ro-bind-try 添加,因此它不必存在

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

扫描字体文件的默认目录是 /usr/share/fonts/"${XDG_DATA_HOME}/fonts/""${XDG_DATA_HOME}/fonts/" 使用 --ro-bind-try 添加

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

"$XDG_DATA_HOME" 传递到沙箱

--setenv XDG_DATA_HOME "$XDG_DATA_HOME" \

就像 "$XDG_CONFIG_HOME" 一样,这并不总是定义的,所以回退到 XDG 基本目录 默认值

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

如果设置了 "$XDG_DATA_HOME",则使用它,否则使用 "$HOME/.local/share"

还需要用户字体信息缓存,默认情况下是 "${XDG_CACHE_HOME}/fontconfig/"

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

"$XDG_CACHE_HOME" 传递到沙箱

--setenv XDG_CACHE_HOME "$XDG_CACHE_HOME" \

就像 "$XDG_CONFIG_HOME" 一样,这并不总是定义的,所以回退到 XDG 基本目录 默认值

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

如果设置了 "$XDG_CACHE_HOME",则使用它,否则使用 "$HOME/.cache"

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

也是需要的,否则当您执行 :<backspace> 时,它将终止进程。ICU 提供 Unicode 和全球化支持。

待办事项: 这是使用:Bubblewrap#找不到缺少的路径 找到的,有更好的方法吗?


更新后的 ~/.local/bin/bwrap-imv 应该看起来像这样

内容为 ~/.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:-./}"

查看沙箱中存在的内容

最后,通过将 /usr/libexec/imv-wayland "${1:-./}" 替换为 /bin/sh 并添加 --ro-bind /bin/ /bin/ \ 来测试所有允许的内容。四处查看,看看文件系统是什么样的

内容为 ~/.local/bin/bwrap-imv

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

调用 bwrap-imv

$ bwrap-imv IMAGE

显示哪些环境变量处于活动状态

$ printenv

查看根目录下的目录

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

完成时 exit

$ exit

不要忘记改回来

内容为 ~/.local/bin/bwrap-imv

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

完成了基本 bwrap 包装器。

Seccomp

此材料需要扩展...

.desktop 集成

此材料已过时...

这可能应该在 Default_applications 中记录并链接到此处。在使用 bwrap 时,没有什么独特的。(讨论

注意: 本节还使用 imv 作为示例。

XDG 桌面条目规范 是一组标准,描述了如何启动特定程序,它如何在菜单中显示等等。

imv 的默认 .desktop 文件位于 /usr/share/applications/imv.desktop。将其移动到 "${XDG_DATA_HOME}/applications/bwrap-imv.desktop"

只需要更改 3 个选项:Name/Name[en_US],在图形文件管理器(如果您已安装)的应用程序菜单中显示的内容;Exec,要执行的程序

内容为 "${XDG_DATA_HOME}/applications/bwrap-imv.desktop"

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

程序 xdg-open(来自 xdg-utils 软件包)可用于根据 MIME 类型 + "${XDG_CONFIG_HOME}/mimeapps.list""${XDG_DATA_HOME}/applications/mimeinfo.cache" 中相应的条目打开文件。

如果尚未安装 desktop-file-utils,请安装它,它带有两个需要的命令 desktop-file-validateupdate-desktop-database

# apk add desktop-file-utils

验证

最好使用 desktop-file-validate 验证 imv.desktop

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

更新数据库

这将使 "${XDG_DATA_HOME}/applications/" 中的条目优先于系统范围的文件(/usr/share/applications/)。但是 "${XDG_CONFIG_HOME}/mimeapps.list" 优先于两者。

更新数据库将创建 "${XDG_DATA_HOME}/applications/mimeinfo.cache"

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

故障排除

找不到缺少的路径

如果所有其他方法都失败,请从广泛开始,并努力缩小范围。查看 bwrap 是否完全适用于该程序

$ bwrap \ --dev-bind / / PROGRAM

如果这有效,则开始缩小范围

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

继续操作,直到您尽可能缩小范围。

参见