1 Android 安全机制概述
Android安全机制在三个方面来体现。分别从kernel,dalvik, framework三个层次管理。在kernel方面,android系统引入SE linux;在dalvik方面引入沙箱隔离技术;在framework层面引入应用权限控制。详细如下:
A. SE Linux:Linux内核层的安全增强,是一套独立于传统Linux权限访问控制的强制性权限控制机制。Google已将这套机制移植到Android内核,增强了内核的安全性。
B. 沙箱隔离:沙箱是基于不同应用之间User ID的不同而实现的,其本质是Linux对于不同用户间访问权限的隔离。每个APP和系统进程都被分配唯一并且固定的User Id,这个uid与内核层进程的uid对应。每个APP在各自独立的Dalvik虚拟机中运行,拥有独立的地址空间和资源。运行于Dalvik虚拟机中的 进程必须依托内核层Linux进程而存在,因此Android使用Dalvik虚拟机和Linux的文件访问控制来实现沙箱机制。
C. 应用权限控制:Android应用需要申请相应的权限才能访问系统的资源和信息,大多数权限由Android框架层的API进行控制,另一部分权限映射到应用所在的Group ID上,由Linux内核做出控制。
2 UID,GID,GIDS说明与设置(android L)
2.1 UID, GID, GIDS说明
Android 的权限分离的基础是建立在 Linux 已有的 uid 、 gid 、 gids 基础上的 。
UID: Android 在安装一个应用程序,就会为它分配一个 uid。
GID: 对于普通应用程序来说, gid 等于uid。
GIDS: gids 是由框架在 Application 安装过程中生成,与 Application 申请的具体权限相关。 如果 Application 申请的相应的 permission 被 granted ,而且 中有对应的 gid s , 那么 这个 Application 的 gids 中将 包含这个 gid s
2.2 UID, GID, GIDS 设置
1 Android启动某一个App应用,创建进程:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs)
{
........
int uid = app.uid;
........
permGids = pm.getPackageGids(app.info.packageName);
........
System.arraycopy(permGids, 0, gids, 2, permGids.length);
........
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo,
requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
........
}
frameworks/base/core/java/android/os/Process.java
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String[] zygoteArgs) {
........
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, zygoteArgs);
........
}
private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String[] extraArgs)
throws ZygoteStartFailedEx {
........
argsForZygote.add("--runtime-init");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
........
sb.append("--setgroups=");
........
argsForZygote.add(sb.toString());
........
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
frameworks/base/core/java/com/android/internal/os/Zygote.java
public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
String instructionSet, String appDataDir) {
........
int pid = nativeForkAndSpecialize(
uid, gid, gids, debugFlags, rlimits,
mountExternal, seInfo, niceName, fdsToClose,
instructionSet, appDataDir);
........
}
frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
jint debug_flags, jobjectArray javaRlimits,
jlong permittedCapabilities,
jlong effectiveCapabilities,
jint mount_external,
jstring java_se_info, jstring java_se_name,
bool is_system_server, jintArray fdsToClose,
jstring instructionSet, jstring dataDir) {
........
pid_t pid = fork();
........
SetGids(env, javaGids);
........
int rc = setresgid(gid, gid, gid);
........
rc = setresuid(uid, uid, uid);
........
}
创建进程完毕,同时该进程设置了相应的uid, gid, gids
3 app权限信息的加载过程
所有App权限信息保存在/data/system/packages.xml。 系统启动后,会检查/data/system/packages.xml 是否存在。这个文件是在解析 apk 时由writeLP()创建的,里面记录了系统的 permissions,以及每个 apk name, codePath, flags, ts, version, uesrid 等信息,这些信息主要通过 apk 的AndroidManifest.xml 解析获取,解析完 apk 后将更新信息写入这个文件并保存到 flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有 apk升级,安装或删除时会更新这个文件。
3.1 SystemServer中启动PackageManagerService
frameworks/base/services/java/com/android/server/SystemServer.java
mPackageManagerService = PackageManagerService.main(mSystemContext,
mInstaller,mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
mSettings = new Settings(context);
frameworks/base/services/core/java/com/android/server/pm/Settings.java
mSettingsFilename = new File(mSystemDir, "packages.xml");
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
mPackageListFilename = new File(mSystemDir, "packages.list");
FileUtils.setPermissions(mPackageListFilename, 0660,
SYSTEM_UID, PACKAGE_INFO_GID);
读取/data/目录下文件:
/data/packages.xml, /data/packages.list
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
@Override
public int[] getPackageGids(String packageName) {
........
PackageParser.Package p = mPackages.get(packageName);
........
final PackageSetting ps = (PackageSetting)p.mExtras;
return ps.getGids();
........
}
3.2 安装新应用权限信息的写入过程
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
a. installNewPackageLI()
b. PackageParser.Package newPackage = scanPackageLI(pkg,
parseFlags, scanFlags, System.currentTimeMillis(), user);
c. updateSettingsLI(newPackage, installerPackageName, null, null, res);
d. mSettings.writeLPr();
将解析的每个 apk 的信息保存到 packages.xml 和 packages.list 文件里,