总贴 在这里。
支持文件系统隔离
我们管这个叫做文件沙盒。其实android的沙盒是不彻底的,因为sdcard下的路径全部APP共享。 到了android 8,App就算不用外部sdcard也可以放一堆东西,通过FileProvider也可以提供跨应用的数据。但是正如大家诟病的,许多APP还是会申请sdcard的读写权限。
我们在测试的过程中,发现某些安全库,会写死一些边边角角的可读写的地方,去放东西,这个很恶心。
哦,说句题外话,android系统的东西都是放在/data/data
下的,许多奇奇的目录都是符号连接,rm -rf /data/data/*
就可以达到出厂设置的效果。
ok,我们的方案是怎么做的呢,有几个点:
- 要根据上文的instance_no,来新建文件目录
- 在zygote初始化的时候动态mount新建的目录,设置这个目录可读写
- 在kernel中,如果是多开进程的文件访问,都给截获,重新映射到这个mount的目录
instance_no部分上一篇博客说了,mount部分是这样做的:
在zygote的 pid_t pid = fork()
pid != 0
之后
if (access (abs_path, F_OK) < 0) {
ALOGW ("Zg: Target path %s for %s does not exist: err=%d, skip it.", abs_path, source_path, errno);
continue;
}
if (TEMP_FAILURE_RETRY (mount (source_path, abs_path, NULL, MS_BIND, NULL)) < 0) {
ALOGE ("Zg: Failed to mount %s to %s: err=%d", source_path, abs_path, errno);
closedir (app_root);
RuntimeAbort (env);
}
值得一提的是,zygote fork进程之后,通过设置
SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
把linux上的权限给阉割了,这也是为什么su
要在另外一个进程执行的原因(因为zygote 建出来的进程就没有任何权限)
kernel部分,主要是修改syscall部分。就是把open、access等系统调调的时候,获取标识位,看看是不是hook过的,如果是的话,就映射下读取路径。这样的话,/data/data
下的文件路径就被映射到我们上面mount的路径中去了。
kernel/fs/open.c
#ifdef CONFIG_INTERCEPT_FILE_SYSCALLS
/* Lionfore for ML. Sep 11th, 2017 */
if (this_process_should_be_intercepted ()) {
xd_access_syscall_req_t req;
xd_access_syscall_res_t rsp;
res = __filename_absolute_path (dfd, filename, lookup_flags, req.path);
if (res < 0)
goto __trace_syscall; /* Lionfore for ML. Sep 15th, 2017 */
req.hdr.type = XD_ACCESS_SYSCALL_REQ;
req.hdr.len = sizeof req;
req.hdr.pid = current->pid;
req.hdr.app_tag = get_process_inst_no (current);
req.mode = mode;
req.uid = __kuid_val (current_cred ()->euid);
req.gid = __kgid_val (current_cred ()->egid);
rsp.hdr.len = sizeof rsp;
res = intercept_syscall (&req.hdr, &rsp.hdr);
if (res < 0)
goto __trace_syscall; /* Lionfore for ML. Sep 15th, 2017 */
if (rsp.hdr.err < 0) {
res = rsp.hdr.err;
goto __trace_syscall; /* Lionfore for ML. Sep 15th, 2017 */
}
}
#endif
需要注意的是 readlink
这个系统调用也要改,代码在
kernel/fs/namei.c
关于软连接和硬连接的介绍,看这里
小结一下。上面介绍了通过zygote
和 kernel的系统调用
的修改。在打开新应用的时候动态创建目录,动态映射目录,做到了文件系统隔离的效果。
其实在android8之后,规范的写android,机会可以不用用到外部存储,所以应用里面的简单沙盒其实是够用的。
不够用的时候,可能是出于 唯一标识 && 安全 方面的考量。
- 比如我在每个碎片话的系统(mi,huawei、魅族)在一些边边角角可读可写的目录,用户不会清理到的地方,放一点自定义文件,存着key,然后
全家桶
都用这个key来作为用户标识。 - 如果在两个不同的账号下同时读到同一个key,那就是多开了:)