转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类型的参数:

  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 }, 
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。

  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); 
/* 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:

  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 
#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安全上下文方法实现:

  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 
#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参数传递。

  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. ... 
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中调用。

  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.    } 
 /**
     * 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。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值