启动一个新的进程时,如何加入SEAndroid信息seInfo

SEAndroid Zygote

在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. }  
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. {  
  7.     pid_t pid;  
  8.   
  9.     pid = forkAndSpecializeCommon(args, false);  
  10.   
  11.     RETURN_INT(pid);  
  12. }  
/* 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, 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  
#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 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. }  
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 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.    }  
 /**
     * 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。 

 

 

QQ 240136495

http://www.jsqj.cc 军事新闻 爱好者。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值