转Android 安全攻防(三): SEAndroid Zygote执行用户态许可检查控制

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,也正是在此动的手脚。


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

[cpp] view plain copy print ?
  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 }, 

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

[cpp] view plain copy print ?
  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.     pid_t pid; 
  7.  
  8.     pid = forkAndSpecializeCommon(args, false); 
  9.  
  10.     RETURN_INT(pid); 

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

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

[cpp] view plain copy print ?
  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安全上下文方法实现:

[cpp] view plain copy print ?
  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,constchar *niceName) 
  9. #ifdef HAVE_ANDROID_OS 
  10.     return selinux_android_setcontext(uid, isSystemServer, seInfo, niceName); 
  11. #else 
  12.     return 0; 
  13. #endif 
  14. #endif 


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

[java] view plain copy print ?
  1. public class Zygote { 
  2. ... 
  3.     public staticint 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 publicstaticint 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 staticint 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,null,null); 
  25.     } 
  26. ... 


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

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

[java] view plain copy print ?
  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 staticvoid 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 staticvoid 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。

你可能感兴趣的:(转Android 安全攻防(三): SEAndroid Zygote执行用户态许可检查控制)