Android安全攻防(三):SEAndroid Zygote


Android安全攻防(三):SEAndroid Zygote
Androidシステムでは、すべてのアプリケーションプロセス、およびシステムサービスプロセスSystemServerがZygoteによってforkを生み出しています.Zygoteのnative取得主な研究dalvik/vm/native/dalvik_system_Zygote.cpp,SEAndroidはアプリケーションリソースアクセス権限を管理し,dalvik全体に対しても,ここで動作する手足である.
まずは投げ出したDalvikNativeMethod dvm_を見てdalvik_system_Zygoteは、オリジナルAndroidと比較して、nativeForkAndSpecializeで2つの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 },
}

では、この2つのパラメータは何ですか?追いかけ続ける
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つのパラメータを追加すると、1つはseInfoであり、新しいプロセスを定義するSEAndroid情報であり、1つはniceNameであり、新しいプロセス名を定義するために使用されることがわかります.
static pid_t forkAndSpecializeCommon(const u 4*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
", 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が入ります.