您的位置:首页 > 移动开发 > Android开发

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

2013-01-20 16:12 393 查看
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 plaincopyprint?

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


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。

[cpp]
view plaincopyprint?

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


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

[cpp]
view plaincopyprint?

#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 

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

[cpp]
view plaincopyprint?

#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,constchar *niceName) 

#ifdef HAVE_ANDROID_OS 

    return selinux_android_setcontext(uid, isSystemServer, seInfo, niceName); 
#else 
    return 0; 
#endif 

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

[java]
view plaincopyprint?

public class Zygote { 
... 
    public staticint 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 publicstaticint 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 staticint 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); 
    } 
... 


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

[java]
view plaincopyprint?

/**
    * 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 staticvoid 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 staticvoid 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; 
   } 

/**
* 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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: