强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第 8 章 - Flatpak 集成

第 8 章:Flatpak 集成

本章介绍 Bubblewrap 与 Flatpak 的深度集成关系,包括 Flatpak 如何使用 bwrap 创建应用沙箱、权限管理机制以及门户 API(Portal API)的使用。


8.1 Flatpak 与 Bubblewrap 的关系

Flatpak 是一个 Linux 桌面应用分发框架,其核心沙箱机制完全依赖 Bubblewrap

架构关系

┌───────────────────────────────────────────────────┐
│                   用户界面                         │
│          (GNOME Software, KDE Discover)           │
├───────────────────────────────────────────────────┤
│                   Flatpak 框架                     │
│  ┌─────────────────────────────────────────────┐  │
│  │  flatpak-builder    flatpak run             │  │
│  │  (构建工具)         (运行时管理)              │  │
│  └─────────────────────────────────────────────┘  │
├───────────────────────────────────────────────────┤
│              Bubblewrap 沙箱层                     │
│  ┌─────────────────────────────────────────────┐  │
│  │  bwrap --ro-bind ... --unshare-all ...      │  │
│  │  (命名空间隔离、文件系统控制)                  │  │
│  └─────────────────────────────────────────────┘  │
├───────────────────────────────────────────────────┤
│              Linux 内核                            │
│  Namespace | seccomp | cgroup | SELinux/AppArmor  │
└───────────────────────────────────────────────────┘

Flatpak 使用 bwrap 的方式

当你运行 flatpak run 时,Flatpak 会:

  1. 根据应用的权限声明,构建 bwrap 命令行参数
  2. 设置文件系统挂载点(运行时、应用、SDK)
  3. 配置命名空间隔离
  4. 设置门户 API 通信
  5. 通过 bwrap 启动应用进程
# 查看 Flatpak 实际执行的 bwrap 命令
flatpak run --command=cat org.gnome.Calculator /dev/null 2>&1 &
FLATPAK_PID=$!

# 查看进程树
pstree -p $FLATPAK_PID
# 或者使用 strace 追踪
# strace -f -e clone,clone3 flatpak run org.gnome.Calculator 2>&1 | grep bwrap

8.2 Flatpak 沙箱结构

文件系统布局

Flatpak 应用的文件系统:
/
├── app/                    → 应用自身文件 (ro-bind)
│   └── org.gnome.Calculator/
│       ├── bin/
│       ├── lib/
│       └── share/
├── usr/                    → 运行时 (ro-bind)
│   ├── bin/
│   ├── lib/
│   └── share/
├── etc/                    → 配置 (ro-bind 部分)
├── tmp/                    → tmpfs
├── var/                    → 应用数据
│   └── data/
│       └── org.gnome.Calculator/
├── home/                   → 沙箱化主目录 (tmpfs)
│   └── user/
│       ├── .var/
│       │   └── app/
│       │       └── org.gnome.Calculator/
│       │           ├── data/     → 持久存储
│       │           ├── config/   → 持久配置
│       │           └── cache/    → 缓存
│       └── (其他目录通常是 tmpfs)
├── run/                    → tmpfs
│   ├── host/               → 宿主部分目录
│   ├── user/               → 用户运行时
│   └── flatpak/
└── dev/                    → 最小 dev

命名空间配置

命名空间Flatpak 默认说明
User应用在 user namespace 中运行
Mount独立的文件系统视图
PID只看到自己的进程
Network⚠️ 可选默认共享宿主网络,可禁用
UTS独立主机名
Cgroup隐藏宿主 cgroup
IPC隔离 IPC

8.3 Flatpak 权限管理

权限类型

权限类型说明示例
文件系统访问宿主文件系统--filesystem=home, --filesystem=xdg-download
设备访问硬件设备--device=dri (GPU), --device=all
网络网络访问--share=network
IPC共享 IPC--allow=bluetooth
Socket使用特定 socket--socket=x11, --socket=wayland, --socket=pulseaudio
功能启用特定功能--own-name=org.example.App
环境环境变量--env=VAR=value

查看应用权限

# 查看已安装应用的权限
flatpak info --show-permissions org.gnome.Calculator
# 或
flatpak permission-show org.gnome.Calculator

# 查看应用元数据中的权限声明
cat ~/.local/share/flatpak/app/org.gnome.Calculator/current/active/metadata

# 使用 flatpak override 查看/修改权限
flatpak override --show org.gnome.Calculator

管理应用权限

# 授予额外权限
# 允许访问下载目录
flatpak override --filesystem=xdg-download org.gnome.Calculator

# 禁止网络访问
flatpak override --unshare=network org.gnome.Calculator

# 允许访问特定目录
flatpak override --filesystem=/mnt/data org.gnome.Calculator

# 撤销权限
flatpak override --nofilesystem=xdg-download org.gnome.Calculator

# 重置所有覆盖
flatpak override --reset org.gnome.Calculator

权限对照表

权限命令bwrap 等效说明
--filesystem=home--bind $HOME /home/user访问整个主目录
--filesystem=xdg-download--bind ~/Downloads /home/user/Downloads仅访问下载目录
--unshare=network--unshare-net禁用网络
--share=network(不使用 –unshare-net)启用网络
--device=dri--dev-bind /dev/dri /dev/driGPU 访问
--socket=x11--bind /tmp/.X11-unix /tmp/.X11-unixX11 显示

8.4 门户 API(Portal API)

什么是门户 API

门户 API 是 Flatpak 的安全 IPC 机制,允许沙箱内的应用通过受控的方式访问宿主系统的资源,而不需要直接的文件系统或设备权限。

沙箱应用                     门户守护进程                  宿主系统
┌──────────────┐            ┌──────────────────┐        ┌──────────────┐
│              │   D-Bus    │                  │        │              │
│  应用代码    │ ──────────→│  xdg-desktop-    │ ──────→│  文件系统    │
│              │            │  portal          │        │  打印机      │
│  "请打开文件"│ ←──────────│                  │ ←──────│  通知系统    │
│              │            │  "用户选择了      │        │  摄像头      │
│              │            │   这个文件"      │        │  ...        │
└──────────────┘            └──────────────────┘        └──────────────┘

常用门户

门户功能用户体验
文件选择器打开/保存文件对话框用户通过对话框选择文件
打印打印文档调用系统打印对话框
通知发送桌面通知显示在通知栏
位置获取地理位置弹出权限请求
屏幕截图截取屏幕用户确认后截图
屏幕共享共享屏幕内容用户确认后共享
通知发送通知显示在系统通知中
打开 URI打开 URL用默认浏览器打开
壁纸设置壁纸用户确认

使用门户 API

# 测试文件选择器门户(需要 xdg-desktop-portal)
flatpak run --command=bash org.gnome.Calculator -c '
    # 使用 gdbus 调用文件选择器门户
    gdbus call --session \
        --dest org.freedesktop.portal.Desktop \
        --object-path /org/freedesktop/portal/desktop \
        --method org.freedesktop.portal.OpenFile.OpenFile \
        "" "选择文件" "options" "{}"
'

门户 API 安全模型

传统模式(无门户):
  应用 → 直接访问文件系统 → 可能访问敏感文件

门户模式:
  应用 → 请求文件 → 用户选择 → 应用只能访问用户选择的文件
                          ↑
                     用户控制点
对比项直接访问门户 API
安全性低(全盘访问)高(用户授权)
用户体验无需交互需要用户确认
隐私保护
实现复杂度简单较复杂
可审计性好(可记录授权历史)

8.5 Flatpak 应用开发

创建 Flatpak 应用清单

# org.example.MyApp.yml
app-id: org.example.MyApp
runtime: org.freedesktop.Platform//23.08
runtime-version: '23.08'
sdk: org.freedesktop.Sdk//23.08
command: myapp

# 应用权限
finish-args:
  # 允许显示 GUI(Wayland)
  - --socket=wayland
  # 允许显示 GUI(X11 fallback)
  - --socket=fallback-x11
  # 允许网络访问
  - --share=network
  # 允许访问下载目录
  - --filesystem=xdg-download
  # 禁止访问其他用户的目录
  - --no-filesystem=home
  # 允许 GPU 加速
  - --device=dri

modules:
  - name: myapp
    buildsystem: meson
    sources:
      - type: archive
        url: https://example.com/myapp-1.0.tar.gz
        sha256: abc123...

构建和测试

# 构建 Flatpak 应用
flatpak-builder --force-clean build-dir org.example.MyApp.yml

# 安装本地构建
flatpak-builder --user --install --force-clean build-dir org.example.MyApp.yml

# 运行应用
flatpak run org.example.MyApp

# 查看沙箱配置
flatpak info --show-permissions org.example.MyApp

# 调试模式运行
flatpak run --devel --command=bash org.example.MyApp

查看底层 bwrap 命令

# 使用 strace 捕获 flatpak 的 bwrap 调用
strace -f -e trace=clone,clone3,execve \
    flatpak run org.gnome.Calculator 2>&1 | grep bwrap

# 或者通过 Flatpak 的调试选项
flatpak run --verbose org.gnome.Calculator 2>&1 | grep "bwrap\|bubblewrap"

8.6 Flatpak 运行时与 SDK

运行时层次

Flatpak 运行时架构:
┌─────────────────────────────────────┐
│          应用 (org.example.App)     │
│  ┌───────────────────────────────┐  │
│  │  应用代码 + 独立依赖           │  │
│  └───────────────────────────────┘  │
├─────────────────────────────────────┤
│          运行时 (Runtime)           │
│  ┌───────────────────────────────┐  │
│  │  共享库、字体、基础工具         │  │
│  │  (GLib, GTK, Mesa, ...)       │  │
│  └───────────────────────────────┘  │
├─────────────────────────────────────┤
│          SDK (构建时)               │
│  ┌───────────────────────────────┐  │
│  │  编译器、头文件、开发工具       │  │
│  │  (gcc, meson, pkg-config...)  │  │
│  └───────────────────────────────┘  │
└─────────────────────────────────────┘

常用运行时

运行时版本包含内容
org.freedesktop.Platform23.08基础 Linux 用户空间
org.gnome.Platform45GNOME 库和工具
org.kde.Platform6.6KDE 库和工具

8.7 高级:自定义 Flatpak 沙箱

使用 flatpak override 深度定制

# 挂载自定义目录到沙箱
flatpak override --filesystem=/mnt/shared-data org.gnome.TextEditor

# 设置自定义环境变量
flatpak override --env=EDITOR=vim org.gnome.TextEditor

# 禁用 D-Bus 访问
flatpak override --no-talk-name=org.freedesktop.secrets org.gnome.TextEditor

# 限制 socket 访问
flatpak override --no-socket=pulseaudio org.gnome.TextEditor

# 查看所有覆盖
flatpak override --show org.gnome.TextEditor

Flatpak 权限影响 bwrap 的方式

Flatpak 权限底层 bwrap 效果
--filesystem=home--bind $HOME /home/user
--filesystem=host--bind / /run/host (受限)
--filesystem=/path--bind /path /run/host/path
--no-filesystem仅 tmpfs 主目录
--unshare=network--unshare-net
--device=all--dev-bind /dev /dev
--device=dri--dev-bind /dev/dri /dev/dri

8.8 Flatpak 沙箱调试

进入沙箱调试

# 以开发模式进入沙箱
flatpak run --devel --command=bash org.gnome.Calculator

# 在沙箱内查看环境
ls /
mount
cat /proc/self/uid_map
id

# 检查可用的库
ldconfig -p | grep gtk

# 退出
exit

查看沙箱日志

# 查看 Flatpak 运行时日志
flatpak run --log-session-bus --log-system-bus org.gnome.Calculator

# 使用 journalctl 查看相关日志
journalctl --user -f | grep -i flatpak

# 查看门户日志
journalctl --user -f | grep -i portal

常见问题排查

# 问题: 应用无法访问文件
# 解决: 检查并添加文件系统权限
flatpak override --filesystem=xdg-download org.example.App

# 问题: 应用无法联网
# 解决: 确认网络权限
flatpak info --show-permissions org.example.App | grep network

# 问题: 应用无法显示
# 解决: 检查显示 socket
flatpak override --socket=wayland org.example.App
flatpak override --socket=x11 org.example.App

# 问题: GPU 加速不工作
# 解决: 授予 DRI 权限
flatpak override --device=dri org.example.App

8.9 Flatseal:图形化权限管理

Flatseal 是一个图形化的 Flatpak 权限管理工具。

# 安装 Flatseal
flatpak install flathub com.github.tchx84.Flatseal

# 运行
flatpak run com.github.tchx84.Flatseal

Flatseal 提供的功能:

  • 查看和修改每个应用的权限
  • 实时预览权限更改
  • 权限说明和文档
  • 重置到默认权限

8.10 不使用 Flatpak 的 bwrap 集成

模拟 Flatpak 的沙箱模式

即使不使用 Flatpak,你也可以利用 bwrap 创建类似的沙箱环境:

#!/bin/bash
# flatpak-like-sandbox.sh - 模拟 Flatpak 沙箱

APP_NAME="$1"
shift

# 应用数据目录
APP_DATA="$HOME/.local/share/sandbox/$APP_NAME"
mkdir -p "$APP_DATA"/{data,config,cache}

exec bwrap \
  --ro-bind / / \
  --dev /dev \
  --proc /proc \
  --tmpfs /tmp \
  --tmpfs /run \
  --unshare-all \
  --hostname "$APP_NAME" \
  --die-with-parent \
  --new-session \
  --bind "$APP_DATA/data" "/home/user/.var/app/$APP_NAME/data" \
  --bind "$APP_DATA/config" "/home/user/.var/app/$APP_NAME/config" \
  --bind "$APP_DATA/cache" "/home/user/.var/app/$APP_NAME/cache" \
  --clearenv \
  --setenv HOME /home/user \
  --setenv XDG_DATA_HOME /home/user/.var/app/$APP_NAME/data \
  --setenv XDG_CONFIG_HOME /home/user/.var/app/$APP_NAME/config \
  --setenv XDG_CACHE_HOME /home/user/.var/app/$APP_NAME/cache \
  "$@"

使用:

# 在沙箱中运行 vim
./flatpak-like-sandbox.sh myeditor vim /tmp/test.txt

# 在沙箱中运行 Python
./flatpak-like-sandbox.sh mypython python3

8.11 注意事项

⚠️ 重要提醒

  1. Flatpak 的 bwrap 调用是自动生成的:不要尝试手动修改 Flatpak 生成的 bwrap 命令,应使用 flatpak override 修改权限。

  2. 门户 API 需要守护进程xdg-desktop-portal 必须在宿主上运行,否则门户功能不可用。

  3. GPU 访问需要 DRI 权限--device=dri 对于图形应用至关重要,否则会使用软件渲染。

  4. X11 转发的安全性--socket=x11 允许应用截取屏幕和记录按键。推荐使用 Wayland。

  5. 运行时版本:保持运行时更新,以获得安全修复。

  6. --filesystem=host 是危险权限:授予对宿主文件系统的广泛访问权限,应尽量避免。


8.12 扩展阅读


上一章:第 7 章 - 安全策略 | 下一章:第 9 章 - Docker 中使用