Andriod

Android系统编译之系统权限

2021-02-08  本文已影响0人  过期的薯条

1.引言

android system/etc 中有很多配置文件,例如白名单,例如system-private 权限区别,还例如 如何配置aapp的内存。这些都是懵逼的。抱着好奇心态,决定深入进去看看一般是怎么设置的。参考链接:https://blog.csdn.net/superkris/article/details/7709504/

2.Android的权限规则

2.1 基于UserID的进程级别的安全机制

进程有独立的地址空间,进程与进程间默认是不能互相访问的,Android通过为每一个apk分配唯一的linux userID来实现,名称为"app_"加一个数字,比如app_43不同的UserID,运行在不同的进程,所以apk之间默认便不能相互访问。

Android提供了如下的一种机制,可以使两个apk打破前面讲的这种壁垒。 在AndroidManifest.xml中利用sharedUserId属性给不同的package分配相同的userID,通过这样做,两个package可以被当做同一个程序, 系统会分配给两个程序相同的UserID。当然,基于安全考虑,两个apk需要相同的签名,否则没有验证也就没有意义了

2.2 默认apk生成的数据对外是不可见的

实现方法是:Android会为程序存储的数据分配该程序的UserID。借助于Linux严格的文件系统访问权限,便实现了apk之间不能相互访问似有数据的机制。 例:我的应用创建的一个文件,默认权限如下,可以看到只有UserID为app_21的程序才能读写该文件

2.3 root权限和system权限

frameworks\base\core\res\AndroidManifest.xml 定义了各种广播,普通权限,危险权限,特权权限:

<!-- Allows notifications to be colorized
     <p>Not for use by third-party applications. @hide -->
<permission android:name="android.permission.USE_COLORIZED_NOTIFICATIONS"
            android:protectionLevel="signature|setup" /> //setting 具备的

<!-- Allows access to keyguard secure storage.  Only allowed for system processes.
    @hide -->
<permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
    android:protectionLevel="signature" />  //系统签名

<!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
<permission android:name="android.permission.MANAGE_FINGERPRINT"
    android:protectionLevel="signature|privileged" />  //系统签名且还需要在system/priv-app 下

<!-- Allows an app to reset fingerprint attempt counter. Reserved for the system. @hide -->
<permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
    android:protectionLevel="signatureorsystem " />  //系统签名且还得是系统app(system/priv-app 或system/app)

Android 权限分成四类:

应用场景1:
前提:app 系统签过名且放置于system/app/下
操作: 调用 Settings.System.putInt
现象:
Caused by: java.lang.IllegalArgumentException: You cannot keep your settings in the secure settings.
解决方案: 将app 防止于system/priv-app下
问题: 为什么放置于system/priv-app就解决了问题呢?

源码分析:putInt方法最终会调用: enforceRestrictedSystemSettingsMutationForCallingPackage 方法

1858    private void enforceRestrictedSystemSettingsMutationForCallingPackage(int operation,
1859            String name, int userId) {
1860        // System/root/shell can mutate whatever secure settings they want.
1861        final int callingUid = Binder.getCallingUid();
1862        final int appId = UserHandle.getAppId(callingUid);
1863        if (appId == android.os.Process.SYSTEM_UID
1864                || appId == Process.SHELL_UID
1865                || appId == Process.ROOT_UID) {
1866            return;
1867        }
1868
1869        switch (operation) {
1870            case MUTATION_OPERATION_INSERT:
1871                // Insert updates.
1872            case MUTATION_OPERATION_UPDATE: {
1873                if (Settings.System.PUBLIC_SETTINGS.contains(name)) {
1874                    return;
1875                }
1876
1877                // The calling package is already verified.
1878                PackageInfo packageInfo = getCallingPackageInfoOrThrow(userId);
1879
1880                // Privileged apps can do whatever they want. 只要是特权应用,就可以直接插入数据
1881                if ((packageInfo.applicationInfo.privateFlags
1882                        & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
1883                    return;
1884                }
1885                // 检查是否具备插入数据的资格,没得就会抛出异常
1886                warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
1887                        packageInfo.applicationInfo.targetSdkVersion, name);
1888            } break;
18
1910    }
应用场景2:
前提:国内 app 采用系统签名,放在/system/priv-app/下,但是没有添加 android:sharedUserId="android.uid.system
操作:app本身是一个service,需要有读写权限
现象:app中直接进行创建/删除文件,报错,提示没得读写权限
解决方案:

Y:\aosp\device\google\marlin\default-permissions.xml:

<exceptions>
    <exception package="com.verizon.mips.services">
        <permission name="android.permission.PROCESS_OUTGOING_CALLS" fixed="false"/>
        <permission name="android.permission.READ_PHONE_STATE" fixed="false"/>
        <permission name="android.permission.RECEIVE_SMS" fixed="false"/>
    </exception>
</exceptions>

default-permissions 配置文件会在第一次开机的时候加载。所以假如直接更改开发版中的default-permissions。需要格式化开发板,恢复出厂模式

应用场景3:
前提:国内 app 采用系统签名,放在/system/priv-app/下,但是没有添加 android:sharedUserId="android.uid.system且android:persistent="false"
操作: 代码中直接使用startService启动服务
现象:
Not allowed to start service Intent { flg=0x1000000 cmp=packagename/.servicename (has extras) }: app is in background uid UidRecord{52db80 u2357s1000 TRNB bg:+2m42s199ms idle procs:3 seq(0,0,0)}
问题: app系统签名且置于/system/app/下 但是为啥startService 还报错呢?且为什么加上android:persistent="true"就ok了呢
解答:

startService 启动服务流程中,有一个方法appServicesRestrictedInBackgroundLocked

 int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
    // Persistent app?
        if (mPackageManagerInt.isPackagePersistent(packageName)) {
            if (DEBUG_BACKGROUND_CHECK) {
                Slog.i(TAG, "App " + uid + "/" + packageName
                        + " is persistent; not restricted in background");
            }
            return ActivityManager.APP_START_MODE_NORMAL;
        }
        // Non-persistent but background whitelisted?
        if (uidOnBackgroundWhitelist(uid)) {
            if (DEBUG_BACKGROUND_CHECK) {
                Slog.i(TAG, "App " + uid + "/" + packageName
                        + " on background whitelist; not restricted in background");
            }
            return ActivityManager.APP_START_MODE_NORMAL;
        }
        // Is this app on the battery whitelist?
        if (isOnDeviceIdleWhitelistLocked(uid, /*allowExceptIdleToo=*/ false)) {
            if (DEBUG_BACKGROUND_CHECK) {
                Slog.i(TAG, "App " + uid + "/" + packageName
                        + " on idle whitelist; not restricted in background");
            }
            return ActivityManager.APP_START_MODE_NORMAL;
        }
        // None of the service-policy criteria apply, so we apply the common criteria
        return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk);
    }
应用场景4:
前提:AndroidManifest 中添加android:sharedUserId="android.uid.system"
操作:代码中调用安装apk的代码
现象:弹出如下所示的dialog
问题:为什么会弹出这个框?如何解决这个问题
第一个问题解答:ActivityManagerService#checkGrantUriPermissionLocked
        if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) { 
9715            if ("com.android.settings.files".equals(grantUri.uri.getAuthority())
9716                    || SystemConfig.getInstance().getAuthoriesInPreloadedApks().contains(
9717                    grantUri.uri.getAuthority())) {
9718                // Exempted authority for
9719                // 1. cropping user photos and sharing a generated license html
9720                //    file in Settings app
9721                // 2. sharing a generated license html file in TvSettings app
9722            } else {
9723                Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission"
9724                        + " grant to " + grantUri + "; use startActivityAsCaller() instead");
9725                return -1;
9726            }
9727        }

callUid为SYSTEM_UID,且不满足俩个if 则return -1 ,于是就出现上述的安装失败情况。

解决方式有俩种:

上一篇下一篇

猜你喜欢

热点阅读