SELinux(Security-Enhanced Linux)是 Linux 内核的一个安全模块,它提供了一种强制访问控制(Mandatory Access Control, MAC)机制。与传统的 Linux 自主访问控制(Discretionary Access Control, DAC)不同,SELinux 不依赖于文件的所有者和权限来控制访问,而是通过一套预先定义的策略,强制性地对所有进程和资源(如文件、目录、端口等)进行访问控制。即使是 root 用户,其行为也会受到 SELinux 策略的限制,这大大增强了系统的安全性。

1. SELinux 原理介绍

SELinux 的核心是基于 "域-类型"(Domain-Type)模型的强制访问控制。

主体(Subject)和客体(Object):

主体通常是指一个正在运行的进程,它试图访问某些资源。

客体是指被访问的资源,如文件、目录、网络端口等。

安全上下文(Security Context):

这是 SELinux 工作的基石。每个主体和客体都有一个唯一的安全上下文标签。

一个完整的安全上下文通常由四个部分组成:user:role:type:sensitivity。

在 Android 中,最重要的是 type,它决定了进程可以访问哪些资源,以及资源可以被哪些进程访问。通常以 _t 结尾,例如 untrusted_app_t、system_server_t。

策略(Policy)和规则(Rule):

策略是 SELinux 的核心,它定义了系统中的所有访问控制规则。

规则的形式通常为:allow <source_type> <target_type>:<class> <permissions>;

source_type:请求访问的主体的类型。

target_type:被访问的客体的类型。

class:客体的类别,如 file, dir, socket 等。

permissions:允许的操作,如 read, write, execute 等。

简而言之,当一个进程(主体)试图对一个资源(客体)执行某个操作时,SELinux 会首先检查它们各自的安全上下文。然后,它会在策略中查找是否存在一条允许 source_type 对 target_type 执行该 class 的 permission 的规则。如果找不到,访问就会被拒绝。

2. SELinux 的运行模式

SELinux 有三种主要运行模式,你可以通过adb shell getenforce 命令查看当前模式,并使用 adb shell setenforce 命令临时切换。

强制模式(enforcing):

这是最严格的模式。SELinux 策略被严格执行,任何违反策略的访问都会被拒绝并记录到日志中。

在生产环境中,系统通常运行在强制模式下以确保最大安全性。

宽容模式(permissive):

SELinux 策略不会被强制执行。所有违反策略的访问都会被允许,但会像在强制模式下一样,将拒绝信息记录到日志中。

这个模式非常适合开发和调试,你可以通过日志来发现策略中存在的缺陷,而不会导致系统功能异常。

禁用模式(disabled):

SELinux 完全不工作。不进行任何访问控制,也不记录任何日志。

不建议在任何情况下使用此模式,因为它会极大地降低系统的安全性。

Android 高通平台上的 SELinux 示例方法

在 Android 系统中,SELinux 是其安全模型的重要组成部分。对于高通(Qualcomm)平台,SELinux 的应用尤为关键。以下是一些常见场景及其 SELinux 策略的示例:

示例 1: 访问自定义设备节点

假设你开发了一个自定义的驱动程序,并在 /dev/my_device 创建了一个设备节点。现在,一个名为 my_service 的服务进程需要访问它。

定义设备节点的类型: 在策略文件中(通常是 .te 文件,如 vendor/qcom/proprietary/common/sepolicy/my_service.te),你需要为这个设备节点定义一个类型。

代码段

# 定义设备节点 my_device 的类型为 my_device_dev

type my_device_dev, dev_type;

设置文件上下文: 接下来,你需要告诉系统,/dev/my_device 这个路径下的文件应该被打上 my_device_dev 的标签。这通常在 file_contexts 文件中完成。

代码段

# file_contexts 文件

/dev/my_device  u:object_r:my_device_dev:s0

为服务进程定义访问权限: 最后,你需要为 my_service 进程定义一个 domain(域),并授予它访问 my_device_dev 类型的权限。

代码段

# my_service.te 文件

# 定义 my_service 进程的 domain

type my_service_t, domain;

# 授予 my_service_t 对 my_device_dev 的读写权限

allow my_service_t my_device_dev:chr_file { read write };

示例 2: 访问自定义属性文件

如果你的服务需要通过 sysfs(/sys)来控制硬件,例如通过 /sys/class/my_hw/status 文件读取状态。

定义 sysfs 文件的类型: sysfs 文件也有自己的类型。

代码段

# 在 sysfs_entry.te 中定义

type my_hw_status_sysfs, sysfs_type, fs_type;

设置文件上下文: 在 file_contexts 中指定这个 sysfs 文件的类型。

代码段

# file_contexts 文件

/sys/class/my_hw/status  u:object_r:my_hw_status_sysfs:s0

为服务进程授予权限: 给 my_service 进程授予读取 my_hw_status_sysfs 类型的权限。

代码段

# my_service.te 文件

allow my_service_t my_hw_status_sysfs:file { read };

调试手段与日志分析

调试 SELinux 问题是开发过程中不可或缺的一部分。当出现 Permission denied 错误时,往往就是 SELinux 策略阻止了访问。

日志打印

SELinux 的拒绝信息(denials)会被内核记录到 dmesg 和 auditd 日志中。你可以通过以下命令查看这些日志。

查看内核日志: 在 adb shell 中使用 dmesg 命令。拒绝信息通常包含 avc: denied 关键词。

Shell

adb shell "dmesg | grep 'avc: denied'"

一条典型的拒绝日志如下:

avc: denied { read } for pid=1234 comm="my_service" name="my_device" dev="tmpfs" ino=12345 scontext=u:r:my_service_t:s0 tcontext=u:object_r:my_device_dev:s0 tclass=chr_file permissive=0

日志解读:

denied { read }:被拒绝的操作是 read。

pid=1234 comm="my_service":请求访问的进程 ID 和名称。

scontext=u:r:my_service_t:s0:主体的安全上下文。

tcontext=u:object_r:my_device_dev:s0:客体(被访问资源)的安全上下文。

tclass=chr_file:客体的类别,这里是字符设备文件。

permissive=0:表示当前处于强制模式。如果是 permissive=1,则表示处于宽容模式,此次访问被允许,但仍有日志记录。

调试工具

audit2allow: 这是一个强大的工具,它可以根据日志中的拒绝信息自动生成 SELinux 策略规则。

首先,在宽容模式下复现问题,确保日志中记录了所有拒绝信息。

将 dmesg 日志导出到文件中。

Shell

adb shell "dmesg | grep 'avc: denied'" > avc.log

使用 audit2allow 工具生成规则

Shell

audit2allow -i avc.log -M my_service_policy

这个命令会生成两个文件:my_service_policy.te 和 my_service_policy.cil。my_service_policy.te 文件中包含了建议添加的规则,你可以将其合并到你的策略文件中。

seinfo 和 sesearch:

seinfo 可以用来查看当前加载的 SELinux 策略信息,例如所有类型、属性等。

sesearch 允许你查询策略中是否存在特定的规则,是分析现有策略的利器。

2 neverallow 策略简介

2.1 neverallow 是一种特殊的 SELinux 策略,顾名思义,它永远不允许某些特定的访问。它的存在是为了强化系统的安全,防止策略编写者无意中授予过于宽泛或危险的权限。

与普通的 allow 规则不同,neverallow 规则一旦被定义,就无法通过任何方式(包括添加 allow 规则)来覆盖。如果你的策略中任何一条 allow 规则与 neverallow 规则冲突,SELinux 策略编译器(sepolicy-compile)就会报错,导致编译失败。

neverallow 的典型用途:

限制特权进程的行为:例如,防止像 init 这样的高权限进程访问普通应用程序的数据。

防止跨域访问:确保不同安全域(如 system、vendor、app)之间的隔离。

禁止危险操作:例如,阻止任何非 init 进程创建 dev_t 类型的文件。

2.2 如何规避 neverallow 策略

因为 neverallow 无法被直接覆盖,所以“规避”它并不是指“绕过”它的限制,而是指通过修改你的策略设计来避免触发 neverallow 规则。

这里有几种常见的方法:

方法一:使用特定属性(attribute)

neverallow 规则通常是针对一个**属性(attribute)**而不是一个具体的类型。例如,一个 neverallow 规则可能禁止所有具有 untrusted_app 属性的类型访问 system_data 目录。

代码段

# 这是一个 hypothetical (假设的) neverallow 规则

neverallow untrusted_app system_data_file:dir { read write };

如果你有一个自定义的 app 类型 my_app_t,并且它被赋予了 untrusted_app 属性,那么它就无法访问 system_data_file。

规避方法:

不要将你的类型与受限属性关联。如果你的 my_app_t 不需要 untrusted_app 的所有权限,你可以不把它定义为 untrusted_app。

创建新的、更细粒度的属性。如果你需要访问某些受限资源,可以考虑创建一个新的属性,并让 neverallow 规则只针对旧的、宽泛的属性。但这需要修改 AOSP 的核心策略,通常不推荐。

方法二:修改你的代码逻辑

很多时候,触发 neverallow 是因为你的代码试图以一种不安全的方式访问资源。

规避方法:

不要直接访问受限资源。如果你的进程需要访问一个被 neverallow 规则禁止的资源,你应该重新设计你的代码。例如,通过调用一个有权限的**服务(service)**来间接操作,而不是直接访问。

使用 SELinux 允许的接口。Android 提供了 binder、hwservice 等多种 IPC(进程间通信)机制。你应该通过这些机制调用有权限的服务,让服务来完成操作,而不是自己去突破限制。

方法三:修改 SELinux 策略,但要谨慎

这是最后的手段,通常只在特殊情况下才需要。修改 neverallow 规则本身可能会削弱系统的安全性。

规避方法:

在 OEM 策略中添加例外。在某些高通平台,允许在 vendor/qcom/proprietary/common/sepolicy 目录下添加一些 OEM 特有的策略。如果 AOSP 的 neverallow 规则对你的特定功能造成了不合理的限制,并且你确定该操作是安全的,你可以考虑在 OEM 策略中添加更细粒度的 neverallow 规则或调整现有规则。但这需要非常小心,并进行充分的安全审计。

3. system_app 添加 per-property 属性的注意事项

在 Android 系统中,system_app 是一种特殊的应用程序,它们通常具有比普通应用更高的权限。为 system_app 添加 per-property 属性(即每个属性都有独立的 SELinux 类型)是常见的需求,尤其是在需要和自定义服务通信时。

示例:system_app 和自定义属性

假设你有一个 system_app,其进程类型是 system_app_t,你需要让它能设置一个自定义的系统属性 vendor.my.custom.prop。

定义属性类型: 在你的策略文件(如 vendor/qcom/proprietary/common/sepolicy/vendor.te)中,首先定义这个属性的类型。

代码段

# 定义自定义属性的类型

type my_custom_prop, property_type;

设置属性上下文: 在 property_contexts 文件中,将你的属性和类型关联起来。

代码段

# property_contexts 文件

vendor.my.custom.prop     u:object_r:my_custom_prop:s0

授予 system_app 设置权限: 现在,你需要允许 system_app_t 类型的进程设置这个属性。

代码段

# system_app.te (或者你的自定义策略文件)

# 允许 system_app_t 对 my_custom_prop 类型进行 set 权限

allow system_app_t my_custom_prop:property_service set;

注意事项:

neverallow 检查:即使是 system_app_t,也可能会受到一些 neverallow 规则的限制。例如,可能存在 neverallow system_app_t property_type:property_service set; 这样的规则,禁止 system_app 设置某些核心系统属性。在添加新的 allow 规则之前,最好检查一下是否存在相关的 neverallow 限制。

权限最小化原则:永远遵循最小权限原则。只授予 system_app 必要的权限,不要为了方便而授予过于宽泛的权限,例如 allow system_app_t property_type:property_service *;。

区分 system_app 和 vendor 进程:system_app 运行在 system 分区,而 vendor 进程运行在 vendor 分区。两者有不同的 SELinux 域,不能混用。确保你的 system_app 策略只影响 system_app_t 域,而不会影响到 vendor 域。

SELinux 策略隔离:Android GSI (Generic System Image) 要求 vendor 策略和 system 策略隔离。因此,你不能在 system 分区的策略中直接引用 vendor 策略中定义的类型,反之亦然。你需要通过 vendor_init_t 等中间类型或特定的属性来桥接这两个分区。

总之,neverallow 策略是 SELinux 安全模型的重要保障。理解它的原理并采取正确的策略设计,而不是试图绕过它,才能确保你所构建的 Android 系统既安全又稳定。

3、SELinux 策略修改示例与规范

在 Android 高通平台上的 SELinux 策略修改,旨在实现对工厂端回读信息的支持。这些修改涉及多个核心 SELinux 策略文件,体现了在自定义系统功能时如何正确扩展策略。

下面是根据你的提交内容,对 SELinux 策略修改的详细分析、解释和注意事项。

3.1.策略文件修改分析

你的修改主要集中在 shell.te、property.te、property_contexts 和 init 相关的策略文件中。这些修改的核心目标是:

定义新的属性类型:为 xxx相关的持久化属性(如 sn, snPcba, product.model)创建了新的 SELinux 类型。

允许 shell 和 init 访问这些属性:授予 shell 和 vendor_init 域的进程读写这些新定义属性的权限。

允许 shell 访问特定文件:为 shell 域添加了对特定文件(如 em_bluetooth_prop 和 mnt_vendor_file)的读取权限。

Vendor分区属性在BoradConfig.mk中添加 BUILD_BROKEN_VENDOR_PROPERTY_NAMESPACE 标记,这通常用于绕过对 vendor 属性命名空间的严格检查。

3.2 SELinux 策略修改示例详解

以下是根据你提供的 diff 内容,对每个重要修改点的具体分析。

示例 1:在 shell.te 中添加文件访问权限

Diff

--- a/LA.QSSI.12.0.r1/LINUX/android/system/sepolicy/prebuilts/api/32.0/private/shell.te+++ b/LA.QSSI.12.0.r1/LINUX/android/system/sepolicy/prebuilts/api/32.0/private/shell.te@@ -48,6 +48,9 @@ allow shell perfetto:process signal;

allow shell self:udp_socket { ioctl getopt setopt };

allow shell self:tcp_socket { ioctl getopt setopt };

allow shell mnt_vendor_file:dir { read getattr search open };+allow shell xx_bluetooth_prop:file { read open getattr map };+allow shell sysfs:file { open read getattr map };+allow shell mnt_vendor_file:file { open read getattr map};

修改目的:允许 shell 进程读取 xx_bluetooth_prop 类型的文件,以及 sysfs 和 mnt_vendor_file 类型的文件。

规范分析:这是一个典型的权限扩展。当你需要通过 adb shell 或其他 shell 脚本访问特定文件时,必须显式地在 shell.te 中添加相应的 allow 规则。这里的 xxx_bluetooth_prop 显然是一个自定义类型,需要在 file_contexts 中进行定义和关联。

示例 2:定义和设置新的 property 属性

Diff

--- a/LINUX/android/device/qcom/sepolicy_vndr/generic/vendor/common/property.te+++ b/LA.VENDOR.12.2.r1/LINUX/android/device/qcom/sepolicy_vndr/generic/vendor/common/property.te@@ -80,6 +80,9 @@ vendor_internal_prop(vendor_sensors_prop);

vendor_restricted_prop(vendor_tee_listener_prop);

vendor_restricted_prop(vendor_km_strongbox_version_prop);

vendor_restricted_prop(vendor_display_prop);+vendor_restricted_prop(vendor_xxx_product_model_prop);+vendor_restricted_prop(vendor_xxx_snpcba_prop);+vendor_restricted_prop(vendor_xxxx_sn_prop);

vendor_internal_prop(vendor_usb_prop);

vendor_restricted_prop(vendor_radio_prop);

vendor_internal_prop(vendor_qteeconnector_opti_prop);

修改目的:为 xxx 相关的属性定义了新的类型,并将其声明为 vendor_restricted_prop。

规范分析:将自定义属性声明为 vendor_restricted_prop 是一种推荐做法。这意味着这些属性只能由特定的 vendor 进程读写,从而确保了属性的隔离和安全。

示例 3:在 init_shell.te 中授予属性读写权限

Diff

--- LINUX/android/device/qcom/sepolicy_vndr/generic/vendor/common/init_shell.te+++ LINUX/android/device/qcom/sepolicy_vndr/generic/vendor/common/init_shell.te@@ -122,6 +122,12 @@ get_prop(vendor_qti_init_shell, radio_control_prop)

set_prop(vendor_qti_init_shell, vendor_gpu_prop)

set_prop(vendor_qti_init_shell, vendor_sensors_prop)

set_prop(vendor_qti_init_shell, vendor_adsprpc_prop)+set_prop(vendor_qti_init_shell, vendor_xxx_product_model_prop)+get_prop(vendor_qti_init_shell, vendor_xxx_product_model_prop)+set_prop(vendor_qti_init_shell, vendor_xxx_snpcba_prop)+get_prop(vendor_qti_init_shell, vendor_xxx_snpcba_prop)+set_prop(vendor_qti_init_shell, vendor_xxx_sn_prop)+get_prop(vendor_qti_init_shell, vendor_emdoor_sn_prop)

修改目的:允许 vendor_qti_init_shell 进程读写新定义的 emdoor 属性。

规范分析:在 init 脚本中设置或获取属性是常见操作,因此需要在 init 进程对应的 SELinux 域中添加相应的权限。这里的 set_prop 和 get_prop 宏是标准的 SELinux 策略写法,用于简化对属性服务的访问规则定义。

示例 4:在 BoardConfig.mk 中规避命名空间检查

Diff

--- LINUX/android/device/qcom/neo/BoardConfig.mk+++ LINUX/android/device/qcom/neo/BoardConfig.mk@@ -117,7 +117,7 @@ BOARD_METADATAIMAGE_PARTITION_SIZE := 16777216

BOARD_DTBOIMG_PARTITION_SIZE := 0x1700000

BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4

BOARD_FLASH_BLOCK_SIZE := 131072 # (BOARD_KERNEL_PAGESIZE * 64)-+BUILD_BROKEN_VENDOR_PROPERTY_NAMESPACE := true    # selinux name not to check

修改目的:由于你定义的属性 persist.xxx.* 不遵循标准的 vendor 属性命名规则(例如,必须以 vendor. 开头),这个标记用于暂时禁用策略编译器的严格检查。

规范分析:这种做法应该被视为临时解决方案,不推荐在长期项目中保留。标准的 vendor 属性应该以 vendor. 作为前缀,或者遵循 AOSP 规定的其他命名空间。使用这个标记虽然能解决编译问题,但可能会在未来的 Android 版本中遇到兼容性问题,并可能隐藏潜在的安全风险。

4、SELinux 最佳实践与注意事项

当你对 SELinux 策略进行修改时,应始终遵循以下原则:

4.1. 最小权限原则(Principle of Least Privilege)

只授予必要的权限:不要为了方便而使用过于宽泛的权限,例如 allow my_domain all_file_types:file *;。这会大大增加攻击面。

细化权限:精确到具体的操作。例如,如果只需要读取文件,就使用 read 和 getattr,而不是 read write。

4.2. neverallow 策略的应对

避免触发 neverallow:在编写新策略时,要先了解现有的 neverallow 规则,并确保你的 allow 规则不会与之冲突。例如,不要尝试让 untrusted_app 访问核心系统文件。

通过 IPC (Inter-Process Communication) 间接访问:如果一个进程需要访问被 neverallow 规则限制的资源,不要直接修改策略去绕过它。正确的做法是,让你的进程通过 Binder 或其他 IPC 机制,调用一个已经有权限的服务来完成这个操作。这是一种安全的设计模式。

4.3. 策略版本与兼容性

保持更新:SELinux 策略会随着 Android 版本不断演进,新的版本可能会引入新的 neverallow 规则或修改现有规则。当升级 Android 版本时,务必检查你的自定义策略是否仍然兼容。

vendor 和 system 策略隔离:在 Android 10 (Q) 及以后版本,Google 强制要求 vendor 策略和 system 策略必须严格隔离。这意味着 vendor 策略不能直接引用 system 策略中定义的类型。你提供的提交中,shell.te 和 vendor 策略都进行了修改,但它们是分开的,这符合隔离原则。

4. 4常见 AVC 错误解析

当 SELinux 拒绝你的访问时,它会在日志里留下一个详细的“案发现场报告”,也就是我们常说的 AVC(Access Vector Cache) 报错。

以下是一些你可能会遇到的经典“案发现场”,以及我们的侦查和破案技巧。

AVC 错误示例 1:无法访问 /sys/ 下的属性文件

案发现场报告:

type=1400 audit(8445.739:50): avc: denied { write } for comm="init" name="brightness" dev="sysfs" ino=78557 scontext=u:r:init:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=0

案情分析:

谁干的? init 进程,身份是 init_t。

想干啥? write(写入)brightness 文件。

被谁拦了? SELinux 安检员。

为什么拦? init_t 没有权限去 write 类型为 sysfs 的 file。

破案手法(解决方案): 在 init.te 文件中添加以下规则:

代码段

allow init sysfs:file { write };

AVC 错误示例 2:服务无法读取 sysfs 文件

案发现场报告:

type=1400 audit(8445.211:14): avc: denied { read } for comm="android.hardware" name="type" dev="sysfs" ino=81076 scontext=u:r:hal_health_default:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=0

案情分析:

谁干的? android.hardware 进程(可能是 HAL 服务),身份是 hal_health_default_t。

想干啥? read(读取)type 文件。

被谁拦了? SELinux 安检员。

为什么拦? hal_health_default_t 没有权限去 read 类型为 sysfs 的 file。

破案手法(解决方案): 在 system/sepolicy/vendor/hal_health_default.te 中添加以下规则:

代码段

allow hal_health_default sysfs:file { read };

AVC 错误示例 3:init 脚本无法写入 sysfs 文件

案发现场报告:

type=1400 audit(8440.707:12): avc: denied { write } for comm="sh" name="read_ahead_kb" dev="sysfs" ino=60930 scontext=u:r:vendor_qti_init_shell:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=0

案情分析:

谁干的? sh 进程(init 脚本),身份是 vendor_qti_init_shell_t。

想干啥? write(写入)read_ahead_kb 文件。

被谁拦了? SELinux 安检员。

为什么拦? vendor_qti_init_shell_t 没有权限去 write 类型为 sysfs 的 file。

破案手法(解决方案): 在 vendor_qti_init_shell.te 中添加以下规则:

代码段

allow vendor_qti_init_shell sysfs:file { write };

5总结:

5.1 终极武器:排查与修复板斧

现在,我们把前面学到的知识总结成一套“三板斧”式的方法论,保证你在其他平台上也能快速上手。

第一板斧:快速确认

当你遇到 Permission denied 时,不要急着改代码。

检查模式:adb shell getenforce

如果是 permissive,那问题就不是 SELinux,去查传统权限(chown,chmod)。

如果是 enforcing,好戏开场了!

调出日志:adb shell "dmesg | grep 'avc: denied'"

如果这条命令有输出,恭喜你,你已经抓到了 SELinux 的“犯罪现场报告”。

如果没输出,但系统又报错,那可能是别的地方的策略问题,需要更深入地排查。

第二板斧:宽容模式下的“侦查”

将设备切换到宽容模式:adb shell setenforce 0。

复现问题,让 SELinux 把所有拒绝信息都记录下来。

导出日志:adb shell "dmesg | grep 'avc: denied'" > avc.log。

第三板斧:用 audit2allow 快速破案

audit2allow 是一个强大的工具,能根据你的日志自动生成策略规则。

使用 audit2allow 生成策略:audit2allow -i avc.log -M my_policy。

这条命令会生成 my_policy.te 和 my_policy.cil。my_policy.te 里面就是工具为你生成的 allow 规则。

注意! 盲目复制粘贴是禁忌!你需要仔细审查这些规则,只保留你需要的,然后把它们加到你的策略文件里。

最后一步: 将你的策略文件重新编译,刷入设备,再把 SELinux 切换回 enforcing 模式:adb shell setenforce 1。

第四板斧:vendor 目录下的排查与修复流程

快速确认:使用 dmesg | grep 'avc: denied' 抓取报错日志。

分析日志:

scontext=u:r:<进程域>:s0:确定是哪个进程(进程域)犯错。

tcontext=u:object_r:<资源类型>:s0:确定受害者的类型(资源类型)。

denied { <权限> }:确定具体是什么操作被拒绝。

定位策略文件:根据 进程域,定位到 vendor 目录下对应的 .te 文件。

审查与添加规则:

在 .te 文件中,添加一条精确的 allow 规则。

如果涉及到新的可执行文件或设备,可能需要在 file_contexts 中添加新类型。

如果涉及到新的属性,可能需要在 property_contexts 中添加新类型。

编译与刷机:重新编译 vendor 分区,刷入设备,验证问题是否解决。

记住,在 vendor 目录中解决问题是 Android 平台 SELinux 开发的黄金法则。遵循这个原则,你的设备将更稳定,也更易于维护和升级。

转载请注明出处SELinux 入门指南-CSDN博客,谢谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/92725.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/92725.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/92725.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ARMv8 MMU页表格式及地址转换过程分析

1.简介 CPU发出的虚拟地址经过MMU转换后得到物理地址&#xff0c;然后使用物理地址访问真实的硬件。虚拟地址和物理地址的映射关系保存在页表中&#xff0c;MMU需要遍历页表&#xff0c;才能将虚拟地址转换成物理地址。ARM64现在有两种大小的页表描述符&#xff0c;分别是ARMv8…

数据结构---二叉树(概念、特点、分类、特性、读取顺序、例题)、gdb调试指令、时间复杂度(概念、大O符号法、分类)

一、二叉树1、树1&#xff09;概念 树是 n(n > 0) 个结点的有限集合。若 n0 &#xff0c;为空树。在任意一个非空树中&#xff1a;&#xff08;1&#xff09;有且仅有一个特定的根结点&#xff1b;&#xff08;2&#xff09;当 n>1 时&#xff0c;其余结点可分为 …

安全基础DAY1-安全概述

信息安全现状及挑战常见术语信息安全的脆弱性及常见攻击网络环境的开放性其实就是人人可以上网&#xff0c;网上零成本。协议栈自身的脆弱性及常见攻击协议栈自身的脆弱性常见安全风险网络的基本攻击模式物理层--物理攻击前置知识 1.打开Apache服务 cd /etc/init.d ./apache2 s…

Claude Code 的核心能力与架构解析

技术分析介绍&#xff1a;Claude Code 的核心能力与架构解析一、概述 Claude Code 是由 Anthropic 推出的面向开发者的智能编码助手&#xff0c;它不仅仅是一个代码生成工具&#xff0c;更是一个具备记忆、工具调用、自主规划和环境感知能力的“智能代理”&#xff08;Agentic …

Mac 电脑放在环境变量中的通用脚本

mac电脑下放在环境变量中&#xff0c;方便提高效率执行 注&#xff1a;相关路径需要根据实际情况进行更新 需要在 .bash_profile 文件中定义如下&#xff08;路径需要做实际替换&#xff09;&#xff1a; source $HOME/software/scripts/base_profile.sh source $HOME/software…

UE蓝图节点Add Impulse和Add Torque in Radians

​​​​​​​Add Impulse&#xff1a;对刚体施加一次性的线性脉冲&#xff08;瞬时改变量&#xff09;&#xff0c;改变速度&#xff08;与质量有关&#xff0c;除非你勾 bVelChange&#xff09;。Add Torque (in Radians)&#xff1a;对刚体施加转矩/旋转力&#xff08;向量…

大型语言模型幻觉检测与缓解技术研究综述

摘要 本文系统综述了大型语言模型(LLMs)中的幻觉现象及其检测与缓解技术。研究首先从认知机制角度分析了幻觉产生的理论根源&#xff0c;包括模型对语言先验的过度依赖、训练数据偏差以及推理过程中的信息衰减等问题。在技术层面&#xff0c;综述将现有方法归纳为三类&#xff…

【数据结构初阶】--二叉树(二)

&#x1f618;个人主页&#xff1a;Cx330❀ &#x1f440;个人简介&#xff1a;一个正在努力奋斗逆天改命的二本觉悟生 &#x1f4d6;个人专栏&#xff1a;《C语言》《LeetCode刷题集》《数据结构-初阶》 前言&#xff1a;上篇博客我们学习了有关树的概念和相关术语的介绍&…

jmm 指令重排 缓存可见性 Volatile 内存屏障

CPU指令重排 CPU指令重排是指CPU为了提高指令执行效率&#xff0c;可能会对指令的执行顺序进行优化&#xff0c;使得&#xff08;单线程下&#xff09;指令的实际执行顺序与代码中的顺序不同&#xff0c;但结果是一致的。 这种优化是通过乱序执行和缓存读写重排来实现的。 乱序…

卡车手机远程启动一键启动无钥匙进入有哪些好处

随着汽车科技的发展&#xff0c;卡车智能化升级已成为趋势&#xff0c;其中手机控车、远程启动、无钥匙进入及一键启动等功能显著提升了驾驶便捷性与安全性。以下从功能特点、技术原理、适用场景及改装建议等方面展开说明。一、核心功能及技术特点1. 无钥匙进入系统自动感应操作…

【pyqt5】SP_(Standard Pixmap)的标准图标常量及其对应的图标

目录 **常见SP_图标分类及用途** **1. 箭头和导航图标** **2. 文件和编辑操作** **3. 系统状态和通知** **4. 应用程序和菜单** **5. 数据视图控件** **完整列表(部分)** **使用建议** **6. 数据操作图标** **7. 编辑和文本操作** **8. 媒体控制图标** **9. 系统和应用状态**…

VS Git巨坑合并分支失败导致多项无关改变

基于主分支创建的临时分支上进行了一些开发&#xff0c;合并回主分支&#xff0c;期间主分支没有进行任何更改还是创建临时分支时的状态&#xff0c;但合并莫名其妙报错 “1 uncommitted …”&#xff0c;我可以确认主分支和临时分支均没有尚未提交的更改。更恶心的是&#xff…

开始记录U9客开过程中听点滴

很久没有更新了。终于有时间可以拾起U9的研究当中。时间长了就生疏了很多&#xff0c;记录下来备查吧。用这个工具可以生成一个VS 2022的项目&#xff0c;在指定的地方写自已的代码既可。BE插件&#xff0c;Busing Plugin 商业插件。总结一下&#xff0c;BE插件是应用于某一个单…

C# 异步编程(使用异步Lambda表达式)

使用异步Lambda表达式 到目前为止&#xff0c;本章只介绍了异步方法。但我们曾经说过&#xff0c;你还可以使用异步匿名方法和异步 Lambda表达式。这些构造尤其适合那些只有少量工作要做的事件处理程序。下面的代码片段将 一个表达式注册为一个按钮点击事件的事件处理程序。 st…

K8S云原生监控方案Prometheus+grafana

目录 1. 概述 1.1 系统架构 1.1.1 架构图 ​编辑 1.2 环境准备 2. 部署prometheus 2.1 创建Namespace 2.2 创建ConfigMap资源 2.3 创建ServiceAccount&#xff0c;Clusterrole&#xff0c;Clusterrolebinding&#xff0c;Service&#xff0c;Deployment&#xff0c;in…

Matplotlib库:Python数据可视化的基石,发现它的美

Matplotlib是Python中最基础、最广泛使用的数据可视化库&#xff0c;它提供了类似MATLAB的绘图接口&#xff0c;能够创建高质量的静态、动态和交互式图表。作为科学计算和数据可视化的核心工具&#xff0c;Matplotlib几乎成为Python数据科学生态系统的标准可视化组件。 今天与…

每日算法刷题Day59:8.9:leetcode 队列8道题,用时2h30min

一、基础 1.套路 1.队列常用在 BFS 中&#xff0c;见 网格图题单 和 图论题单。 2.队列(queue)是容器适配器&#xff0c;功能较少。 队尾插入元素&#xff0c;队首弹出元素&#xff0c;可以访问队首元素、队尾元素和队列长度。 无begin(),end()等迭代器 queue<int> qu…

Java选手如何看待Golang

写在前面&#xff1a;翻了很多博客&#xff0c;一直没有Java选手转行golang的学习经验贴&#xff0c;思考很久&#xff0c;写下这篇Java选手怎么看待golang这个冉冉新星。1.走完所有golang基础之后的感受&#xff08;1&#xff09;最大的不适应有这么几点&#xff1a;---变量定…

Codeforces Round 967 (Div. 2) D. Longest Max Min Subsequence

假设我们要选a[j]为答案数组b[i]&#xff0c;从i从1~m&#xff08;m为a数组中不同数的个数&#xff09;建立一个suf数组&#xff0c;代表以i开头的后缀有多少个不同且在b[1~i-1]中未出现过的的个数&#xff0c;预处理suf&#xff0c;发现后续我们怎么选数改变suf&#xff0c;su…

Linux运维新手的修炼手扎之第27天

mysql服务1 主从复制集群&#xff1a;多主机集群【复制】负载过大解决方案&#xff1a;横向扩展[增加服务器节点分散负载]、纵向扩展[提升单机硬件性能]复制工作原理&#xff1a;前提&#xff1a;基础数据一样&#xff0c;主节点上有同步数据用的账号主角色【二进制日志、binlo…