Android 安全攻防(三): SEAndroid Zygote


在Android系统中,所有的应用程序进程,以及系统服务进程SystemServer都是由Zygote孕育fork出来的。 Zygote的native获取主要研究dalvik/vm/native/dalvik_system_Zygote.cpp,SEAndroid管控应用程序资源存取权限,对于整个dalvik,也正是在此动的手脚。


首先看抛出的DalvikNativeMethoddvm_dalvik_system_Zygote,与原生Android相比,SEAndroid 在nativeForkAndSpecialize 增加传入了两个String类型的参数:

const DalvikNativeMethod dvm_dalvik_system_Zygote[] = {    {"nativeFork", "()I",        Dalvik_dalvik_system_Zygote_fork },    { "nativeForkAndSpecialize", "(II[II[[ILjava/lang/String;Ljava/lang/String;)I",        Dalvik_dalvik_system_Zygote_forkAndSpecialize },    { "nativeForkSystemServer", "(II[II[[IJJ)I",        Dalvik_dalvik_system_Zygote_forkSystemServer },    { "nativeExecShell", "(Ljava/lang/String;)V",        Dalvik_dalvik_system_Zygote_execShell },    { NULL, NULL, NULL },}

那么这两个参数是什么呢?继续追一下 forkAndSpecialize。

/* native public static int forkAndSpecialize(int uid, int gid,* int[] gids, int debugFlags, String seInfo, String niceName);*/static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args,JValue* pResult){    pid_t pid;    pid = forkAndSpecializeCommon(args, false);    RETURN_INT(pid);}

可以看到,增加传入的2个参数一个是seInfo,用于定义新进程的SEAndroid信息,一个是niceName,用于定义新进程名。

在static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)中,其中SEAndroid加入了设置SELinux安全上下文代码段,seInfo和niceName:

#ifdef HAVE_SELINUX    err = setSELinuxContext(uid, isSystemServer, seInfo, niceName);    if (err < 0) {        LOGE("cannot set SELinux context: %s\n", strerror(errno));        dvmAbort();    }    free(seInfo);    free(niceName);#endif

其中设置SELinux安全上下文方法实现:

#ifdef HAVE_SELINUX/** Set SELinux security context.** Returns 0 on success, -1 on failure.*/static int setSELinuxContext(uid_t uid, bool isSystemServer,const char *seInfo, const char *niceName){#ifdef HAVE_ANDROID_OS    return selinux_android_setcontext(uid, isSystemServer, seInfo, niceName);#else    return 0;#endif}#endif


再往上一层就到了libcore/dalvik/src/main/java/dalvik/system/Zygote.java ,Zygote类的封装,对应forkAndSpecialize方法中添加seInfo和niceName参数传递。

public class Zygote {...    public static int forkAndSpecialize(int uid, int gid, int[] gids,            int debugFlags, int[][] rlimits, String seInfo, String niceName) {        preFork();        int pid = nativeForkAndSpecialize(uid, gid, gids, debugFlags, rlimits, seInfo, niceName);        postFork();        return pid;    }    native public static int nativeForkAndSpecialize(int uid, int gid,            int[] gids, int debugFlags, int[][] rlimits, String seInfo, String niceName);    /**     * Forks a new VM instance.     * @deprecated use {@link Zygote#forkAndSpecialize(int, int, int[], int, int[][])}     */    @Deprecated    public static int forkAndSpecialize(int uid, int gid, int[] gids,            boolean enableDebugger, int[][] rlimits) {        int debugFlags = enableDebugger ? DEBUG_ENABLE_DEBUGGER : 0;        return forkAndSpecialize(uid, gid, gids, debugFlags, rlimits, null, null);    }...}


Android应用程序启动流程不再赘述,当建立了ZygoteConnection对象用于socket连接后,接下来就是调用ZygoteConnection.runOnce函数进一步处理了。

源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java,其中,SEAndroid增加zygote安全策略函数,在runOnce中调用。

 /**     * Applies zygote security policy.     * Based on the credentials of the process issuing a zygote command:     * <ol>     * <li> uid 0 (root) may specify --invoke-with to launch Zygote with a     * wrapper command.     * <li> Any other uid may not specify any invoke-with argument.     * </ul>     *     * @param args non-null; zygote spawner arguments     * @param peer non-null; peer credentials     * @throws ZygoteSecurityException     */    private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer,            String peerSecurityContext)            throws ZygoteSecurityException {        int peerUid = peer.getUid();        if (args.invokeWith != null && peerUid != 0) {            throw new ZygoteSecurityException("Peer is not permitted to specify "                    + "an explicit invoke-with wrapper command");        }        if (args.invokeWith != null) {            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,                                                         peerSecurityContext,                                                         "zygote",                                                         "specifyinvokewith");            if (!allowed) {                throw new ZygoteSecurityException("Peer is not permitted to specify "                    + "an explicit invoke-with wrapper command");            }        }    }    /**     * Applies zygote security policy for SEAndroid information.     *     * @param args non-null; zygote spawner arguments     * @param peer non-null; peer credentials     * @throws ZygoteSecurityException     */    private static void applyseInfoSecurityPolicy(            Arguments args, Credentials peer, String peerSecurityContext)            throws ZygoteSecurityException {        int peerUid = peer.getUid();        if (args.seInfo == null) {            // nothing to check            return;        }        if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {            // All peers with UID other than root or SYSTEM_UID            throw new ZygoteSecurityException(                    "This UID may not specify SEAndroid info.");        }        boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,                                                     peerSecurityContext,                                                     "zygote",                                                     "specifyseinfo");        if (!allowed) {            throw new ZygoteSecurityException(                    "Peer may not specify SEAndroid info");        }        return;    }


理所当然的,在启动一个新的进程时,frameworks/base/core/java/android/os/Process.java中也会加入SEAndroid信息seInfo。






更多相关文章

  1. 面试例题1:如何在android应用程序的窗口上绘制图形
  2. Android深入浅出系列课程---Lesson3 AAF110427_进程生命周期Proc
  3. Android进程so注入Hook java方法
  4. 用Eclipse开发第一个Android应用程序HelloWorld
  5. Building Android Apps with AWS 使用AWS构建Android应用程序 Ly
  6. ui布局参数设置
  7. android开发学习笔记(1)我的第一个android应用程序
  8. Android之应用进程模型

随机推荐

  1. 解决mysql创建数据库后出现:Access denied
  2. 解决MySQL 5.7.9版本sql_mode=only_full_
  3. mysql5.7.18.zip免安装版本配置教程(windo
  4. Mysql免安装版设置密码教程详解
  5. mysql innodb 异常修复经验分享
  6. Mysql中几种插入效率的实例对比
  7. 一步步教你配置MySQL远程访问
  8. MySQL 5.7.18 release版安装指南(含有bin
  9. 利用MySQL统计一列中不同值的数量方法示
  10. centos 6.5下 mysql-community-server. 5