14 Star 80 Fork 38

aosp-riscv / working-group

 / 详情

exec_argv0_null

已完成
拥有者
创建于  
2022-06-28 11:37

[ FAILED ] unistd_nofortify.exec_argv0_null
[ FAILED ] unistd.exec_argv0_null
这两个原因类似。

在我的环境里添加 run-as 后就好了,但是 目前这两个cases 在我的环境里是好的,在 RVI 的环境里不行,可能哪里的微小差异导致,还有待研究!

评论 (3)

unicornx 创建了任务
unicornx 修改了描述
展开全部操作日志

分析如下:

TEST(UNISTD_TEST, exec_argv0_null) {
  // http://b/33276926
  char* args[] = {nullptr};
  char* envs[] = {nullptr};
  ASSERT_EXIT(execve("/system/bin/run-as", args, envs), testing::ExitedWithCode(1),
              "<unknown>: usage: run-as");
}

这个 case 依赖于 rootfs 中存在一个 /system/bin/run-as,而且注意这个文件是一个 so,不是 executable。
参考 system/core/run-as/run-as.cpp

int main(int argc, char* argv[]) {
  // Check arguments.
  if (argc < 2) {
    error(1, 0, "usage: run-as <package-name> [--user <uid>] <command> [<args>]\n");
  }
  ......

exec_argv0_null 测试中应该走这个地方并调用 error()

参考 bionic/libc/bionic/error.cpp 中的 error() 函数,

目前出现的问题是我们期望 __error_head() 应该调用 getprogname() 打印 <unknown>, 可是现在不是,而是一个 空 ""

Expected: contains regular expression "<unknown>: usage: run-as"
Actual msg:
[  DEATH   ] : usage: run-as <package-name> [--user <uid>] <command> [<args>]

所以需要检查为啥 getprogname() 里返回的 __progname 不对。
这个值的设置在 bionic/libc/upstream-openbsd/lib/libc/gen/setprogname.c

void
setprogname(const char *progname)
{
	char *tmpn;

	tmpn = strrchr(progname, '/');
	if (tmpn == NULL)
		__progname = (char *)progname;
	else
		__progname = tmpn + 1;
}

具体调用只有一处:bionic/libc/bionic/libc_init_common.cpp

void __libc_init_common() {
  ......
  setprogname(__libc_shared_globals()->init_progname ?: "<unknown>");
......

如果 argv[0] 为 null, 即 init_progname 为 null,则 __progname 就会被设置为 <unknown>, 可是从实际返回值来看,这个似乎没有被设置上。需要在 emulator 里 printf 一下。目前跟踪打印的结果是在 emulator 上 args.argv[0] 不是 nullptr,而是一个 "",也就是说当我们强制设置 argv[0] 为 NULL 时,__libc_shared_globals()->init_progname 并没有被设置为 NULL。

而 init_progname 这个变量被赋值的地方有两处,

  • 一处在 bionic/libc/bionic/libc_init_static.cpp, 在静态链接程序的初始化中设置
  • 另一处是在 bionic/linker/linker_main.cpp ,动态链接的程序加载 linker 中设置
    然后两种情况下都通过调用 __libc_init_common() -> setprogname() 完成对 __progname 的设置。

因为 run-as 这个程序是动态链接的,所以走的是第二个路径。

测试发现和内核版本处理有关,在我们的 qemu 上测试用的是我们自己的内核,而在 RVI 的 emulator 环境下用的是 RVI 的内核,在我们的环境里换成 RVI 的内核就会复现我们的问题.
仔细对比内核版本发现: pass 的内核版本是 5.10.43,fail 的内核版本是 5.10.110
而在 5.10.110 中 fs/exec.cdo_execveat_common() 中增加了如下一段代码:

	/*
	 * When argv is empty, add an empty string ("") as argv[0] to
	 * ensure confused userspace programs that start processing
	 * from argv[1] won't end up walking envp. See also
	 * bprm_stack_limits().
	 */
	if (bprm->argc == 0) {
		retval = copy_string_kernel("", bprm);
		if (retval < 0)
			goto out_free;
		bprm->argc = 1;
	}

也就是说目前的内核中如果应用传进来的 argv 是空的,内核会默认添加一个 argv[0] = ""
所以如果我们采用较新的内核测试这个 case 是过不了的

检查了一下这部分内容在 5.18 时被正式合入主线分支。

unicornx 任务状态待办的 修改为已完成

登录 后才可以发表评论

状态
负责人
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
参与者(1)
136976 unicornx 1674787217
1
https://gitee.com/aosp-riscv/working-group.git
git@gitee.com:aosp-riscv/working-group.git
aosp-riscv
working-group
working-group

搜索帮助