This page describes how Android handles the policy compatibility issues with platform over-the-air (OTA) updates, where new platform SELinux settings might differ from old vendor SELinux settings.
Object ownership and labeling
Ownership must be clearly defined for each object to keep platform and vendor
policy separate. For example, if the vendor policy labels /dev/foo
and the platform policy labels /dev/foo in a subsequent OTA, there
is undefined behavior like an unexpected denial, or more critically, a boot
failure. For SELinux, this manifests as a labeling collision. The device node
can have only a single label that resolves to whichever label is applied last.
As a result:
- Processes that need access to the unsuccessfully applied label loses access to the resource.
- Processes that gain access to the file might break because the wrong device node was created.
Collisions between platform and vendor labels can occur for any object that has an SELinux label, including properties, services, processes, files, and sockets. To avoid these issues, clearly define ownership of these objects.
Type/attribute namespacing
In addition to label collisions, SELinux type and attribute names can also
collide. SELinux doesn't allow multiple declarations of the same types and
attributes. A policy with duplicate declarations fails to compile. To avoid type
and attribute name collisions, all vendor declarations are highly recommended to
start with the vendor_ prefix. For example, vendors should use
type vendor_foo, domain; instead of type foo, domain;.
File ownership
Preventing collisions for files is challenging because platform and vendor policy both commonly provide labels for all filesystems. Unlike type naming, namespacing of files isn't practical since many of them are created by the kernel. To prevent these collisions, follow the naming guidance for filesystems in this section. For Android 8.0, these are recommendations without technical enforcement. In the future, these recommendations will be enforced by the Vendor Test Suite (VTS).
System (/system)
Only the system image must provide labels for /system components
through file_contexts, service_contexts, etc. If labels
for /system components are added in the vendor policy, a
framework-only OTA update might not be possible.
Vendor (/vendor)
The AOSP SELinux policy already labels parts of the vendor
partition the platform interacts with, which enables writing SELinux rules for
platform processes to be able to talk or access parts of the vendor
partition. Examples:
| /vendor path | Platform-provided label | Platform processes depending on the label |
|---|---|---|
/vendor(/.*)?
|
vendor_file
|
All HAL clients in framework, ueventd, etc.
|
/vendor/framework(/.*)?
|
vendor_framework_file
|
dex2oat, appdomain, etc.
|
/vendor/app(/.*)?
|
vendor_app_file
|
dex2oat, installd, idmap, etc.
|
/vendor/overlay(/.*)
|
vendor_overlay_file
|
system_server, zygote, idmap, etc.
|
As a result, specific rules must be followed (enforced through
neverallows) when labelling additional files in the
vendor partition:
vendor_filemust be the default label for all files in thevendorpartition. The platform policy requires this to access passthrough HAL implementations.- All new
exec_typesadded in thevendorpartition through the vendor policy must havevendor_file_typeattribute. This is enforced through neverallows. - To avoid conflicts with future platform/framework updates, avoid labelling
files other than
exec_typesin thevendorpartition. - All library dependencies for AOSP-identified same process HALs must be
labelled as
same_process_hal_file.
Procfs (/proc)
Files in /proc may be labeled using only the genfscon
label. In Android 7.0, both the
platform
and vendor
policy used genfscon to label files in procfs.
Recommendation: Only platform policy labels /proc.
If vendor processes need access to files in /proc that are
currently labeled with the default label (proc), the vendor policy
shouldn't explicitly label them and should instead use the generic
proc type to add rules for vendor domains. This allows the platform
updates to accommodate future kernel interfaces exposed through
procfs and label them explicitly as needed.
Debugfs (/sys/kernel/debug)
Debugfs can be labeled in both file_contexts and
genfscon. In Android 7.0 to Android 10, both platform and vendor label
debugfs.
In Android 11, debugfs can't be
accessed or mounted on production devices. Device manufacturers should
remove debugfs.
Tracefs (/sys/kernel/debug/tracing)
Tracefs can be labeled in both file_contexts and
genfscon. In Android 7.0, only the platform labels
tracefs.
Recommendation: Only platform may label tracefs.
Sysfs (/sys)
Files in /sys may be labeled using both file_contexts
and genfscon. In Android 7.0, both the platform and the vendor use
genfscon to label files in sysfs.
Recommendation: The platform may label sysfs
nodes that aren't device-specific. Otherwise, only vendor may label files.
tmpfs (/dev)
Files in /dev may be labeled in file_contexts. In
Android 7.0, both the platform and the vendor label files here.
Recommendation: Vendor may label only files in
/dev/vendor (for example, /dev/vendor/foo,
/dev/vendor/socket/bar).
Rootfs (/)
Files in / may be labeled in file_contexts. In Android
7.0, both platform and vendor label files here.
Recommendation: Only system may label files in /.
Data (/data)
Data is labeled through a combination of file_contexts and
seapp_contexts.
Recommendation: Disallow vendor labeling outside
/data/vendor. Only platform may label other parts of
/data.
Genfs labels version
Starting with vendor API level 202504, newer SELinux
labels assigned with genfscon in
system/sepolicy/compat/plat_sepolicy_genfs_ver.cil are
optional for older vendor partitions. This allows older
vendor partitions to keep their existing SEPolicy implementation.
This is controlled by the Makefile variable BOARD_GENFS_LABELS_VERSION
which is stored in /vendor/etc/selinux/genfs_labels_version.txt.
Example:
-
In vendor API level 202404, the
/sys/class/udcnode is labeledsysfsby default. -
Starting from vendor API level 202504,
/sys/class/udcis labeledsysfs_udc.
However, /sys/class/udc might be in use by vendor
partitions using API level 202404, either with the default sysfs
label or a vendor-specific label. Unconditionally labeling
/sys/class/udc as sysfs_udc could break compatibility
with these vendor partitions. By checking
BOARD_GENFS_LABELS_VERSION, the platform keeps using the previous
labels and permissions for the older vendor partitions.
BOARD_GENFS_LABELS_VERSION can be greater than or equal to vendor API level. For
instance, vendor partitions using API level 202404 can set
BOARD_GENFS_LABELS_VERSION to 202504 to adopt new labels introduced
in 202504. See the list of
202504-specific genfs labels.
When labeling genfscon nodes, the platform must consider older
vendor partitions and implement fallback mechanisms for
compatibility when needed. The platform can use platform-only libraries to query
the genfs labels version.
-
On native, use
libgenfslabelsversion. Seegenfslabelsversion.hfor the header file oflibgenfslabelsversion. -
On Java, use
android.os.SELinux.getGenfsLabelsVersion().
Platform-public policy
The platform SELinux policy is divided into private and public. The
platform-public policy consists of types and attributes that are always
available for a vendor API level,
acting as an API between platform and vendor. This policy is exposed to vendor
policy writers to enable vendors to build vendor policy files, which when
combined with the platform-private policy, results in a fully functional policy
for a device. The platform-public policy is defined in
system/sepolicy/public.
For example, a type vendor_init, representing the init process in
the context of vendor, is defined under
system/sepolicy/public/vendor_init.te:
type vendor_init, domain;
Vendors can refer to the type vendor_init to write custom policy
rules:
# Allow vendor_init to set vendor_audio_prop in vendor's init scripts
set_prop(vendor_init, vendor_audio_prop)Compatibility attributes
SELinux policy is an interaction between source and target types for specific object classes and permissions. Every object (for example, processes, files) affected by SELinux policy can have only one type, but that type might have multiple attributes.
The policy is written mostly in terms of existing types. Here, both
vendor_init and debugfs are types:
allow vendor_init debugfs:dir { mounton };
This works because the policy was written with knowledge of all types. However,
if the vendor policy and platform policy use specific types, and the label of a
specific object changes in only one of those policies, the other might contain
policy that gained or lost access previously relied upon. For example, suppose
that the platform policy labels sysfs nodes as sysfs:
/sys(/.*)? u:object_r:sysfs:s0
The vendor policy grants access to /sys/usb, labeled as
sysfs:
allow vendor_init sysfs:chr_file rw_file_perms;
If the platform policy is changed to label /sys/usb as
sysfs_usb, the vendor policy remains the same, but
vendor_init loses access to /sys/usb due to the lack
of policy for the new sysfs_usb type:
/sys/usb u:object_r:sysfs_usb:s0
To solve this issue, Android introduces a concept of versioned attributes. At compile time, the build system automatically translates platform public types used in the vendor policy into these versioned attributes. This translation is enabled by mapping files that associate a versioned attribute with one or more public types from the platform.
For example, suppose that /sys/usb is labeled as sysfs
in 202504 platform policy, and 202504 vendor policy grants
vendor_init access to /sys/usb. In this case:
-
The vendor policy writes a rule
allow vendor_init sysfs:chr_file rw_file_perms;, because/sys/usbis labeled assysfsin 202504 platform policy. When the build system compiles vendor policy, it automatically translates the rule intoallow vendor_init_202504 sysfs_202504:chr_file rw_file_perms;. The attributesvendor_init_202504andsysfs_202504correspond to the typesvendor_initandsysfs, which are the types defined by the platform. -
The build system generates an identity mapping file
/system/etc/selinux/mapping/202504.cil. As both thesystemandvendorpartitions use the same202504version, the mapping file contains identity mappings fromtype_202504totype. For example,vendor_init_202504is mapped tovendor_init, andsysfs_202504is mapped tosysfs:(typeattributeset sysfs_202504 (sysfs)) (typeattributeset vendor_init_202504 (vendor_init)) ...
When the version is bumped from 202504 to 202604, a new mapping file for 202504
vendor partitions is created under
system/sepolicy/private/compat/202504/202504.cil, which is
installed to /system/etc/selinux/mapping/202504.cil for the 202604
or newer system partitions. Initially, this mapping file contains
identity mappings, as previously described. If a new label sysfs_usb
for /sys/usb is added to the 202604 platform policy, the mapping
file is updated to map sysfs_202504 to sysfs_usb:
(typeattributeset sysfs_202504 (sysfs sysfs_usb)) (typeattributeset vendor_init_202504 (vendor_init)) ...
This update allows the converted vendor policy rule allow
vendor_init_202504 sysfs_202504:chr_file rw_file_perms; to automatically
grant vendor_init access to the new sysfs_usb type.
To maintain compatibility with older vendor partitions, whenever a
new public type is added, that type must be mapped to at least one of versioned
attributes in the mapping file system/sepolicy/private/compat/ver/ver.cil,
or be listed under system/sepolicy/private/compat/ver/ver.ignore.cil
to state that there is no matching type in the previous vendor versions.
The combination of the platform policy, the vendor policy, and the mapping file allows the system to update without updating the vendor policy. Also the conversion into the versioned attributes happens automatically, so the vendor policy doesn't need to take care of the versioning, keeping using the public types as is.
system_ext public and product public policy
Starting in Android 11, the system_ext and the product
partitions are allowed to export their designated public types to the
vendor partition. Like the platform public policy, the vendor
policy uses types and rules automatically translated into the versioned
attributes, for example, from type into
type_ver, where ver is the vendor API level
of the vendor partition.
When the system_ext and the product partitions are
based on the same platform version ver, the build system generates
base mapping files to system_ext/etc/selinux/mapping/ver.cil
and product/etc/selinux/mapping/ver.cil, which contain
identity mappings from type to type_ver.
The vendor policy can access type with the versioned attribute
type_ver.
In case that only the system_ext and the product
partitions are updated, say ver to ver+1 (or later), while
the vendor partition stays at ver, the vendor policy
might lose access to the types of the system_ext and the
product partitions. To prevent breakage, the
system_ext and the product partitions should provide
mapping files from concrete types into type_ver
attributes. Each partner is responsible for maintaining the mapping
files, if they support ver vendor partition with
ver+1 (or later) system_ext and product
partitions.
To install mapping files to the system_ext and the product
partitions, device implementers, or vendors are expected to:
- Copy the generated base mapping files from ver
system_extandproductpartitions to their source tree. - Amend the mapping files as needed.
-
Install the
mapping files to ver+1 (or later)
system_extandproductpartitions.
For example, suppose that the 202504 system_ext partition has one
public type named foo_type. Then
system_ext/etc/selinux/mapping/202504.cil
in the 202504 system_ext partition looks like this:
(typeattributeset foo_type_202504 (foo_type)) (expandtypeattribute foo_type_202504 true) (typeattribute foo_type_202504)
If bar_type is added to the 202604 system_ext, and if
bar_type should be mapped to foo_type for the 202504
vendor partition, 202504.cil can be updated from
(typeattributeset foo_type_202504 (foo_type)) to
(typeattributeset foo_type_202504 (foo_type bar_type))
and then installed to the 202604 system_ext partition. The 202504
vendor partition can continue accessing to the 202604
system_ext's foo_type and bar_type.
Attribute changes for Android 9
Devices upgrading to Android 9 can use the following attributes, but devices launching with Android 9 must not.
Violator attributes
Android 9 includes these domain-related attributes:
data_between_core_and_vendor_violators. Attribute for all domains that violate the requirement of not sharing files by path betweenvendorandcoredomains. Platform and vendor processes shouldn't use on-disk files to communicate (unstable ABI). Recommendation:- Vendor code should use
/data/vendor. - System shouldn't use
/data/vendor.
- Vendor code should use
system_executes_vendor_violators. Attribute for all system domains (exceptinitandshell domains) that violate the requirement of not executing vendor binaries. Execution of vendor binaries has unstable API. Platform shouldn't execute vendor binaries directly. Recommendation:- Such platform dependencies on vendor binaries must be behind HIDL HALs.
OR
coredomainsthat need access to vendor binaries should be moved to thevendorpartition and thus, stop beingcoredomain.
- Such platform dependencies on vendor binaries must be behind HIDL HALs.
Untrusted attributes
Untrusted apps that host arbitrary code shouldn't have access to HwBinder services, except those considered sufficiently safe for access from such apps (see safe services below). The two main reasons for this are:
- HwBinder servers don't perform client authentication because HIDL currently doesn't expose caller UID information. Even if HIDL did expose such data, many HwBinder services either operate at a level below that of apps (such as, HALs) or must not rely on app identity for authorization. Thus, to be safe, the default assumption is that every HwBinder service treats all its clients as equally authorized to perform operations offered by the service.
- HAL servers (a subset of HwBinder services) contain code with higher
incidence rate of security issues than
system/corecomponents and have access to the lower layers of the stack (all the way down to hardware) thus increasing opportunities for bypassing the Android security model.
Safe services
Safe services include:
same_process_hwservice. These services (by definition) run in the process of the client and thus have the same access as the client domain in which the process runs.coredomain_hwservice. These services don't pose risks associated with reason #2.hal_configstore_ISurfaceFlingerConfigs. This service is specifically designed for use by any domain.hal_graphics_allocator_hwservice. These operations are also offered bysurfaceflingerBinder service, which apps are permitted to access.hal_omx_hwservice. This is a HwBinder version of themediacodecBinder service, which apps are permitted to access.hal_codec2_hwservice. This is a newer version ofhal_omx_hwservice.
Useable attributes
All hwservices not considered safe have the attribute
untrusted_app_visible_hwservice. The corresponding HAL servers have
the attribute untrusted_app_visible_halserver. Devices launching
with Android 9 MUST NOT use either
untrusted attribute.
Recommendation:
- Untrusted apps should instead talk to a system service that talks to the
vendor HIDL HAL. For example, apps can talk to
binderservicedomain, thenmediaserver(which is abinderservicedomain) in turn talks to thehal_graphics_allocator.OR
- Apps that need direct access to
vendorHALs should have their own vendor-defined sepolicy domain.
File attribute tests
Android 9 includes build time tests that ensure all files in specific
locations have the appropriate attributes (such as, all files in
sysfs have the required sysfs_type attribute).
SELinux contexts labeling
To support the distinction between platform and vendor sepolicy, the system builds SELinux context files differently to keep them separate.
File contexts
Android 8.0 introduced the following changes for file_contexts:
- To avoid additional compilation overhead on device during boot,
file_contextscease to exist in the binary form. Instead, they are readable, regular expression text file such as{property, service}_contexts(as they were pre-7.0). - The
file_contextsare split between two files:plat_file_contexts- Android platform
file_contextthat has no device-specific labels, except for labeling parts of/vendorpartition that must be labeled precisely to ensure proper functioning of the sepolicy files. - Must reside in
systempartition at/system/etc/selinux/plat_file_contextson device and be loaded byinitat the start along with the vendorfile_context.
- Android platform
vendor_file_contexts- Device-specific
file_contextbuilt by combiningfile_contextsfound in the directories pointed to byBOARD_SEPOLICY_DIRSin the device'sBoardconfig.mkfiles. - Must be installed at
/vendor/etc/selinux/vendor_file_contextsinvendorpartition and be loaded byinitat the start along with the platformfile_context.
- Device-specific
Property contexts
In Android 8.0, the property_contexts is split between two files:
plat_property_contexts- Android platform
property_contextthat has no device-specific labels. - Must reside in
systempartition at/system/etc/selinux/plat_property_contextsand be loaded byinitat the start along with the vendorproperty_contexts.
- Android platform
vendor_property_contexts- Device-specific
property_contextbuilt by combiningproperty_contextsfound in the directories pointed to byBOARD_SEPOLICY_DIRSin device'sBoardconfig.mkfiles. - Must reside in
vendorpartition at/vendor/etc/selinux/vendor_property_contextsand be loaded byinitat the start along with the platformproperty_context
- Device-specific
Service contexts
In Android 8.0, the service_contexts is split between the following
files:
plat_service_contexts- Android platform-specific
service_contextfor theservicemanager. Theservice_contexthas no device-specific labels. - Must reside in
systempartition at/system/etc/selinux/plat_service_contextsand be loaded byservicemanagerat the start along with the vendorservice_contexts.
- Android platform-specific
vendor_service_contexts- Device-specific
service_contextbuilt by combiningservice_contextsfound in the directories pointed to byBOARD_SEPOLICY_DIRSin the device'sBoardconfig.mkfiles. - Must reside in
vendorpartition at/vendor/etc/selinux/vendor_service_contextsand be loaded byservicemanagerat the start along with the platformservice_contexts. - Although
servicemanagerlooks for this file at boot time, for a fully compliantTREBLEdevice, thevendor_service_contextsMUST NOT exist. This is because all interaction betweenvendorandsystemprocesses MUST go throughhwservicemanager/hwbinder.
- Device-specific
plat_hwservice_contexts- Android platform
hwservice_contextforhwservicemanagerthat has no device-specific labels. - Must reside in
systempartition at/system/etc/selinux/plat_hwservice_contextsand be loaded byhwservicemanagerat the start along with thevendor_hwservice_contexts.
- Android platform
vendor_hwservice_contexts- Device-specific
hwservice_contextbuilt by combininghwservice_contextsfound in the directories pointed to byBOARD_SEPOLICY_DIRSin the device'sBoardconfig.mkfiles. - Must reside in
vendorpartition at/vendor/etc/selinux/vendor_hwservice_contextsand be loaded byhwservicemanagerat the start along with theplat_service_contexts.
- Device-specific
vndservice_contexts- Device-specific
service_contextfor thevndservicemanagerbuilt by combiningvndservice_contextsfound in the directories pointed to byBOARD_SEPOLICY_DIRSin the device'sBoardconfig.mk. - This file must reside in
vendorpartition at/vendor/etc/selinux/vndservice_contextsand be loaded byvndservicemanagerat the start.
- Device-specific
Seapp contexts
In Android 8.0, the seapp_contexts is split between two files:
plat_seapp_contexts- Android platform
seapp_contextthat has no device-specific changes. - Must reside in
systempartition at/system/etc/selinux/plat_seapp_contexts.
- Android platform
vendor_seapp_contexts- Device-specific extension to platform
seapp_contextbuilt by combiningseapp_contextsfound in the directories pointed to byBOARD_SEPOLICY_DIRSin the device'sBoardconfig.mkfiles. - Must reside in
vendorpartition at/vendor/etc/selinux/vendor_seapp_contexts.
- Device-specific extension to platform
MAC permissions
In Android 8.0, the mac_permissions.xml is split between two files:
- Platform
mac_permissions.xml- Android platform
mac_permissions.xmlthat has no device-specific changes. - Must reside in
systempartition at/system/etc/selinux/.
- Android platform
- Non-Platform
mac_permissions.xml- Device-specific extension to platform
mac_permissions.xmlbuilt frommac_permissions.xmlfound in the directories pointed to byBOARD_SEPOLICY_DIRSin the device'sBoardconfig.mkfiles. - Must reside in
vendorpartition at/vendor/etc/selinux/.
- Device-specific extension to platform
Shared memory changes for Android 17
Starting with Android 17, devices launching with the following properties must enable the memfd_class policy capability, and update their shared memory related policy to support memfd_file class objects:
- Vendor API level 202604 or higher to provide vendors and OEMs the opportunity to update their vendor policy to support
memfd. It also lets existing devices upgrade to higher versions of Android without requiring an update to their vendor partition. android16-6.12or higher kernel, since those kernels support thememfd_classfeature, which is required for implementing fine-grained policy formemfd.
Enable the memfd_class policy capability
Until recently, SELinux labeled a memfd as a file with the same type as its backing filesystem–-tmpfs. This made it impossible to distinguish a memfd from another file on a tmpfs mount from a policy perspective. Now, SELinux labels a memfd with the security context of the allocating process and memfds are treated as memfd_file class objects. This functionality is guarded by the memfd_class policy capability to preserve backward compatibility with older userspace environments.
To enable the memfd_class policy capability, create a policy_capabilities file under BOARD_VENDOR_SEPOLICY_DIRS. The file should contain the following entry:
# $BOARD_VENDOR_SEPOLICY_DIRS/*/policy_capabilities
policycap memfd_class;Then, rebuild your images and flash them to your device to verify that the capability is enabled.
Verify that the memfd_class policy capability is enabled
Use the following command to check the status of the memfd_class policy capability:
adb shell 'cat /sys/fs/selinux/policy_capabilities/memfd_class'
If the result is 1, then the memfd_class policy capability is enabled. Otherwise, it is not enabled.
Transition existing policy to memfd
Certain processes used the tmpfs_domain() macro in their policy to access and namespace their memfds, for example:
# foo.te
tmpfs_domain(foo)This translates to:
# foo.te type_transition foo tmpfs:file foo_tmpfs; allow foo foo_tmpfs:file { read write getattr map };
and lets process bar access process foo's memfds as such:
# bar.te allow bar foo_tmpfs:file { read write getattr map };
With the memfd_class policy capability enabled, the tmpfs_domain() macro is no longer needed, as the platform policy has been updated to let any process create and use its own memfds, as seen here:
# system/sepolicy/private/domain.te allow domain self:memfd_file { create read write getattr map };
and memfds created by process foo can be accessed by process bar as such:
# bar.te allow bar foo:memfd_file { read write getattr map };
The platform's policy has been updated to account for existing usages of memfd. However, vendor and device-specific policy that uses tmpfs labels must be updated to use memfd_file. If the policy is shared between SoCs or devices that don't have vendor API level 202604 or higher, then it is recommended that the legacy tmpfs policy is retained alongside the new memfd_file policy for compatibility.
Identify memfd related AVC denials
Memfd-related denials can be retrieved by using the following command:
adb shell logcat -d -b events | grep memfd
avc denials with tmpfs as the target
The following example shows an avc denial that was encountered by a process that tried to write to a memfd that it didn't have permission to write to:
audit(0.0:539): avc: denied { write } for comm="binder:665_1" name="memfd:MessageQueue"
dev="tmpfs" ino=8324 scontext=u:r:mediacodec:s0 tcontext=u:object_r:tmpfs:s0 tclass=file
permissive=0
When the memfd_class policy capability is enabled, the target context of a memfd is the allocating process' security context, not tmpfs, and the target class is memfd_file, not file. Therefore, if you are observing avc denials related to memfd, where the memfd in question is labeled as a tmpfs file, the memfd_class policy capability is not enabled.
avc denials with memfd_file as the target class
The following example shows an avc denial that was encountered by a process that tries to write to a memfd that it didn't have permission to write to, and the memfd_class policy capability was enabled, as well as an additional line that logd emits after the denial with the same timestamp:
audit(0.0:86): avc: denied { read } for
path=2F6D656D66643A4D6564696142756666657247726F7570202864656C6574656429 ino=512 dev=""
scontext=u:r:mediaserver:s0 tcontext=u:object_r:mediaextractor:s0 tclass=memfd_file
auditd : Decoded path for audit(0.0:86): /memfd:MediaBufferGroup (deleted)
The matching timestamp indicates that the Decoded path for … log is related to the avc denial with the 0.0.86 timestamp. This log decodes the hexadecimal string from the path value in the avc denial, and provides the memfd memory region's name, which can be useful to understand what buffer is being shared. The source context and target context are useful for understanding what processes need to share memory. From the preceding example, it's clear that the mediaserver process needs to be able to access mediaextractor's memfds. Therefore, the appropriate policy is:
# mediaserver.te allow mediaserver mediaextractor:memfd_file { getattr read write map };
Security domain updates in Android 17
The ASharedMemory_create() API in Android 17 implements conditional logic to select between the legacy ashmem driver and the memfd framework for shared memory allocations.
For devices meeting the memfd requirements (vendor API level 202604 or higher and kernel android16-6.12 or newer), the API evaluates the calling app's targetSdkVersion. If the target SDK version is 37 or higher, a memfd is allocated. This allows developers to fix issues that they encounter as they upgrade their target SDK version.
If the device doesn't meet memfd's prerequisites, ASharedMemory falls back to ashmem. This maintains compatibility for upgraded devices with older vendor partitions or kernels.
To enforce this transition, the platform SELinux policy blocks apps targeting SDK version 37 or higher in the platform_app, priv_app, and untrusted_app security domains from opening /dev/ashmem and invoking ashmem ioctl commands on memfd. This is achieved by splitting those app domains based on target SDK version. This introduces the platform_app_36, priv_app_36, and untrusted_app_34 security domains, which along with other app domains retain ashmem open permissions and the ability to invoke ashmem ioctl commands on memfds.
In a future Android release, the set of apps that retain permissions to open the ashmem device and invoke ashmem ioctl commands on memfds are reduced to just platform_app_36, priv_app_36, and untrusted_app_34 and untrusted app domains for older SDK versions.
Custom vendor or OEM SELinux policies for apps that pin their target SDK version must be updated to align with these domain changes, as detailed in the following sections.
platform_app SELinux domain updates
The platform_app domain is split based on the app's targetSdkVersion. Platform apps targeting SDK version 37 or higher are assigned the platform_app domain, while those targeting SDK version 36 or lower use platform_app_36. The platform_app_36 domain retains the ability to open /dev/ashmem for backward compatibility. To simplify policy management across both domains, use the platform_app_all attribute.
Consider the case where platform app sample-plat-app needs to read and write from and to /dev/foo_device. The existing vendor SELinux policy might look like this:
# This will only allow sample-plat-app to access the device if it # is placed in the platform_app domain (i.e. target SDK version is 37 or higher). allow platform_app foo_device:chr_file rw_file_perms;
However, if sample-plat-app is pinned at target SDK version 36, it is placed in the platform_app_36 domain, and the SELinux policy from earlier won't apply, and the following AVC denial is observed:
auditd : type=1400 audit(0.0:11): avc: denied { read write } for comm="sample-plat-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:platform_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0
To fix that, the policy can be updated as such since the app should always have access to the device node:
# This allows sample-plat-app to access the device independent of # target SDK version. allow platform_app_all foo_device:chr_file rw_file_perms;
There may be situations where platform_app_all may not work. For example, if the hal_client_domain() macro is used with platform_app_all, the policy fails to compile. This is because platform_app_all is an attribute, and hal_client_domain() would attempt to attach another attribute to it, which is not possible:
# platform_app.te
hal_client_domain(platform_app, hal_foo)
In those scenarios, it is required to use the platform_app_36 type directly, so your policy has the following content:
# platform_app.te hal_client_domain(platform_app, hal_foo) # platform_app_36.te hal_client_domain(platform_app_36, hal_foo)
priv_app SELinux domain updates
The priv_app domain is split based on the app's targetSdkVersion. Privileged apps targeting SDK version 37 or higher are assigned the priv_app domain, while those targeting SDK version 36 or lower use priv_app_36. The priv_app_36 domain retains the ability to open /dev/ashmem for backward compatibility. To simplify policy management across both domains, use the priv_app_all attribute.
Consider the case where platform app sample-priv-app needs to read and write from and to /dev/foo_device. The existing vendor SELinux policy might look like this:
# This will only allow sample-priv-app to access the device if it # is placed in the priv_app domain (i.e. target SDK version is 37 or higher). allow priv_app foo_device:chr_file rw_file_perms;
However, if sample-priv-app is pinned at target SDK version 36, it is placed in the priv_app_36 domain, and the SELinux policy from earlier won't apply, and the following AVC denial is observed:
auditd : type=1400 audit(0.0:11): avc: denied { read write } for comm="sample-priv-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:priv_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0
To fix that, the policy can be updated as such since the app should always have access to the device node:
# This allows sample-priv-app to access the device independent of # target SDK version. allow priv_app_all foo_device:chr_file rw_file_perms;
There may be situations where priv_app_all may not work. For example, if the hal_client_domain() macro is used with priv_app_all, the policy will fail to compile. This is because priv_app_all is an attribute, and hal_client_domain() would attempt to attach another attribute to it, which is not possible:
# priv_app.te
hal_client_domain(priv_app, hal_foo)
In those scenarios, it is required to use the priv_app_36 type directly, so your policy files will look something like this:
# priv_app.te hal_client_domain(priv_app, hal_foo) # priv_app_36.te hal_client_domain(priv_app_36, hal_foo)
untrusted_app SELinux domain updates
The untrusted_app domain is split based on the app's targetSdkVersion. Untrusted apps targeting SDK 37 version or higher are assigned the untrusted_app domain, while those targeting SDK versions 34-36 inclusive are assigned the new untrusted_app_34 domain. The untrusted_app_34 domain, as well as the untrusted_app_X domains, where `X` is an older target SDK version, retain the ability to open `/dev/ashmem` for backward compatibility.