Android 安全攻防(三): SEAndroid Zygote

转自:http://blog.csdn.net/yiyaaixuexi/article/details/8495695

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

 

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

 

  1. const DalvikNativeMethod dvm_dalvik_system_Zygote[] = {  
  2.     {"nativeFork""()I",  
  3.         Dalvik_dalvik_system_Zygote_fork },  
  4.     { "nativeForkAndSpecialize""(II[II[[ILjava/lang/String;Ljava/lang/String;)I",  
  5.         Dalvik_dalvik_system_Zygote_forkAndSpecialize },  
  6.     { "nativeForkSystemServer""(II[II[[IJJ)I",  
  7.         Dalvik_dalvik_system_Zygote_forkSystemServer },  
  8.     { "nativeExecShell""(Ljava/lang/String;)V",  
  9.         Dalvik_dalvik_system_Zygote_execShell },  
  10.     { NULL, NULL, NULL },  
  11. }  


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

 

 

  1. /* native public static int forkAndSpecialize(int uid, int gid, 
  2. * int[] gids, int debugFlags, String seInfo, String niceName); 
  3. */  
  4. static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args,  
  5. JValue* pResult)  
  6. {  
  7.     pid_t pid;  
  8.   
  9.     pid = forkAndSpecializeCommon(args, false);  
  10.   
  11.     RETURN_INT(pid);  
  12. }  


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

 

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

  1. #ifdef HAVE_SELINUX  
  2.     err = setSELinuxContext(uid, isSystemServer, seInfo, niceName);  
  3.     if (err < 0) {  
  4.         LOGE("cannot set SELinux context: %s\n", strerror(errno));  
  5.         dvmAbort();  
  6.     }  
  7.     free(seInfo);  
  8.     free(niceName);  
  9. #endif  


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

 

 

  1. #ifdef HAVE_SELINUX  
  2. /* 
  3. * Set SELinux security context. 
  4. * 
  5. * Returns 0 on success, -1 on failure. 
  6. */  
  7. static int setSELinuxContext(uid_t uid, bool isSystemServer,  
  8. const char *seInfo, const char *niceName)  
  9. {  
  10. #ifdef HAVE_ANDROID_OS  
  11.     return selinux_android_setcontext(uid, isSystemServer, seInfo, niceName);  
  12. #else  
  13.     return 0;  
  14. #endif  
  15. }  
  16. #endif  



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

 

  1. public class Zygote {  
  2. ...  
  3.     public static int forkAndSpecialize(int uid, int gid, int[] gids,  
  4.             int debugFlags, int[][] rlimits, String seInfo, String niceName) {  
  5.         preFork();  
  6.         int pid = nativeForkAndSpecialize(uid, gid, gids, debugFlags, rlimits, seInfo, niceName);  
  7.         postFork();  
  8.         return pid;  
  9.     }  
  10.   
  11.   
  12.     native public static int nativeForkAndSpecialize(int uid, int gid,  
  13.             int[] gids, int debugFlags, int[][] rlimits, String seInfo, String niceName);  
  14.   
  15.   
  16.     /** 
  17.      * Forks a new VM instance. 
  18.      * @deprecated use {@link Zygote#forkAndSpecialize(int, int, int[], int, int[][])} 
  19.      */  
  20.     @Deprecated  
  21.     public static int forkAndSpecialize(int uid, int gid, int[] gids,  
  22.             boolean enableDebugger, int[][] rlimits) {  
  23.         int debugFlags = enableDebugger ? DEBUG_ENABLE_DEBUGGER : 0;  
  24.         return forkAndSpecialize(uid, gid, gids, debugFlags, rlimits, nullnull);  
  25.     }  
  26. ...  
  27. }  

 

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

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

 

  1. /** 
  2.     * Applies zygote security policy. 
  3.     * Based on the credentials of the process issuing a zygote command: 
  4.     * <ol> 
  5.     * <li> uid 0 (root) may specify --invoke-with to launch Zygote with a 
  6.     * wrapper command. 
  7.     * <li> Any other uid may not specify any invoke-with argument. 
  8.     * </ul> 
  9.     * 
  10.     * @param args non-null; zygote spawner arguments 
  11.     * @param peer non-null; peer credentials 
  12.     * @throws ZygoteSecurityException 
  13.     */  
  14.    private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer,  
  15.            String peerSecurityContext)  
  16.            throws ZygoteSecurityException {  
  17.        int peerUid = peer.getUid();  
  18.   
  19.        if (args.invokeWith != null && peerUid != 0) {  
  20.            throw new ZygoteSecurityException("Peer is not permitted to specify "  
  21.                    + "an explicit invoke-with wrapper command");  
  22.        }  
  23.   
  24.        if (args.invokeWith != null) {  
  25.            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,  
  26.                                                         peerSecurityContext,  
  27.                                                         "zygote",  
  28.                                                         "specifyinvokewith");  
  29.            if (!allowed) {  
  30.                throw new ZygoteSecurityException("Peer is not permitted to specify "  
  31.                    + "an explicit invoke-with wrapper command");  
  32.            }  
  33.        }  
  34.    }  
  35.   
  36.    /** 
  37.     * Applies zygote security policy for SEAndroid information. 
  38.     * 
  39.     * @param args non-null; zygote spawner arguments 
  40.     * @param peer non-null; peer credentials 
  41.     * @throws ZygoteSecurityException 
  42.     */  
  43.    private static void applyseInfoSecurityPolicy(  
  44.            Arguments args, Credentials peer, String peerSecurityContext)  
  45.            throws ZygoteSecurityException {  
  46.        int peerUid = peer.getUid();  
  47.   
  48.        if (args.seInfo == null) {  
  49.            // nothing to check  
  50.            return;  
  51.        }  
  52.   
  53.        if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {  
  54.            // All peers with UID other than root or SYSTEM_UID  
  55.            throw new ZygoteSecurityException(  
  56.                    "This UID may not specify SEAndroid info.");  
  57.        }  
  58.   
  59.        boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,  
  60.                                                     peerSecurityContext,  
  61.                                                     "zygote",  
  62.                                                     "specifyseinfo");  
  63.        if (!allowed) {  
  64.            throw new ZygoteSecurityException(  
  65.                    "Peer may not specify SEAndroid info");  
  66.        }  
  67.   
  68.        return;  
  69.    }  



 

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

 

posted @ 2013-09-26 21:31  清灵阁主  阅读(809)  评论(0编辑  收藏  举报