浏览代码

feat: add gvisor syscall test (#1271)

* feat(tests): 添加gvisor系统调用测试套件

新增gvisor系统调用测试框架,包含Makefile、运行脚本、文档和测试用例。调整rootfs镜像大小为2G以适应测试需求。

Signed-off-by: longjin <longjin@DragonOS.org>

* feat(gvisor): 重构测试运行器为Rust实现并添加DADK支持

- 将Shell脚本实现的测试运行器重写为Rust版本
- 添加DADK构建配置文件以支持DragonOS应用开发工具链
- 更新Makefile以支持Rust工具链和DADK安装目标
- 增强下载脚本功能,支持跳过已存在测试套件和强制下载选项
- 移除原有的run_tests.sh脚本,替换为更高效的Rust实现

Signed-off-by: longjin <longjin@DragonOS.org>

* feat(config): 添加应用程序黑名单功能

- 新增 app-blocklist.toml 配置文件模板,支持多种应用程序匹配方式
- 支持严格模式和非严格模式配置
- 添加黑名单配置文件路径到 dadk-manifest.toml
- 提供详细的配置说明和示例

Signed-off-by: longjin <longjin@DragonOS.org>

* docs: 更新gVisor系统调用测试文档

- 新增gVisor系统调用测试文档,包含概述、快速开始和测试机制说明
- 删除旧的测试运行器README文档

Signed-off-by: longjin <longjin@DragonOS.org>

---------

Signed-off-by: longjin <longjin@DragonOS.org>
LoGin 1 月之前
父节点
当前提交
e1db32e669

+ 67 - 0
config/app-blocklist.toml

@@ -0,0 +1,67 @@
+# =========================================================
+# DADK 应用程序黑名单配置文件模板
+# =========================================================
+# 
+# 应用程序黑名单功能允许用户指定不希望编译和安装的应用程序。
+# 当黑名单中的应用程序被检测到时,DADK 会根据配置自动跳过这些应用程序的构建和安装过程。
+
+# =========================================================
+# 全局配置选项
+# =========================================================
+
+# 是否启用严格模式(可选)
+# - true(默认):严格模式,跳过被屏蔽的应用程序并记录警告
+# - false:非严格模式,只记录警告但不跳过应用程序
+strict = true
+
+# 是否在日志中显示被跳过的应用(可选)
+# - true(默认):在日志中显示被跳过的应用程序信息
+# - false:静默模式,不显示被跳过的应用程序
+log_skipped = true
+
+# =========================================================
+# 被屏蔽的应用程序列表
+# =========================================================
+# 
+# 支持以下匹配方式:
+# 1. 精确匹配:            name = "app1"
+# 2. 版本匹配:            name = "openssl@1.1.1"  
+# 3. 通配符名称:          name = "test-*"
+# 4. 通配符版本:          name = "nginx@1.*"
+# 5. 复合模式:            name = "lib*@2.*"
+#
+# 每个应用可以选择性地提供屏蔽原因(reason)
+
+
+# =========================================================
+# 配置说明和注意事项
+# =========================================================
+#
+# 1. **依赖关系**:如果其他应用程序依赖被屏蔽的应用程序,构建过程可能会失败。
+#    请确保处理好依赖关系。
+#
+# 2. **模式匹配优先级**:
+#    - 精确匹配 > 版本匹配 > 模式匹配
+#    - 如果有多个模式都匹配,使用第一个匹配的结果
+#
+# 3. **通配符语法**:
+#    - "*" 匹配任意数量的字符(包括0个)
+#    - "?" 匹配单个字符
+#    - 支持在名称和版本中使用通配符
+#
+# 4. **版本格式**:
+#    - 版本号使用 "@" 符号分隔,如 "app@1.0.0"
+#    - 版本号支持通配符,如 "app@1.*"
+#
+# 5. **配置文件路径**:
+#    - 默认路径:config/app-blocklist.toml
+#    - 可在 dadk-manifest.toml 中通过 app-blocklist-config 字段自定义路径
+#
+# 6. **字段说明**:
+#    - name:应用程序名称或匹配模式(必需)
+#    - reason:屏蔽原因说明(可选,建议提供以便调试和维护)
+
+# 屏蔽gvisor系统调用测试
+[[blocked_apps]]
+name = "gvisor syscall tests"
+reason = "由于文件较大,因此屏蔽。如果要允许系统调用测试,则把这几行取消注释即可"

+ 1 - 1
config/rootfs.toml

@@ -2,7 +2,7 @@
 # Filesystem type (options: `fat32`)
 fs_type = "fat32"
 # Size of the rootfs disk image (eg, `1G`, `1024M`)
-size = "1G"
+size = "2G"
 
 [partition]
 # Partition type (options: "none", "mbr", "gpt")

+ 4 - 0
dadk-manifest.toml

@@ -22,3 +22,7 @@ cache-root-dir = "bin/dadk_cache"
 # User configuration directory path
 # 这个字段只是临时用于兼容旧版本,v0.2版本重构完成后会删除
 user-config-dir = "user/dadk/config"
+
+# Application blocklist configuration file path
+app-blocklist-config = "config/app-blocklist.toml"
+

+ 79 - 0
docs/kernel/ktest/gvisor_syscall_test.rst

@@ -0,0 +1,79 @@
+==============================
+gVisor 系统调用测试
+==============================
+
+DragonOS 集成了 gVisor 系统调用测试套件,用于验证操作系统系统调用实现的兼容性和正确性。
+
+概述
+========
+
+gVisor 是 Google 开发的容器运行时沙箱,包含了大量的系统调用兼容性测试。这些测试用于验证操作系统的系统调用实现是否符合 Linux 标准。
+
+主要特性:
+
+- **全面的测试覆盖**:包含数百个系统调用测试用例
+- **白名单机制**:默认只运行已验证的测试,逐步完善支持
+- **黑名单过滤**:可针对每个测试程序屏蔽特定的测试用例
+- **自动化运行**:提供 Makefile 和脚本简化测试流程
+
+快速开始
+==========
+
+1. 进入测试目录:
+
+   .. code-block:: bash
+
+      cd user/apps/tests/syscall/gvisor
+
+2. 在Linux运行白名单测试(自动下载测试套件):
+
+   .. code-block:: bash
+
+      make test
+
+3. 如果需要运行测试,请先修改配置文件:
+
+   编辑 `config/app-blocklist.toml`,注释掉以下内容:
+
+   .. code-block:: toml
+
+      # 屏蔽gvisor系统调用测试
+      # [[blocked_apps]]
+      # name = "gvisor syscall tests"
+      # reason = "由于文件较大,因此屏蔽。如果要允许系统调用测试,则把这几行取消注释即可"
+
+4. 在 DragonOS 系统内运行测试:
+
+   进入安装目录并运行测试程序:
+
+   .. code-block:: bash
+
+      cd /opt/tests/gvisor
+      ./gvisor-test-runner --help
+
+   使用 ``./gvisor-test-runner`` 可以运行具体的测试用例。
+
+5. 查看详细文档:
+
+   请参阅 `user/apps/tests/syscall/gvisor/README.md` 获取完整的使用说明。
+
+测试机制
+==========
+
+白名单模式
+-----------
+
+测试框架默认启用白名单模式,只运行 ``whitelist.txt`` 中指定的测试程序。这允许逐步验证 DragonOS 的系统调用实现。
+
+黑名单过滤
+-----------
+
+对于每个测试程序,可以通过 ``blocklists/`` 目录下的文件屏蔽特定的测试用例。这对于跳过暂不支持或不稳定的测试非常有用。
+
+更多详细信息
+==============
+
+关于 gVisor 系统调用测试的详细使用方法、配置选项和开发指南,请查看测试目录下的 README.md 文档:
+
+- 文档位置:`user/apps/tests/syscall/gvisor/README.md`
+

+ 2 - 0
docs/kernel/ktest/index.rst

@@ -17,3 +17,5 @@
    :maxdepth: 1
    :caption: 目录
 
+   gvisor_syscall_test.rst
+

+ 1 - 1
user/Makefile

@@ -2,7 +2,7 @@ user_sub_dirs = apps
 
 DADK_VERSION=$(shell dadk -V | awk 'END {print $$2}')
 # 最小的DADK版本
-MIN_DADK_VERSION = 0.4.0
+MIN_DADK_VERSION = 0.5.0
 DADK_CACHE_DIR = $(ROOT_PATH)/bin/dadk_cache
 
 ECHO:

+ 2 - 0
user/apps/tests/syscall/gvisor/.gitignore

@@ -0,0 +1,2 @@
+/tests/
+/results/

+ 105 - 0
user/apps/tests/syscall/gvisor/Makefile

@@ -0,0 +1,105 @@
+# gvisor系统调用测试 Makefile
+# 用于DragonOS项目
+
+# Rust工具链配置
+TOOLCHAIN="+nightly-2025-08-10-x86_64-unknown-linux-gnu"
+RUSTFLAGS+=""
+
+ifdef DADK_CURRENT_BUILD_DIR
+# 如果是在dadk中编译,那么安装到dadk的安装目录中
+INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR)
+else
+# 如果是在本地编译,那么安装到当前目录下的install目录中
+INSTALL_DIR = ./install
+endif
+
+ifeq ($(ARCH), x86_64)
+	export RUST_TARGET=x86_64-unknown-linux-musl
+else ifeq ($(ARCH), riscv64)
+	export RUST_TARGET=riscv64gc-unknown-linux-gnu
+else
+# 默认为x86_64,用于本地编译
+	export RUST_TARGET=x86_64-unknown-linux-musl
+endif
+
+.PHONY: all build install download test list run clean help
+
+# 默认目标:构建并安装
+all: build install
+
+# 显示帮助信息
+help:
+	@echo "gvisor系统调用测试 Makefile"
+	@echo ""
+	@echo "可用目标:"
+	@echo "  all         - 构建并安装测试运行器(默认)"
+	@echo "  build       - 构建Rust测试运行器"
+	@echo "  install     - 安装测试运行器和必要文件"
+	@echo "  download    - 下载gvisor测试套件"
+	@echo "  test        - 运行白名单中的测试"
+	@echo "  list        - 列出所有可用测试"
+	@echo "  run         - 运行测试并传递参数(如:make run ARGS=\"-v epoll_test\")"
+	@echo "  clean       - 清理测试文件和结果"
+	@echo "  help        - 显示此帮助信息"
+	@echo ""
+	@echo "环境变量:"
+	@echo "  SYSCALL_TEST_WORKDIR - 测试工作目录(默认: /tmp/gvisor_tests)"
+	@echo "  TEST_TIMEOUT         - 单个测试超时时间(默认: 300秒)"
+
+# 构建Rust测试运行器
+build:
+	@echo "构建gvisor测试运行器..."
+	@cd runner && RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release
+
+# 下载测试套件
+download:
+	@echo "下载gvisor测试套件..."
+	@./download_tests.sh
+
+# 安装到目标目录
+install: build
+	@echo "安装gvisor测试套件到 $(INSTALL_DIR)"
+	@mkdir -p $(INSTALL_DIR)
+	# 安装Rust测试运行器二进制文件
+	@cp -f runner/target/$(RUST_TARGET)/release/runner $(INSTALL_DIR)/gvisor-test-runner
+	# 安装测试配置文件
+	@cp -f whitelist.txt $(INSTALL_DIR)/
+	@cp -rf blocklists $(INSTALL_DIR)/
+	# 安装下载脚本(用于目标系统上下载测试)
+	@cp -f download_tests.sh $(INSTALL_DIR)/
+	@chmod +x $(INSTALL_DIR)/download_tests.sh
+	@chmod +x $(INSTALL_DIR)/gvisor-test-runner
+	@echo "安装完成"
+
+# 运行测试
+test: build
+	@echo "运行gvisor系统调用测试..."
+	@if [ ! -d tests ]; then \
+		echo "测试套件不存在,正在下载..."; \
+		./download_tests.sh; \
+	fi
+	@./runner/target/$(RUST_TARGET)/release/runner
+
+# 列出所有测试
+list: build
+	@if [ ! -d tests ]; then \
+		echo "测试套件不存在,正在下载..."; \
+		./download_tests.sh; \
+	fi
+	@./runner/target/$(RUST_TARGET)/release/runner --list
+
+# 运行测试并传递参数
+run: build
+	@if [ ! -d tests ]; then \
+		echo "测试套件不存在,正在下载..."; \
+		./download_tests.sh; \
+	fi
+	@./runner/target/$(RUST_TARGET)/release/runner $(ARGS)
+
+# 清理
+clean:
+	@echo "清理测试文件和结果..."
+	@rm -rf results/
+	@rm -f gvisor-syscalls-tests.tar.xz
+	@cd runner && cargo clean
+	@echo "清理完成"

+ 306 - 0
user/apps/tests/syscall/gvisor/README.md

@@ -0,0 +1,306 @@
+# gvisor系统调用测试套件
+
+这是DragonOS项目中用于运行gvisor系统调用测试的自动化工具。
+
+测试用例仓库:https://cnb.cool/DragonOS-Community/test-suites
+
+## 概述
+
+gvisor是Google开发的容器运行时沙箱,它包含了大量的系统调用兼容性测试。这些测试可以用来验证操作系统的系统调用实现是否符合Linux标准。
+
+本测试框架默认启用**白名单模式**,只运行`whitelist.txt`文件中指定的测试程序,这样可以逐步验证DragonOS的系统调用实现。同时,每个测试程序内部的测试用例可以通过`blocklists/`目录中的黑名单文件进行过滤。
+
+## 快速开始
+
+### 1. 下载并运行白名单测试
+
+```bash
+# 进入gvisor测试目录
+cd user/apps/tests/syscall/gvisor
+
+# 运行白名单中的测试(默认行为,会自动下载测试套件)
+make test
+
+# 运行所有测试(包括非白名单)
+make run ARGS="--no-whitelist"
+```
+
+### 2. 仅下载测试套件
+
+```bash
+make download
+# 或者直接运行脚本
+./download_tests.sh
+```
+
+### 3. 查看可用测试
+
+```bash
+make list
+```
+
+## 详细使用方法
+
+### 基本使用
+
+通过Makefile可以方便地运行测试:
+
+```bash
+# 显示所有可用命令
+make help
+
+# 构建并安装测试运行器
+make
+
+# 下载测试套件
+make download
+
+# 运行白名单中的测试(自动下载测试套件)
+make test
+
+# 列出所有可用测试
+make list
+
+# 运行测试并传递参数
+make run ARGS="-v"
+make run ARGS="epoll_test"
+make run ARGS="-j 4 --no-whitelist"
+
+# 清理测试结果
+make clean
+```
+
+### 使用示例
+
+```bash
+# 运行特定测试
+make run ARGS="epoll_test"
+
+# 使用模式匹配运行多个测试
+make run ARGS="socket*"
+
+# 详细输出模式
+make run ARGS="-v"
+
+# 并行运行4个测试
+make run ARGS="-j 4"
+
+# 禁用白名单,运行所有测试程序
+make run ARGS="--no-whitelist"
+
+# 忽略所有blocklist文件
+make run ARGS="--no-blocklist"
+
+# 设置超时时间为60秒
+make run ARGS="-t 60"
+
+# 组合多个参数
+make run ARGS="-v -j 2 epoll_test"
+```
+
+## 添加新的测试
+
+### 添加测试程序到白名单
+
+1. 编辑 `whitelist.txt` 文件
+2. 每行添加一个测试程序名称(不带路径)
+3. 支持注释(以 `#` 开头)
+
+示例:
+```text
+# 核心系统调用测试
+socket_test
+epoll_test
+fcntl_test
+ioctl_test
+
+# 文件系统测试
+open_test
+stat_test
+mmap_test
+```
+
+### 创建blocklist过滤测试用例
+
+对于每个测试程序,可以创建blocklist文件来屏蔽特定的测试用例:
+
+1. 在 `blocklists/` 目录下创建与测试程序同名的文件
+2. 每行添加要屏蔽的测试用例名称
+3. 支持注释和空行
+
+示例blocklist文件(`blocklists/socket_test`):
+```text
+# 屏蔽IPv6相关测试(DragonOS暂不支持IPv6)
+SocketTest.IPv6*
+SocketTest.IPv6Socket*
+
+# 屏蔽需要特殊权限的测试
+SocketTest.PrivilegedSocket
+
+# 屏蔽已知不稳定的测试
+SocketTest.UnimplementedFeature
+```
+
+### Blocklist文件格式
+
+- 每行一个测试用例名称或模式
+- 支持通配符(`*` 匹配任意字符)
+- 注释以 `#` 开头
+- 空行会被忽略
+- 测试用例名称通常格式为 `TestSuite.TestName`
+
+## Blocklist机制详解
+
+### 什么是Blocklist
+
+Blocklist用于屏蔽某些在当前环境下不适用或不稳定的测试子用例。这对于逐步完善系统调用支持非常有用。
+
+### Blocklist的工作原理
+
+1. 当运行测试时,测试运行器会自动查找与测试程序同名的blocklist文件
+2. 文件位于 `blocklists/` 目录下
+3. 支持多个额外的blocklist目录(通过 `--extra-blocklist` 参数)
+4. 匹配的测试用例会被跳过,不计入统计结果
+
+### 示例:完整的测试配置
+
+假设我们要添加对 `epoll_test` 的支持:
+
+1. **添加到白名单** (`whitelist.txt`):
+   ```text
+   epoll_test
+   ```
+
+2. **创建blocklist** (`blocklists/epoll_test`):
+   ```text
+   # 屏蔽超时测试(需要更精确的时间控制)
+   EpollTest.Timeout*
+
+   # 屏蔽循环测试(可能导致死锁)
+   EpollTest.CycleOfOneDisallowed
+   EpollTest.CycleOfThreeDisallowed
+
+   # 屏蔽信号竞争测试
+   # UnblockWithSignal contains races. Better not to enable it.
+   EpollTest.UnblockWithSignal
+   ```
+
+3. **运行测试**:
+   ```bash
+   # 使用Makefile运行所有白名单测试(会自动应用blocklist)
+   make test
+
+   # 只运行特定测试
+   make run ARGS="epoll_test"
+
+   # 查看详细输出
+   make run ARGS="-v epoll_test"
+   ```
+
+## 文件结构
+
+```
+user/apps/tests/syscall/gvisor/
+├── download_tests.sh      # 下载脚本
+├── Makefile              # Make构建文件
+├── README.md             # 说明文档
+├── whitelist.txt         # 测试程序白名单
+├── runner/               # Rust测试运行器
+│   ├── Cargo.toml
+│   ├── Makefile
+│   └── src/
+│       ├── main.rs
+│       └── lib_sync.rs
+├── blocklists/           # Blocklist目录
+│   ├── README.md         # Blocklist说明
+│   └── epoll_test        # 示例blocklist
+├── tests/                # 测试可执行文件(下载后生成)
+└── results/              # 测试结果(运行后生成)
+    ├── failed_cases.txt  # 失败用例列表
+    ├── test_report.txt   # 测试报告
+    └── *.output          # 各测试的详细输出
+```
+
+## 环境变量
+
+- `SYSCALL_TEST_WORKDIR`: 测试工作目录,默认为`/tmp/gvisor_tests`
+- `TEST_TIMEOUT`: 单个测试的超时时间,默认300秒
+- `RUSTFLAGS`: Rust编译器标志
+
+## 测试报告
+
+测试完成后会生成:
+
+1. **控制台输出**: 实时显示测试进度和结果
+2. **测试报告**: `results/test_report.txt` - 包含统计信息和失败用例
+3. **失败用例列表**: `results/failed_cases.txt` - 仅包含失败的测试名称
+4. **详细输出**: `results/*.output` - 每个测试的详细输出
+
+## 开发者指南
+
+### 编译和开发
+
+```bash
+# 构建Rust测试运行器
+make build
+
+# 安装到指定目录
+make install
+```
+
+### 性能提示
+
+- 默认串行运行测试,确保稳定性
+- 如需并行测试,使用 `-j` 参数(谨慎使用)
+- 合理设置超时时间,避免长时间等待
+- 使用blocklist跳过已知问题的测试
+
+## 注意事项
+
+1. **网络依赖**: 首次运行 `make test` 时会自动下载测试套件
+2. **存储空间**: 测试套件解压后约占用1.1GB空间
+3. **运行时间**: 完整测试可能需要较长时间,建议先运行部分测试
+4. **权限要求**: 某些测试可能需要特定的系统权限
+5. **自动下载**: 运行 `make test` 或 `make list` 时会自动下载所需的测试套件
+
+## 故障排除
+
+### 下载失败
+```bash
+# 检查网络连接
+wget --spider https://cnb.cool/DragonOS-Community/test-suites/-/releases/download/release_20250626/gvisor-syscalls-tests.tar.xz
+
+# 手动下载并放置
+wget -O gvisor-syscalls-tests.tar.xz https://cnb.cool/DragonOS-Community/test-suites/-/releases/download/release_20250626/gvisor-syscalls-tests.tar.xz
+```
+
+### MD5校验失败
+```bash
+# 重新下载文件
+rm -f gvisor-syscalls-tests.tar.xz
+./download_tests.sh
+```
+
+### 测试运行失败
+1. 检查测试二进制文件是否存在
+2. 确认可执行权限
+3. 查看详细输出了解失败原因
+
+### 测试失败过多
+1. 检查系统调用实现是否完整
+2. 调整blocklist屏蔽已知问题
+3. 检查测试环境配置
+4. 考虑增加超时时间
+
+## 贡献
+
+如果发现测试相关的问题或有改进建议,请:
+
+1. 提交issue描述问题
+2. 更新相应的blocklist文件
+3. 提交patch修复脚本问题
+4. 帮助完善测试覆盖
+
+## 许可证
+
+本测试框架代码遵循GPLv2许可证。gvisor测试套件本身遵循其原始许可证。

+ 43 - 0
user/apps/tests/syscall/gvisor/blocklists/README.md

@@ -0,0 +1,43 @@
+# Blocklist 目录
+
+这个目录包含用于屏蔽特定gvisor测试子用例的blocklist文件。
+
+## 文件格式
+
+每个blocklist文件对应一个测试可执行文件,文件名应与测试可执行文件名相同。
+
+例如:
+- `socket_test` - 对应测试可执行文件 `socket_test`
+- `pipe_test` - 对应测试可执行文件 `pipe_test`
+
+## 内容格式
+
+blocklist文件中每一行包含一个要屏蔽的测试用例名称:
+
+```
+# 这是注释行,会被忽略
+# 屏蔽某个特定的测试用例
+TestCase.SpecificTest
+# 屏蔽某个测试套件下的所有测试
+TestSuite.*
+# 屏蔽包含特定模式的测试
+*PatternName*
+```
+
+## 注意事项
+
+- 以 `#` 开头的行会被视为注释并忽略
+- 空行会被忽略
+- 支持通配符模式匹配
+- 测试用例名称格式通常为 `TestSuite.TestCase`
+
+## 示例
+
+如果要屏蔽socket_test中的某些测试,创建文件`socket_test`:
+
+```
+# 屏蔽IPv6相关的测试(暂不支持)
+SocketTest.IPv6*
+# 屏蔽特定的不稳定测试
+SocketTest.UnstableTest
+``` 

+ 7 - 0
user/apps/tests/syscall/gvisor/blocklists/epoll_test

@@ -0,0 +1,7 @@
+# EpollTest.Timeout_NoRandomSave
+# EpollTest.CycleOfOneDisallowed
+# EpollTest.CycleOfThreeDisallowed
+# `UnblockWithSignal` contains races. Better not to enable it.
+# See https://github.com/asterinas/asterinas/pull/1035 for details.
+# EpollTest.UnblockWithSignal
+

+ 233 - 0
user/apps/tests/syscall/gvisor/download_tests.sh

@@ -0,0 +1,233 @@
+#!/bin/bash
+
+# gvisor系统调用测试套件下载和校验脚本
+# 用于DragonOS项目
+
+set -e
+
+SCRIPT_DIR=$(dirname "$(realpath "$0")")
+TESTS_DIR="$SCRIPT_DIR/tests"
+TEST_ARCHIVE="gvisor-syscalls-tests.tar.xz"
+TEST_URL="https://cnb.cool/DragonOS-Community/test-suites/-/releases/download/release_20250626/$TEST_ARCHIVE"
+MD5SUM_URL="https://cnb.cool/DragonOS-Community/test-suites/-/releases/download/release_20250626/$TEST_ARCHIVE.md5sum"
+
+# 颜色定义
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+RED='\033[0;31m'
+NC='\033[0m'
+
+print_info() {
+    echo -e "${GREEN}[INFO]${NC} $1"
+}
+
+print_warn() {
+    echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+print_error() {
+    echo -e "${RED}[ERROR]${NC} $1"
+}
+
+# 检查命令是否存在
+check_command() {
+    if ! command -v "$1" &> /dev/null; then
+        print_error "命令 '$1' 未找到,请安装相应软件包"
+        exit 1
+    fi
+}
+
+# 检查必要的命令
+check_dependencies() {
+    print_info "检查依赖..."
+    check_command wget
+    check_command md5sum
+    check_command tar
+}
+
+# 检查测试套件是否已存在且完整
+check_existing_tests() {
+    if [ -d "$TESTS_DIR" ] && [ "$(find "$TESTS_DIR" -name "*_test" | wc -l)" -gt 0 ]; then
+        print_info "发现已存在的测试套件"
+        return 0
+    else
+        return 1
+    fi
+}
+
+# 下载文件
+download_file() {
+    local url="$1"
+    local output="$2"
+    local quiet_mode="${3:-false}"
+    
+    if [ "$quiet_mode" = "true" ]; then
+        # 静默下载(用于小文件如MD5)
+        if wget -q -O "$output" "$url" 2>/dev/null; then
+            return 0
+        else
+            return 1
+        fi
+    else
+        # 显示进度的下载(用于大文件)
+        print_info "从 $url 下载文件..."
+        if wget -q --show-progress -O "$output" "$url"; then
+            print_info "下载完成: $output"
+            return 0
+        else
+            print_error "下载失败: $url"
+            return 1
+        fi
+    fi
+}
+
+# 获取期望的MD5值
+get_expected_md5() {
+    # 将日志输出重定向到stderr,避免混入返回值
+    print_info "获取期望的MD5校验和..." >&2
+    local temp_md5_file=$(mktemp)
+    
+    # 确保在函数退出时清理临时文件
+    trap "rm -f '$temp_md5_file'" RETURN
+    
+    if download_file "$MD5SUM_URL" "$temp_md5_file" "true"; then
+        # 解析MD5文件,格式通常是: "md5hash filename"
+        local expected_md5=$(head -1 "$temp_md5_file" | cut -d' ' -f1)
+        
+        if [ -n "$expected_md5" ] && [ ${#expected_md5} -eq 32 ]; then
+            echo "$expected_md5"
+            return 0
+        else
+            print_error "MD5文件格式无效或为空" >&2
+            return 1
+        fi
+    else
+        print_error "无法下载MD5校验和文件" >&2
+        return 1
+    fi
+}
+
+# 验证MD5校验和
+verify_md5() {
+    local file="$1"
+    local expected="$2"
+    
+    print_info "验证MD5校验和..."
+    local actual_md5=$(md5sum "$file" | cut -d' ' -f1)
+    
+    if [ "$actual_md5" = "$expected" ]; then
+        print_info "MD5校验和验证成功"
+        return 0
+    else
+        print_error "MD5校验和验证失败"
+        print_error "期望: $expected"
+        print_error "实际: $actual_md5"
+        return 1
+    fi
+}
+
+# 解压测试套件
+extract_tests() {
+    local archive="$1"
+    
+    print_info "解压测试套件..."
+    mkdir -p "$TESTS_DIR"
+    
+    if tar -xf "$archive" -C "$TESTS_DIR" --strip-components=1; then
+        print_info "解压完成"
+        return 0
+    else
+        print_error "解压失败"
+        return 1
+    fi
+}
+
+# 清理临时文件
+cleanup_temp_files() {
+    print_info "清理临时文件..."
+    rm -f "$SCRIPT_DIR/$TEST_ARCHIVE"
+}
+
+# 主函数
+main() {
+    local skip_if_exists=false
+    local force_download=false
+
+    # 检查参数
+    for arg in "$@"; do
+        case "$arg" in
+            --skip-if-exists)
+                skip_if_exists=true
+                ;;
+            --force-download)
+                force_download=true
+                ;;
+        esac
+    done
+
+    print_info "开始检查和下载gvisor系统调用测试套件"
+
+    # 检查依赖
+    check_dependencies
+
+    # 检查是否已存在测试套件
+    if check_existing_tests; then
+        if [ "$skip_if_exists" = true ]; then
+            print_info "测试套件已存在,跳过下载"
+            exit 0
+        elif [ "$force_download" = true ]; then
+            print_warn "强制重新下载,删除现有测试套件..."
+            rm -rf "$TESTS_DIR"
+        else
+            read -p "测试套件已存在,是否重新下载?(y/N) " -n 1 -r
+            echo
+            if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+                print_info "使用现有测试套件"
+                exit 0
+            fi
+            print_warn "删除现有测试套件..."
+            rm -rf "$TESTS_DIR"
+        fi
+    fi
+    
+    # 下载测试套件
+    if ! download_file "$TEST_URL" "$SCRIPT_DIR/$TEST_ARCHIVE"; then
+        exit 1
+    fi
+    
+    # 获取期望的MD5值
+    local expected_md5
+    if ! expected_md5=$(get_expected_md5); then
+        cleanup_temp_files
+        exit 1
+    fi
+    
+    print_info "期望的MD5校验和: $expected_md5"
+    
+    # 验证MD5
+    if ! verify_md5 "$SCRIPT_DIR/$TEST_ARCHIVE" "$expected_md5"; then
+        cleanup_temp_files
+        exit 1
+    fi
+    
+    # 解压测试套件
+    if ! extract_tests "$SCRIPT_DIR/$TEST_ARCHIVE"; then
+        cleanup_temp_files
+        exit 1
+    fi
+    
+    # 清理临时文件
+    cleanup_temp_files
+    
+    # 统计测试数量
+    local test_count=$(find "$TESTS_DIR" -name "*_test" | wc -l)
+    print_info "测试套件安装完成,共包含 $test_count 个测试用例"
+    
+    # 设置执行权限
+    find "$TESTS_DIR" -name "*_test" -exec chmod +x {} \;
+    
+    print_info "gvisor测试套件准备就绪"
+}
+
+# 运行主函数
+main "$@" 

+ 21 - 0
user/apps/tests/syscall/gvisor/runner/.gitignore

@@ -0,0 +1,21 @@
+# Rust构建产物
+/target/
+Cargo.lock
+
+# IDE文件
+.vscode/
+.idea/
+*.swp
+*.swo
+
+# 操作系统文件
+.DS_Store
+Thumbs.db
+
+# 临时文件
+*~
+*.tmp
+*.bak
+
+# 测试输出文件(如果在此目录运行)
+/results/

+ 19 - 0
user/apps/tests/syscall/gvisor/runner/Cargo.toml

@@ -0,0 +1,19 @@
+[package]
+name = "gvisor-test-runner"
+version = "0.1.0"
+edition = "2021"
+
+[[bin]]
+name = "runner"
+path = "src/main.rs"
+
+[dependencies]
+clap = { version = "4.0", features = ["derive"] }
+anyhow = "1.0"
+regex = "1.0"
+chrono = { version = "0.4", features = ["serde"] }
+log = "0.4"
+env_logger = "0.10"
+
+[profile.release]
+lto = true

+ 69 - 0
user/apps/tests/syscall/gvisor/runner/Makefile

@@ -0,0 +1,69 @@
+# Makefile for gvisor-test-runner
+
+# 默认目标
+.PHONY: all build release clean install test help
+
+# 默认构建
+all: build
+
+# 开发构建
+build:
+	cargo build
+
+# Release构建(推荐)
+release:
+	cargo build --release
+
+# 清理构建文件
+clean:
+	cargo clean
+
+# 运行测试(如果有单元测试)
+test:
+	cargo test
+
+# 检查代码
+check:
+	cargo check
+
+# 格式化代码
+fmt:
+	cargo fmt
+
+# 代码检查
+clippy:
+	cargo clippy
+
+# 列出测试用例
+list: release
+	./target/release/runner --list
+
+# 运行测试(使用默认配置)
+run: release
+	./target/release/runner
+
+# 显示帮助
+help: release
+	./target/release/runner --help
+
+# 显示此Makefile的帮助
+show-help:
+	@echo "可用的make目标:"
+	@echo "  all      - 构建开发版本(默认)"
+	@echo "  build    - 构建开发版本"
+	@echo "  release  - 构建release版本(推荐)"
+	@echo "  clean    - 清理构建文件"
+	@echo "  install  - 安装到系统(需要sudo)"
+	@echo "  test     - 运行单元测试"
+	@echo "  check    - 检查代码编译"
+	@echo "  fmt      - 格式化代码"
+	@echo "  clippy   - 运行代码检查"
+	@echo "  list     - 列出所有测试用例"
+	@echo "  run      - 运行测试(默认配置)"
+	@echo "  help     - 显示程序帮助"
+	@echo ""
+	@echo "使用示例:"
+	@echo "  make release                    # 构建release版本"
+	@echo "  make list                       # 列出测试用例"  
+	@echo "  make run                        # 运行白名单中的测试"
+	@echo "  ./target/release/runner --help  # 查看详细帮助"

+ 594 - 0
user/apps/tests/syscall/gvisor/runner/src/lib_sync.rs

@@ -0,0 +1,594 @@
+use anyhow::Result;
+use chrono::{DateTime, Local};
+use std::{
+    collections::HashSet,
+    fs::{self, File},
+    io::{BufRead, BufReader, Write},
+    path::{Path, PathBuf},
+    process::Command,
+    sync::{
+        atomic::{AtomicUsize, Ordering},
+        Arc,
+    },
+    time::Instant,
+};
+
+/// 测试统计信息
+#[derive(Debug, Default)]
+pub struct TestStats {
+    total: AtomicUsize,
+    passed: AtomicUsize,
+    failed: AtomicUsize,
+    skipped: AtomicUsize,
+}
+
+impl TestStats {
+    pub fn increment_total(&self) {
+        self.total.fetch_add(1, Ordering::Relaxed);
+    }
+
+    pub fn increment_passed(&self) {
+        self.passed.fetch_add(1, Ordering::Relaxed);
+    }
+
+    pub fn increment_failed(&self) {
+        self.failed.fetch_add(1, Ordering::Relaxed);
+    }
+
+    #[allow(dead_code)]
+    pub fn increment_skipped(&self) {
+        self.skipped.fetch_add(1, Ordering::Relaxed);
+    }
+
+    pub fn get_totals(&self) -> (usize, usize, usize, usize) {
+        (
+            self.total.load(Ordering::Relaxed),
+            self.passed.load(Ordering::Relaxed),
+            self.failed.load(Ordering::Relaxed),
+            self.skipped.load(Ordering::Relaxed),
+        )
+    }
+}
+
+/// 测试运行器配置
+#[derive(Debug, Clone)]
+pub struct Config {
+    pub verbose: bool,
+    pub timeout: u64,
+    pub parallel: usize,
+    pub use_blocklist: bool,
+    pub use_whitelist: bool,
+    pub whitelist_file: PathBuf,
+    pub tests_dir: PathBuf,
+    pub blocklists_dir: PathBuf,
+    pub results_dir: PathBuf,
+    pub temp_dir: PathBuf,
+    pub extra_blocklist_dirs: Vec<PathBuf>,
+    pub test_patterns: Vec<String>,
+}
+
+impl Default for Config {
+    fn default() -> Self {
+        let script_dir = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
+        Self {
+            verbose: false,
+            timeout: 300,
+            parallel: 1,
+            use_blocklist: true,
+            use_whitelist: true,
+            whitelist_file: script_dir.join("whitelist.txt"),
+            tests_dir: script_dir.join("tests"),
+            blocklists_dir: script_dir.join("blocklists"),
+            results_dir: script_dir.join("results"),
+            temp_dir: PathBuf::from(
+                std::env::var("SYSCALL_TEST_WORKDIR")
+                    .unwrap_or_else(|_| "/tmp/gvisor_tests".to_string()),
+            ),
+            extra_blocklist_dirs: Vec::new(),
+            test_patterns: Vec::new(),
+        }
+    }
+}
+
+/// 颜色输出辅助函数(简化版)
+pub fn print_colored(color: &str, prefix: &str, msg: &str) {
+    match color {
+        "green" => println!("\x1b[32m[{}]\x1b[0m {}", prefix, msg),
+        "yellow" => println!("\x1b[33m[{}]\x1b[0m {}", prefix, msg),
+        "red" => eprintln!("\x1b[31m[{}]\x1b[0m {}", prefix, msg),
+        "blue" => println!("\x1b[34m[{}]\x1b[0m {}", prefix, msg),
+        _ => println!("[{}] {}", prefix, msg),
+    }
+}
+
+/// gvisor系统调用测试运行器
+pub struct TestRunner {
+    pub config: Config,
+    pub stats: Arc<TestStats>,
+}
+
+impl TestRunner {
+    pub fn new(config: Config) -> Self {
+        Self {
+            config,
+            stats: Arc::new(TestStats::default()),
+        }
+    }
+
+    /// 打印信息日志
+    fn print_info(&self, msg: &str) {
+        print_colored("green", "INFO", msg);
+    }
+
+    /// 打印警告日志
+    fn print_warn(&self, msg: &str) {
+        print_colored("yellow", "WARN", msg);
+    }
+
+    /// 打印错误日志
+    fn print_error(&self, msg: &str) {
+        print_colored("red", "ERROR", msg);
+    }
+
+    /// 打印测试日志
+    fn print_test(&self, msg: &str) {
+        print_colored("blue", "TEST", msg);
+    }
+
+    /// 检查测试套件是否存在
+    pub fn check_test_suite(&self) -> Result<()> {
+        if !self.config.tests_dir.exists() {
+            anyhow::bail!(
+                "测试目录不存在: {:?}\n请先运行 ./download_tests.sh 下载测试套件",
+                self.config.tests_dir
+            );
+        }
+
+        let test_files: Vec<_> = fs::read_dir(&self.config.tests_dir)?
+            .filter_map(|entry| entry.ok())
+            .filter(|entry| {
+                entry.path().is_file() && entry.file_name().to_string_lossy().ends_with("_test")
+            })
+            .collect();
+
+        if test_files.is_empty() {
+            anyhow::bail!("测试套件未找到\n请先运行 ./download_tests.sh 下载测试套件");
+        }
+
+        Ok(())
+    }
+
+    /// 创建必要的目录
+    pub fn setup_directories(&self) -> Result<()> {
+        fs::create_dir_all(&self.config.results_dir)?;
+        fs::create_dir_all(&self.config.temp_dir)?;
+        fs::create_dir_all(&self.config.blocklists_dir)?;
+        Ok(())
+    }
+
+    /// 读取白名单中的测试程序
+    fn get_whitelist_tests(&self) -> Result<HashSet<String>> {
+        if !self.config.whitelist_file.exists() {
+            anyhow::bail!("白名单文件不存在: {:?}", self.config.whitelist_file);
+        }
+
+        let file = File::open(&self.config.whitelist_file)?;
+        let reader = BufReader::new(file);
+        let mut tests = HashSet::new();
+
+        for line in reader.lines() {
+            let line = line?;
+            let line = line.trim();
+            if !line.is_empty() && !line.starts_with('#') {
+                tests.insert(line.to_string());
+            }
+        }
+
+        Ok(tests)
+    }
+
+    /// 检查测试是否在白名单中
+    fn is_test_whitelisted(&self, test_name: &str) -> bool {
+        if !self.config.use_whitelist {
+            return true;
+        }
+
+        match self.get_whitelist_tests() {
+            Ok(whitelist) => whitelist.contains(test_name),
+            Err(_) => false,
+        }
+    }
+
+    /// 获取测试的blocklist
+    fn get_test_blocklist(&self, test_name: &str) -> Vec<String> {
+        if !self.config.use_blocklist {
+            return Vec::new();
+        }
+
+        let mut blocked_subtests = Vec::new();
+
+        // 检查主blocklist目录
+        let blocklist_file = self.config.blocklists_dir.join(test_name);
+        if let Ok(content) = self.read_blocklist_file(&blocklist_file) {
+            blocked_subtests.extend(content);
+        }
+
+        // 检查额外的blocklist目录
+        for extra_dir in &self.config.extra_blocklist_dirs {
+            let extra_blocklist = extra_dir.join(test_name);
+            if let Ok(content) = self.read_blocklist_file(&extra_blocklist) {
+                blocked_subtests.extend(content);
+            }
+        }
+
+        blocked_subtests
+    }
+
+    /// 读取blocklist文件
+    fn read_blocklist_file(&self, path: &Path) -> Result<Vec<String>> {
+        if !path.exists() {
+            return Ok(Vec::new());
+        }
+
+        let file = File::open(path)?;
+        let reader = BufReader::new(file);
+        let mut blocked = Vec::new();
+
+        for line in reader.lines() {
+            let line = line?;
+            let line = line.trim();
+            if !line.is_empty() && !line.starts_with('#') {
+                blocked.push(line.to_string());
+            }
+        }
+
+        Ok(blocked)
+    }
+
+    /// 获取要运行的测试列表
+    pub fn get_test_list(&self) -> Result<Vec<String>> {
+        // 获取所有测试文件
+        let mut all_tests = Vec::new();
+        for entry in fs::read_dir(&self.config.tests_dir)? {
+            let entry = entry?;
+            if entry.path().is_file() {
+                let file_name = entry.file_name();
+                let file_name_str = file_name.to_string_lossy();
+                if file_name_str.ends_with("_test") {
+                    all_tests.push(file_name_str.to_string());
+                }
+            }
+        }
+
+        // 应用白名单过滤
+        let mut candidate_tests = Vec::new();
+        if self.config.use_whitelist {
+            for test in &all_tests {
+                if self.is_test_whitelisted(test) {
+                    candidate_tests.push(test.clone());
+                }
+            }
+
+            if candidate_tests.is_empty() {
+                self.print_warn("没有测试通过白名单过滤");
+                return Ok(Vec::new());
+            }
+
+            if self.config.verbose {
+                self.print_info(&format!(
+                    "白名单过滤后有 {} 个测试可用",
+                    candidate_tests.len()
+                ));
+            }
+        } else {
+            candidate_tests = all_tests;
+        }
+
+        // 如果没有指定模式,返回候选测试
+        if self.config.test_patterns.is_empty() {
+            candidate_tests.sort();
+            return Ok(candidate_tests);
+        }
+
+        // 根据模式过滤测试
+        let mut filtered_tests = HashSet::new();
+        for pattern in &self.config.test_patterns {
+            for test in &candidate_tests {
+                if test == pattern {
+                    filtered_tests.insert(test.clone());
+                }
+            }
+        }
+
+        let mut result: Vec<_> = filtered_tests.into_iter().collect();
+        result.sort();
+        Ok(result)
+    }
+
+    /// 运行单个测试
+    pub fn run_single_test(&self, test_name: &str) -> Result<bool> {
+        println!("[DEBUG] 开始运行测试: {}", test_name);
+        let test_path = self.config.tests_dir.join(test_name);
+        println!("[DEBUG] 测试路径: {:?}", test_path);
+
+        if !test_path.exists() || !test_path.is_file() {
+            self.print_warn(&format!("测试不存在或不可执行: {}", test_name));
+            return Ok(false);
+        }
+
+        self.print_test(&format!("运行测试用例: {}", test_name));
+
+        // 获取blocklist
+        let blocked_subtests = self.get_test_blocklist(test_name);
+
+        // 结果输出文件(使用绝对路径,避免工作目录切换影响)
+        let output_file = self
+            .config
+            .results_dir
+            .join(format!("{}.output", test_name));
+
+        println!("[DEBUG] 工作目录: {:?}", self.config.tests_dir);
+        println!("[DEBUG] TEST_TMPDIR: {:?}", self.config.temp_dir);
+        println!("[DEBUG] 直接执行: {:?}", test_path);
+        if !blocked_subtests.is_empty() {
+            println!("[DEBUG] gtest_filter: -{}", blocked_subtests.join(":"));
+        }
+
+        // 确保结果目录存在
+        if let Err(e) = fs::create_dir_all(&self.config.results_dir) {
+            self.print_error(&format!("创建结果目录失败: {}", e));
+        }
+
+        // 打开输出文件,并将 stdout/stderr 重定向到该文件
+        let out = File::create(&output_file);
+        if let Err(e) = out.as_ref() {
+            self.print_error(&format!("创建输出文件失败: {:?}, 错误: {}", output_file, e));
+        }
+        let out = out?;
+        let err = out.try_clone()?;
+
+        // 构造并执行命令(不使用 shell,不捕获输出,不创建管道)
+        let start_time = Instant::now();
+        let mut cmd = Command::new(&test_path);
+        if !blocked_subtests.is_empty() {
+            cmd.arg("--gtest_filter")
+                .arg(format!("-{}", blocked_subtests.join(":")));
+        }
+        let status = cmd
+            .current_dir(&self.config.tests_dir)
+            .env("TEST_TMPDIR", &self.config.temp_dir)
+            .stdout(std::process::Stdio::from(out))
+            .stderr(std::process::Stdio::from(err))
+            .status();
+
+        // 清理临时目录
+        let _ = fs::remove_dir_all(&self.config.temp_dir);
+        let _ = fs::create_dir_all(&self.config.temp_dir);
+
+        let duration = start_time.elapsed();
+        match status {
+            Ok(s) if s.success() => {
+                self.print_info(&format!(
+                    "✓ {} 通过 ({:.2}s)",
+                    test_name,
+                    duration.as_secs_f64()
+                ));
+                // 将输出文件尾部打印一点,便于快速查看
+                if let Ok(content) = fs::read_to_string(&output_file) {
+                    let tail: String = content
+                        .lines()
+                        .rev()
+                        .take(10)
+                        .collect::<Vec<_>>()
+                        .into_iter()
+                        .rev()
+                        .map(|s| format!("{}\n", s))
+                        .collect();
+                    if !tail.is_empty() {
+                        println!("[DEBUG] 输出尾部: \n{}", tail);
+                    }
+                }
+                Ok(true)
+            }
+            Ok(s) => {
+                self.print_error(&format!(
+                    "✗ {} 失败 ({:.2}s), 退出码: {:?}",
+                    test_name,
+                    duration.as_secs_f64(),
+                    s.code()
+                ));
+                // 打印错误输出尾部
+                if let Ok(content) = fs::read_to_string(&output_file) {
+                    let tail: String = content
+                        .lines()
+                        .rev()
+                        .take(20)
+                        .collect::<Vec<_>>()
+                        .into_iter()
+                        .rev()
+                        .map(|s| format!("{}\n", s))
+                        .collect();
+                    if !tail.is_empty() {
+                        println!("[DEBUG] 错误输出尾部: \n{}", tail);
+                    }
+                }
+                Ok(false)
+            }
+            Err(e) => {
+                self.print_error(&format!("✗ {} 执行错误: {}", test_name, e));
+                Ok(false)
+            }
+        }
+    }
+
+    /// 运行所有测试
+    pub fn run_all_tests(&self) -> Result<()> {
+        let test_list = self.get_test_list()?;
+
+        if test_list.is_empty() {
+            self.print_warn("没有找到匹配的测试用例");
+            return Ok(());
+        }
+
+        self.print_info(&format!("准备运行 {} 个测试用例", test_list.len()));
+
+        // 初始化结果文件
+        let failed_cases_file = self.config.results_dir.join("failed_cases.txt");
+        let mut failed_cases = File::create(&failed_cases_file)?;
+
+        // 运行测试
+        for test_name in test_list {
+            self.stats.increment_total();
+
+            match self.run_single_test(&test_name) {
+                Ok(true) => {
+                    self.stats.increment_passed();
+                }
+                Ok(false) => {
+                    self.stats.increment_failed();
+                    writeln!(failed_cases, "{}", test_name)?;
+                }
+                Err(e) => {
+                    self.stats.increment_failed();
+                    writeln!(failed_cases, "{}", test_name)?;
+                    self.print_error(&format!("测试 {} 出错: {}", test_name, e));
+                }
+            }
+
+            println!("---");
+        }
+
+        Ok(())
+    }
+
+    /// 生成测试报告
+    pub fn generate_report(&self) -> Result<()> {
+        let report_file = self.config.results_dir.join("test_report.txt");
+        let mut file = File::create(&report_file)?;
+        let (total, passed, failed, _skipped) = self.stats.get_totals();
+
+        let now: DateTime<Local> = Local::now();
+        let success_rate = if total > 0 {
+            passed as f64 * 100.0 / total as f64
+        } else {
+            0.0
+        };
+
+        let report = format!(
+            "gvisor系统调用测试报告\n\
+            ==========================\n\
+            测试时间: {}\n\
+            测试目录: {:?}\n\
+            \n\
+            测试统计:\n\
+            总测试数: {}\n\
+            通过: {}\n\
+            失败: {}\n\
+            成功率: {:.2}%\n\
+            \n",
+            now.format("%Y-%m-%d %H:%M:%S"),
+            self.config.tests_dir,
+            total,
+            passed,
+            failed,
+            success_rate
+        );
+
+        file.write_all(report.as_bytes())?;
+        println!("{}", report);
+
+        if failed > 0 {
+            let failed_cases_file = self.config.results_dir.join("failed_cases.txt");
+            if failed_cases_file.exists() {
+                let failed_content = fs::read_to_string(&failed_cases_file)?;
+                let failed_section = format!("失败的测试用例:\n{}", failed_content);
+                file.write_all(failed_section.as_bytes())?;
+                println!("{}", failed_section);
+            }
+        }
+
+        Ok(())
+    }
+
+    /// 显示测试结果
+    pub fn show_results(&self) {
+        let (total, passed, failed, _skipped) = self.stats.get_totals();
+
+        log::info!("");
+        log::info!("===============================================");
+        self.print_info("测试完成");
+        log::info!(
+            "\x1b[32m{}\x1b[0m / \x1b[32m{}\x1b[0m 测试用例通过",
+            passed,
+            total
+        );
+
+        if failed > 0 {
+            log::info!("\x1b[31m{}\x1b[0m 个测试用例失败:", failed);
+            let failed_cases_file = self.config.results_dir.join("failed_cases.txt");
+            if let Ok(content) = fs::read_to_string(&failed_cases_file) {
+                for line in content.lines() {
+                    if !line.trim().is_empty() {
+                        log::info!("  \x1b[31m[X]\x1b[0m {}", line);
+                    }
+                }
+            }
+        }
+
+        log::info!("");
+        log::info!(
+            "详细报告保存在: {:?}",
+            self.config.results_dir.join("test_report.txt")
+        );
+    }
+
+    /// 列出所有测试用例
+    pub fn list_tests(&self) -> Result<()> {
+        if !self.config.tests_dir.exists() {
+            self.print_error(&format!("测试目录不存在: {:?}", self.config.tests_dir));
+            self.print_info("请先运行 ./download_tests.sh 下载测试套件");
+            return Ok(());
+        }
+
+        if self.config.use_whitelist {
+            self.print_info(&format!(
+                "白名单模式 - 可运行的测试用例 (来自: {:?}):",
+                self.config.whitelist_file
+            ));
+            let test_list = self.get_test_list()?;
+            for test_name in &test_list {
+                log::info!("  \x1b[32m✓\x1b[0m {}", test_name);
+            }
+
+            self.print_info("所有可用测试用例 (包括未在白名单中的):");
+            for entry in fs::read_dir(&self.config.tests_dir)? {
+                let entry = entry?;
+                if entry.path().is_file() {
+                    let file_name = entry.file_name();
+                    let file_name_str = file_name.to_string_lossy();
+                    if file_name_str.ends_with("_test") {
+                        if self.is_test_whitelisted(&file_name_str) {
+                            log::info!("  \x1b[32m✓\x1b[0m {} (在白名单中)", file_name_str);
+                        } else {
+                            log::info!("  \x1b[33m○\x1b[0m {} (不在白名单中)", file_name_str);
+                        }
+                    }
+                }
+            }
+        } else {
+            self.print_info("所有可用的测试用例:");
+            for entry in fs::read_dir(&self.config.tests_dir)? {
+                let entry = entry?;
+                if entry.path().is_file() {
+                    let file_name = entry.file_name();
+                    let file_name_str = file_name.to_string_lossy();
+                    if file_name_str.ends_with("_test") {
+                        log::info!("  {}", file_name_str);
+                    }
+                }
+            }
+        }
+
+        Ok(())
+    }
+}

+ 159 - 0
user/apps/tests/syscall/gvisor/runner/src/main.rs

@@ -0,0 +1,159 @@
+use anyhow::Result;
+use clap::{Arg, Command};
+use std::path::PathBuf;
+
+mod lib_sync;
+use lib_sync::{Config, TestRunner};
+
+fn main() -> Result<()> {
+    env_logger::Builder::from_default_env()
+        .filter_level(log::LevelFilter::Info)
+        .init();
+    let app = Command::new("gvisor-test-runner")
+        .version("0.1.0")
+        .about("gvisor系统调用测试运行脚本 - Rust版本")
+        .arg(
+            Arg::new("help")
+                .short('h')
+                .long("help")
+                .action(clap::ArgAction::Help)
+                .help("显示此帮助信息"),
+        )
+        .arg(
+            Arg::new("list")
+                .short('l')
+                .long("list")
+                .action(clap::ArgAction::SetTrue)
+                .help("列出所有可用的测试用例"),
+        )
+        .arg(
+            Arg::new("verbose")
+                .short('v')
+                .long("verbose")
+                .action(clap::ArgAction::SetTrue)
+                .help("详细输出模式"),
+        )
+        .arg(
+            Arg::new("timeout")
+                .short('t')
+                .long("timeout")
+                .value_name("SEC")
+                .help("设置单个测试的超时时间(默认:300秒)")
+                .value_parser(clap::value_parser!(u64)),
+        )
+        .arg(
+            Arg::new("parallel")
+                .short('j')
+                .long("parallel")
+                .value_name("NUM")
+                .help("并行运行的测试数量(默认:1)")
+                .value_parser(clap::value_parser!(usize)),
+        )
+        .arg(
+            Arg::new("no-blocklist")
+                .long("no-blocklist")
+                .action(clap::ArgAction::SetTrue)
+                .help("忽略所有blocklist文件"),
+        )
+        .arg(
+            Arg::new("extra-blocklist")
+                .long("extra-blocklist")
+                .value_name("DIR")
+                .action(clap::ArgAction::Append)
+                .help("指定额外的blocklist目录"),
+        )
+        .arg(
+            Arg::new("no-whitelist")
+                .long("no-whitelist")
+                .action(clap::ArgAction::SetTrue)
+                .help("禁用白名单模式,运行所有测试程序"),
+        )
+        .arg(
+            Arg::new("whitelist")
+                .long("whitelist")
+                .value_name("FILE")
+                .help("指定白名单文件路径(默认:whitelist.txt)"),
+        )
+        .arg(
+            Arg::new("test-patterns")
+                .value_name("PATTERN")
+                .action(clap::ArgAction::Append)
+                .help("测试名称模式"),
+        );
+
+    let matches = app.get_matches();
+
+    // 解析配置
+    let mut config = Config::default();
+
+    config.verbose = matches.get_flag("verbose");
+
+    if let Some(timeout) = matches.get_one::<u64>("timeout") {
+        config.timeout = *timeout;
+    }
+
+    if let Some(parallel) = matches.get_one::<usize>("parallel") {
+        config.parallel = *parallel;
+    }
+
+    config.use_blocklist = !matches.get_flag("no-blocklist");
+    config.use_whitelist = !matches.get_flag("no-whitelist");
+
+    if let Some(whitelist_file) = matches.get_one::<String>("whitelist") {
+        config.whitelist_file = PathBuf::from(whitelist_file);
+    }
+
+    if let Some(extra_dirs) = matches.get_many::<String>("extra-blocklist") {
+        config.extra_blocklist_dirs = extra_dirs.map(|s| PathBuf::from(s)).collect();
+    }
+
+    if let Some(patterns) = matches.get_many::<String>("test-patterns") {
+        config.test_patterns = patterns.cloned().collect();
+    }
+
+    // 创建测试运行器
+    let runner = TestRunner::new(config);
+
+    // 处理特殊命令
+    if matches.get_flag("list") {
+        runner.list_tests()?;
+        return Ok(());
+    }
+
+    log::info!("==============================");
+    log::info!("  gvisor系统调用测试运行器");
+    log::info!("==============================");
+
+    // 检查测试套件
+    runner.check_test_suite()?;
+
+    // 设置目录
+    runner.setup_directories()?;
+
+    log::info!("开始运行gvisor系统调用测试");
+
+    // 显示运行配置
+    if runner.config.use_whitelist {
+        log::info!("白名单模式已启用: {:?}", runner.config.whitelist_file);
+    }
+    if !runner.config.use_blocklist {
+        log::info!("黑名单已禁用");
+    }
+
+    // 运行测试
+    runner.run_all_tests()?;
+
+    // 生成报告
+    runner.generate_report()?;
+
+    // 显示结果
+    runner.show_results();
+
+    // 返回适当的退出码
+    let (_, _, failed, _) = runner.stats.get_totals();
+    if failed > 0 {
+        std::process::exit(1);
+    }
+
+    Ok(())
+}

+ 30 - 0
user/apps/tests/syscall/gvisor/whitelist.txt

@@ -0,0 +1,30 @@
+# gvisor测试程序白名单
+# 每行一个测试程序名称,只有在此列表中的测试程序才会被执行
+# 以#开头的行为注释,空行会被忽略
+
+# 基础系统调用测试
+read_test
+#chdir_test
+
+# 文件系统相关测试
+#stat_test
+#chmod_test
+#chown_test
+
+# 进程相关测试
+#fork_test
+#exec_test
+#wait_test
+
+# 内存管理测试
+#mmap_test
+#brk_test
+
+# 网络相关测试
+#bind_test
+#connect_test
+#listen_test
+
+# 信号处理测试
+#signal_test
+#sigaction_test

+ 39 - 0
user/dadk/config/gvisor_syscall_tests-1.0.0.toml

@@ -0,0 +1,39 @@
+# 用户程序名称
+name = "gvisor syscall tests"
+# 版本号
+version = "1.0.0"
+# 用户程序描述信息
+description = "gVisor系统调用兼容性测试套件"
+# (可选)是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果
+build-once = false
+#  (可选) 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装
+install-once = false
+# 目标架构
+# 可选值:"x86_64", "aarch64", "riscv64"
+target-arch = ["x86_64"]
+# 任务源
+[task-source]
+# 构建类型
+# 可选值:"build-from-source", "install-from-prebuilt"
+type = "build-from-source"
+# 构建来源
+# "build_from_source" 可选值:"git", "local", "archive"
+# "install_from_prebuilt" 可选值:"local", "archive"
+source = "local"
+# 路径或URL
+source-path = "user/apps/tests/syscall/gvisor"
+
+# 构建相关信息
+[build]
+# (可选)构建命令
+build-command = "make install"
+
+# 安装相关信息
+[install]
+# (可选)安装到DragonOS的路径
+in-dragonos-path = "/opt/tests/gvisor"
+
+# 清除相关信息
+[clean]
+# (可选)清除命令
+clean-command = "make clean"