不一样的SYSTEM APP(SYSTEM flag和system_prop区别)

1.问题引入

在Android开发中,
1)Framework中PackageManager扫包后,会把app归类为SYSTEM, SYSTEM_EXT, PRIVILEGED 类别.

2)同样的, SeAndroid也会把APP归类程platform_app, system_app, untrusted_app(甚至还有其他,mediaprovider,gmscore_app).

flag SYSTEM和system_app我们都称之为系统app.
但是他们不是同一个概念的"系统app".

2.PackageSettings flag SYSTEM

dumpsys package com.android.systemui为例, 输出如下:

Packages:
  Package [com.android.systemui] (d6f33bf):
    appId=10187
    sharedUser=SharedUserSetting{4058ad4 android.uid.systemui/10187}
    pkg=Package{aa0e47d com.android.systemui}
    codePath=/system_ext/priv-app/SystemUI
    resourcePath=/system_ext/priv-app/SystemUI
    legacyNativeLibraryDir=/system_ext/priv-app/SystemUI/lib
    extractNativeLibs=true
    primaryCpuAbi=arm64-v8a
    secondaryCpuAbi=null
    cpuAbiOverride=null
    versionCode=1410014 minSdk=33 targetSdk=34
    minExtensionVersions=[]
    versionName=14.00.14
    usesNonSdkApi=false
    splits=[base]
    apkSigningVersion=3
    flags=[ SYSTEM HAS_CODE PERSISTENT ]
    privateFlags=[ PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION ALLOW_AUDIO_PLAYBACK_CAPTURE DEFAULT_TO_DEVICE_PROTECTED_STORAGE DIRECT_BOOT_AWARE PARTIALLY_DIRECT_BOOT_AWARE PRIVILEGED SYSTEM_EXT PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING ]
    forceQueryable=false

根据输出可以看到两个重要的flag,分别为flags和privateFlags.其中flags其中标签为SYSTEM和PERSISTENT, 而privateFlags其中两个输出为PRIVILEGED/SYSTEM_EXT.

对应的输出代码如下:

    @NeverCompile // Avoid size overhead of debugging code.
    void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag,
            ArraySet<String> permissionNames, PackageSetting ps,
            LegacyPermissionState permissionsState, SimpleDateFormat sdf, Date date,
            List<UserInfo> users, boolean dumpAll, boolean dumpAllComponents) {
        AndroidPackage pkg = ps.getPkg();
        // 省略好多

        if (pkg != null) {
            pw.print(prefix); pw.print("  versionName="); pw.println(pkg.getVersionName());
            pw.print(prefix); pw.print("  usesNonSdkApi="); pw.println(pkg.isUsesNonSdkApi());
            pw.print(prefix); pw.print("  splits="); dumpSplitNames(pw, pkg); pw.println();
            final int apkSigningVersion = pkg.getSigningDetails().getSignatureSchemeVersion();
            pw.print(prefix); pw.print("  apkSigningVersion="); pw.println(apkSigningVersion);
            pw.print(prefix); pw.print("  flags=");
            printFlags(pw, PackageInfoUtils.appInfoFlags(pkg, ps), FLAG_DUMP_SPEC); pw.println();
            int privateFlags = PackageInfoUtils.appInfoPrivateFlags(pkg, ps);
            if (privateFlags != 0) {
                pw.print(prefix); pw.print("  privateFlags="); printFlags(pw,
                        privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
            }
            if (pkg.hasPreserveLegacyExternalStorage()) {
                pw.print(prefix); pw.print("  hasPreserveLegacyExternalStorage=true");
                pw.println();
            }
            pw.print(prefix); pw.print("  forceQueryable=");
            pw.print(ps.getPkg().isForceQueryable());
            if (ps.isForceQueryableOverride()) {
                pw.print(" (override=true)");
            }
static void printFlags(PrintWriter pw, int val, Object[] spec) {
    pw.print("[ ");
    for (int i=0; i<spec.length; i+=2) {
        int mask = (Integer)spec[i];
        if ((val & mask) != 0) {
            pw.print(spec[i+1]);
            pw.print(" ");
        }
    }
    pw.print("]");
}

从上可知是PackageManagerService扫包解析后缓存在PackageSettings中的相关状态值记录,用于区分各类APP.

  1. FLAG_DUMP_SPEC
    在这里插入图片描述
  2. PRIVATE_FLAG_DUMP_SPEC
    在这里插入图片描述

从上可知,输出来源于和这些flag与运算后转换成对应的字串输出.
再看ApplicationInfo中的定义:
[1] FLAG_SYSTEM
在这里插入图片描述
注意表述,只要是预装在System镜像里边的即表示该APP为SYSTEM APP.

再对照着下边几个FLAG来看,
在这里插入图片描述

发现如果APP预制在OEM/ VENDOR/PRODUCT/SYSTEM_EXT分区,都会分别别打上对应的PRIVATE_FLAG_DUMP_SPEC标签.
以我自用的Android14真机举例:
/product/app/Ether
在这里插入图片描述

/product/priv-app/OppoGallery2
在这里插入图片描述

/system_ext/app/OTA/OTA.apk
在这里插入图片描述

/vendor/overlay/WifiResTarget_mainline.apk
在这里插入图片描述
/data/app/OppoCompass2
在这里插入图片描述

从以上可知,在product/system_ext/system/vendor/oem分区的都带FLAG_SYSTEM. 而可卸载的/data分区的不带(即便是OPPO预装的).

oem的例子:
/oem/priv-app/SearchSelector
在这里插入图片描述
因此需要注意ApplicationInfo中的注释,一个是is installed in the device’s system image, 一个是is pre-installed on the xxx partition of the system image.

因此, 暂且可以简单理解为非data分区的都可以是SYSTEM app.
如果是自安装APP(安装在/data分区), 即使是平台签名,也不是FLAG_SYSTEM.
在这里插入图片描述

3.seAndroid system_app

Android 默认是回来其enforcing模式的. 规则中会把各类app分门别类,从而达到其对各分区资源的操作访问做权限管理.
http://aospxref.com/android-13.0.0_r3/xref/system/sepolicy/private/mac_permissions.xml

<?xml version="1.0" encoding="utf-8"?>
<policy>

<!--

    * A signature is a hex encoded X.509 certificate or a tag defined in
      keys.conf and is required for each signer tag. The signature can
      either appear as a set of attached cert child tags or as an attribute.
    * A signer tag must contain a seinfo tag XOR multiple package stanzas.
    * Each signer/package tag is allowed to contain one seinfo tag. This tag
      represents additional info that each app can use in setting a SELinux security
      context on the eventual process as well as the apps data directory.
    * seinfo assignments are made according to the following rules:
      - Stanzas with package name refinements will be checked first.
      - Stanzas w/o package name refinements will be checked second.
      - The "default" seinfo label is automatically applied.

    * valid stanzas can take one of the following forms:

     // single cert protecting seinfo
     <signer signature="@PLATFORM" >
       <seinfo value="platform" />
     </signer>

     // multiple certs protecting seinfo (all contained certs must match)
     <signer>
       <cert signature="@PLATFORM1"/>
       <cert signature="@PLATFORM2"/>
       <seinfo value="platform" />
     </signer>

     // single cert protecting explicitly named app
     <signer signature="@PLATFORM" >
       <package name="com.android.foo">
         <seinfo value="bar" />
       </package>
     </signer>

     // multiple certs protecting explicitly named app (all certs must match)
     <signer>
       <cert signature="@PLATFORM1"/>
       <cert signature="@PLATFORM2"/>
       <package name="com.android.foo">
         <seinfo value="bar" />
       </package>
     </signer>
-->

    <!-- Platform dev key in AOSP -->
    <signer signature="@PLATFORM" >
      <seinfo value="platform" />
    </signer>

    <!-- Sdk Sandbox key -->
    <signer signature="@SDK_SANDBOX" >
      <seinfo value="sdk_sandbox" />
    </signer>

    <!-- Bluetooth key in AOSP -->
    <signer signature="@BLUETOOTH" >
      <seinfo value="bluetooth" />
    </signer>

    <!-- Media key in AOSP -->
    <signer signature="@MEDIA" >
      <seinfo value="media" />
    </signer>

    <signer signature="@NETWORK_STACK" >
      <seinfo value="network_stack" />
    </signer>
</policy>

以上定义了signer和seinfo之间的对应关系.
http://aospxref.com/android-13.0.0_r3/xref/system/sepolicy/private/seapp_contexts

关键部分:

user=_app seinfo=platform name=com.android.traceur domain=traceur_app type=app_data_file levelFrom=all
user=system seinfo=platform domain=system_app type=system_app_data_file
user=_app seinfo=platform domain=platform_app type=app_data_file levelFrom=user
user=_app isPrivApp=true domain=priv_app type=privapp_data_file levelFrom=user
user=_app isPrivApp=true name=com.google.android.providers.media.module domain=mediaprovider_app type=privapp_data_file levelFrom=all

全部内容如下:

# The entries in this file define how security contexts for apps are determined.
# Each entry lists input selectors, used to match the app, and outputs which are
# used to determine the security contexts for matching apps.
#
# Input selectors:
#       isSystemServer (boolean)
#       isEphemeralApp (boolean)
#       user (string)
#       seinfo (string)
#       name (string)
#       isPrivApp (boolean)
#       minTargetSdkVersion (unsigned integer)
#       fromRunAs (boolean)
#
# All specified input selectors in an entry must match (i.e. logical AND).
# An unspecified string or boolean selector with no default will match any
# value.
# A user, or name string selector that ends in * will perform a prefix
# match.
# String matching is case-insensitive.
# See external/selinux/libselinux/src/android/android_platform.c,
# seapp_context_lookup().
#
# isSystemServer=true only matches the system server.
# An unspecified isSystemServer defaults to false.
# isEphemeralApp=true will match apps marked by PackageManager as Ephemeral
# user=_app will match any regular app process.
# user=_isolated will match any isolated service process.
# user=_sdksandbox will match sdk sandbox process for an app.
# Other values of user are matched against the name associated with the process
# UID.
# seinfo= matches aginst the seinfo tag for the app, determined from
# mac_permissions.xml files.
# The ':' character is reserved and may not be used in seinfo.
# name= matches against the package name of the app.
# isPrivApp=true will only match for applications preinstalled in
#       /system/priv-app.
# minTargetSdkVersion will match applications with a targetSdkVersion
#       greater than or equal to the specified value. If unspecified,
#       it has a default value of 0.
# fromRunAs=true means the process being labeled is started by run-as. Default
# is false.
#
# Precedence: entries are compared using the following rules, in the order shown
# (see external/selinux/libselinux/src/android/android_platform.c,
# seapp_context_cmp()).
#       (1) isSystemServer=true before isSystemServer=false.
#       (2) Specified isEphemeralApp= before unspecified isEphemeralApp=
#             boolean.
#       (3) Specified user= string before unspecified user= string;
#             more specific user= string before less specific user= string.
#       (4) Specified seinfo= string before unspecified seinfo= string.
#       (5) Specified name= string before unspecified name= string;
#             more specific name= string before less specific name= string.
#       (6) Specified isPrivApp= before unspecified isPrivApp= boolean.
#       (7) Higher value of minTargetSdkVersion= before lower value of
#              minTargetSdkVersion= integer. Note that minTargetSdkVersion=
#              defaults to 0 if unspecified.
#       (8) fromRunAs=true before fromRunAs=false.
# (A fixed selector is more specific than a prefix, i.e. ending in *, and a
# longer prefix is more specific than a shorter prefix.)
# Apps are checked against entries in precedence order until the first match,
# regardless of their order in this file.
#
# Duplicate entries, i.e. with identical input selectors, are not allowed.
#
# Outputs:
#       domain (string)
#       type (string)
#       levelFrom (string; one of none, all, app, or user)
#       level (string)
#
# domain= determines the label to be used for the app process; entries
# without domain= are ignored for this purpose.
# type= specifies the label to be used for the app data directory; entries
# without type= are ignored for this purpose. The label specified must
# have the app_data_file_type attribute.
# levelFrom and level are used to determine the level (sensitivity + categories)
# for MLS/MCS.
# levelFrom=none omits the level.
# levelFrom=app determines the level from the process UID.
# levelFrom=user determines the level from the user ID.
# levelFrom=all determines the level from both UID and user ID.
#
# levelFrom=user is only supported for _app or _isolated UIDs.
# levelFrom=app or levelFrom=all is only supported for _app UIDs.
# level may be used to specify a fixed level for any UID.
#
# For backwards compatibility levelFromUid=true is equivalent to levelFrom=app
# and levelFromUid=false is equivalent to levelFrom=none.
#
#
# Neverallow Assertions
# Additional compile time assertion checks for the rules in this file can be
# added as well. The assertion
# rules are lines beginning with the keyword neverallow. Full support for PCRE
# regular expressions exists on all input and output selectors. Neverallow
# rules are never output to the built seapp_contexts file. Like all keywords,
# neverallows are case-insensitive. A neverallow is asserted when all key value
# inputs are matched on a key value rule line.
#

# only the system server can be assigned the system_server domains
neverallow isSystemServer=false domain=system_server
neverallow isSystemServer=false domain=system_server_startup
neverallow isSystemServer="" domain=system_server
neverallow isSystemServer="" domain=system_server_startup

# system domains should never be assigned outside of system uid
neverallow user=((?!system).)* domain=system_app
neverallow user=((?!system).)* type=system_app_data_file

# any non priv-app with a non-known uid with a specified name should have a specified
# seinfo
neverallow user=_app isPrivApp=false name=.* seinfo=""
neverallow user=_app isPrivApp=false name=.* seinfo=default

# neverallow shared relro to any other domain
# and neverallow any other uid into shared_relro
neverallow user=shared_relro domain=((?!shared_relro).)*
neverallow user=((?!shared_relro).)* domain=shared_relro

# neverallow non-isolated uids into isolated_app domain
# and vice versa
neverallow user=_isolated domain=((?!isolated_app).)*
neverallow user=((?!_isolated).)* domain=isolated_app

# uid shell should always be in shell domain, however non-shell
# uid's can be in shell domain
neverallow user=shell domain=((?!shell).)*

# only the package named com.android.shell can run in the shell domain
neverallow domain=shell name=((?!com\.android\.shell).)*
neverallow user=shell name=((?!com\.android\.shell).)*

# Ephemeral Apps must run in the ephemeral_app domain
neverallow isEphemeralApp=true domain=((?!ephemeral_app).)*

isSystemServer=true domain=system_server_startup

# sdksandbox must run in the sdksandbox domain
neverallow name=com.android.sdksandbox domain=((?!sdk_sandbox).)*

user=_app seinfo=platform name=com.android.traceur domain=traceur_app type=app_data_file levelFrom=all
user=_app isPrivApp=true name=com.android.remoteprovisioner domain=remote_prov_app type=app_data_file levelFrom=all
user=system seinfo=platform domain=system_app type=system_app_data_file
user=bluetooth seinfo=bluetooth domain=bluetooth type=bluetooth_data_file
user=network_stack seinfo=network_stack domain=network_stack type=radio_data_file
user=nfc seinfo=platform domain=nfc type=nfc_data_file
user=secure_element seinfo=platform domain=secure_element levelFrom=all
user=radio seinfo=platform domain=radio type=radio_data_file
user=shared_relro domain=shared_relro levelFrom=all
user=shell seinfo=platform domain=shell name=com.android.shell type=shell_data_file
user=webview_zygote seinfo=webview_zygote domain=webview_zygote
user=_isolated domain=isolated_app levelFrom=user
user=_sdksandbox domain=sdk_sandbox type=sdk_sandbox_data_file levelFrom=all
user=_app seinfo=app_zygote domain=app_zygote levelFrom=user
user=_app seinfo=media domain=mediaprovider type=app_data_file levelFrom=user
user=_app seinfo=platform domain=platform_app type=app_data_file levelFrom=user
user=_app isEphemeralApp=true domain=ephemeral_app type=app_data_file levelFrom=all
user=_app isPrivApp=true domain=priv_app type=privapp_data_file levelFrom=user
user=_app isPrivApp=true name=com.google.android.permissioncontroller domain=permissioncontroller_app type=privapp_data_file levelFrom=all
user=_app seinfo=media isPrivApp=true name=com.android.providers.media.module domain=mediaprovider_app type=privapp_data_file levelFrom=all
user=_app isPrivApp=true name=com.google.android.providers.media.module domain=mediaprovider_app type=privapp_data_file levelFrom=all
user=_app seinfo=platform isPrivApp=true name=com.android.permissioncontroller domain=permissioncontroller_app type=privapp_data_file levelFrom=all
user=_app isPrivApp=true name=com.android.vzwomatrigger domain=vzwomatrigger_app type=privapp_data_file levelFrom=all
user=_app isPrivApp=true name=com.google.android.gms domain=gmscore_app type=privapp_data_file levelFrom=user
user=_app isPrivApp=true name=com.google.android.gms.* domain=gmscore_app type=privapp_data_file levelFrom=user
user=_app isPrivApp=true name=com.google.android.gms:* domain=gmscore_app type=privapp_data_file levelFrom=user
user=_app isPrivApp=true name=com.google.android.gsf domain=gmscore_app type=privapp_data_file levelFrom=user
user=_app minTargetSdkVersion=32 domain=untrusted_app type=app_data_file levelFrom=all
user=_app minTargetSdkVersion=30 domain=untrusted_app_30 type=app_data_file levelFrom=all
user=_app minTargetSdkVersion=29 domain=untrusted_app_29 type=app_data_file levelFrom=all
user=_app minTargetSdkVersion=28 domain=untrusted_app_27 type=app_data_file levelFrom=all
user=_app minTargetSdkVersion=26 domain=untrusted_app_27 type=app_data_file levelFrom=user
user=_app domain=untrusted_app_25 type=app_data_file levelFrom=user
user=_app minTargetSdkVersion=28 fromRunAs=true domain=runas_app levelFrom=all
user=_app fromRunAs=true domain=runas_app levelFrom=user


从以上定义可知,当签名是platform, 且user是system时,默认匹配到的就是system_app;同样可以在指定包名的情况下为特定APP指定特殊的domain.
例如:com.android.traceur,对应的domain已经是:traceur_app.

[小结]
1.platform签名 + system user 才是system_app;
2.platform签名 + 非system user ,是platform_app;
3.自己安装的三方APP是untrusted_app.

注意这里的system user是指示UID 1000, 如果是个APP, 那么他的AndroidManifest.xml必须声明android:sharedUserId=“android.uid.system”.

注意文件seapp_contexts中对user的定义说明.
user=_app will match any regular app process.
user=_isolated will match any isolated service process.
user=_sdksandbox will match sdk sandbox process for an app.
Other values of user are matched against the name associated with the process UID.

4.结论

  1. framework中的system app, 指的是预装在system image里边的APP.
  2. seAndroid中的system_app,是指拥有平台签名且user为system的APP.

参考资料

SEAndroid安全机制框架分析

<android Selinux 之 platform_app,system_app,priv_app,untrusted_app>

  • 28
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值