当前位置: 首页 > news >正文

Android Native 之 init初始化selinux机制

       

Selinux其实关系到linux kernel阶段和android第一个进程init的几个阶段,下面依次针对这些阶段进行剖析。

1、linux kernel初始化selinux

\par \cf0\highlight0 Shutting Down UEFI Boot Services: 3406 ms\cf1\highlight2 
\par \cf0\highlight0 Start EBS        [ 3407]\cf1\highlight2 
\par \cf0\highlight0 BDS: LogFs sync skipped, Unsupported\cf1\highlight2 
\par \cf0\highlight0 App Log Flush : 78 ms\cf1\highlight2 
\par \cf0\highlight0 Exit EBS        [ 3506] UEFI End\cf1\highlight2 
\par \cf0\highlight0 [    0.000000][    T0] Booting Linux on physical CPU 0x0000000000 [0x51af8014]\cf1\highlight2 
\par \cf0\highlight0 [    0.000000][    T0] Linux version 5.15.167-android13-8-g8c2d35e2e090-abHUACE.01 (build-user@build-host) (Android (8508608, based on r450784e) clang version 14.0.7 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6), LLD 14.0.7) #1 SMP PREEMPT Fri May 23 02:24:42 UTC 2025\cf1\highlight2 
\par \cf0\highlight0 [    0.002810][    T0] LSM: Security Framework initializing\cf1\highlight2 
\par \cf0\highlight0 [    0.002852][    T0] SELinux:  Initializing.\cf1\highlight2 
\par \cf0\highlight0 [    0.002999][    T0] Mount-cache hash table entries: 8192 (order: 4, 65536 bytes, linear)\cf1\highlight2 
\par \cf0\highlight0 [    0.003017][    T0] Mountpoint-cache hash table entries: 8192 (order: 4, 65536 bytes, linear)\cf1\highlight2 

如上日志为设备上电之后,启动linux kernel的流程,在0.002秒的时候开始进行LSM Security进行初始化,和SELinux Initializing初始化。

1.1 LSM: Security Framework initializing

1.2 SELinux: Initializing

1.3 linux kernel是如何设置当前状态?

如上核心代码逻辑为selinux_enforcing_boot如果为1者设置强制模式,否则设置宽容模式。这个变量的定义如下:

//vendor/kernel_platform/common/security/selinux/hooks.c 
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP 
//如果宏CONFIG_SECURITY_SELINUX_DEVELOP被定义执行如下代码
static int selinux_enforcing_boot __initdata;	//定义变量 selinux_enforcing_boot
static int __init enforcing_setup(char *str)
{unsigned long enforcing;//接收来自内核启动参数到enforcing,通过内核启动参数来决定 selinux_enforcing_boot的值if (!kstrtoul(str, 0, &enforcing))selinux_enforcing_boot = enforcing ? 1 : 0;return 1;
}
__setup("enforcing=", enforcing_setup);			//注册启动参数处理函数,当内核启动参数中有"enforcing=xxx"时,调用enforcing_setup函数
#else
//如果宏CONFIG_SECURITY_SELINUX_DEVELOP未被定义,宏定义 selinux_enforcing_boot 为1
#define selinux_enforcing_boot 1
#endif

根据这段代码可以知道,我们必须要打开linux kernel宏控CONFIG_SECURITY_SELINUX_DEVELOP,才可以在linux kernel层面去关闭selinux

1.4 linux selinuxfs实现了什么?

第一步:linux kernel在初始化阶段会主动进行系统调用__initcall

执行init_sel_fs函数,在此函数中,注册了文件系统结构体sel_fs_type,linux kernel在挂此结构体的时候,即2233行就会自动调用.init_fs_context指向的函数指针,反之在销毁的时候的会自动调用.kill_sb指向的函数指针

第二步:最终回调到sel_filll_super函数

在此函数中,在selinux文件系统目录下创建不同的子文件,个人不是很了解,猜测上层可以通过文件操作方式去回调后面对应的结构体,例如操作enforce就会指向对于的sel_enforce_ops

第三步:enforce的终极解密

如下代码,我们指向getenforce和setenforce其实就是对selinux/enforce文件进行读写操作, 最终走到了如下的两个函数,可以看到我们任何版本都可以进行getenforce,但是如果CONFIG_SECURITY_SELINUX_DEVELOP宏没有被定义,那么无法进行setenforce

//vendor/kernel_platform/common/security/selinux/selinuxfs.c
//enforce指定的结构体,即对selinux/enforce文件进行读操作回调sel_read_enforce函数,对selinux/enforce文件进行写操作回调sel_write_enforce
static const struct file_operations sel_enforce_ops = {.read       = sel_read_enforce,.write      = sel_write_enforce,.llseek     = generic_file_llseek,
};
//对selinux/enforce文件进行读操作
static ssize_t sel_read_enforce(struct file *filp, char __user *buf, size_t count, loff_t *ppos) {struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;char tmpbuf[TMPBUFLEN];ssize_t length;length = scnprintf(tmpbuf, TMPBUFLEN, "%d", enforcing_enabled(fsi->state));return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
//对selinux/enforce文件进行写操作
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
//如果CONFIG_SECURITY_SELINUX_DEVELOP宏被定义,定义sel_write_enforce函数
static ssize_t sel_write_enforce(struct file *file, const char __user *buf,  size_t count, loff_t *ppos) {struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;struct selinux_state *state = fsi->state;char *page = NULL;ssize_t length;int old_value, new_value;if (count >= PAGE_SIZE) return -ENOMEM;if (*ppos != 0) return -EINVAL;page = memdup_user_nul(buf, count);if (IS_ERR(page)) return PTR_ERR(page);length = -EINVAL;if (sscanf(page, "%d", &new_value) != 1) goto out;new_value = !!new_value;old_value = enforcing_enabled(state);if (new_value != old_value) {length = avc_has_perm(&selinux_state, current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__SETENFORCE,  NULL);if (length) goto out;audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS, "enforcing=%d old_enforcing=%d auid=%u ses=%u" " enabled=1 old-enabled=1 lsm=selinux res=1", new_value, old_value, from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current));enforcing_set(state, new_value);if (new_value) avc_ss_reset(state->avc, 0);selnl_notify_setenforce(new_value);selinux_status_update_setenforce(state, new_value);if (!new_value) call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL);selinux_ima_measure_state(state);}length = count;
out:kfree(page);return length;
}
#else //注意:如果宏CONFIG_SECURITY_SELINUX_DEVELOP没有被定义,此函数指针为null,即无法进行设置
#define sel_write_enforce NULL
#endif

2、Vendor init进程第一阶段启动

\par \cf0\highlight0 [    0.888559][    T1] Run /init as init process\cf1\highlight2

\par \cf0\highlight0 [    0.894425][    T1] init: init first stage started!\cf1\highlight2

如上代码,vendor init进程的第一阶段关键日志如上,并且没有关于selinux相关的打印,至于linux kernel如果启动到vendor init第一阶段,和vendor init第一阶段如何启动到system init的selinux阶段,参考Android Native 之 Init进程分析

3、System init进程selinux_setup启动

行    86: 06-19 12:02:09.620936     0     0 I (0)[0:swapper/0]SELinux: Initializing.
行  3636: 06-19 12:02:11.360570     1     1 E (0)[1:init]init 3: Init Selinux SetupSelinux A
行  3638: 06-19 12:02:11.368940     1     1 I (0)[1:init]init 3: Opening SELinux policy
行  3639: 06-19 12:02:11.368982     1     1 E (0)[1:init]init 3: Init Selinux SetupSelinux B
行  3642: 06-19 12:02:11.375320     1     1 I (1)[1:init]init 3: Loading APEX Sepolicy from /system/etc/selinux/apex/SEPolicy.zip
行  3643: 06-19 12:02:11.375595     1     1 E (1)[1:init]init 3: Failed to open package /system/etc/selinux/apex/SEPolicy.zip: No such file or directory
行  3644: 06-19 12:02:11.376426     1     1 E (1)[1:init]init 3: selinux root:1
行  3645: 06-19 12:02:11.376561     1     1 I (1)[1:init]init 4: Using userdebug system sepolicy /system/etc/selinux/userdebug_plat_sepolicy_cil
行  3646: 06-19 12:02:11.376651     1     1 I (1)[1:init]init 4: Compiling SELinux policy
行  4385: 06-19 12:02:14.550937     1     1 E (1)[1:init]init 4: Init Selinux SetupSelinux C
行  4386: 06-19 12:02:14.551093     1     1 E (1)[1:init]init 4: Init Selinux SetupSelinux D
行  4387: 06-19 12:02:14.551178     1     1 I (1)[1:init]init 4: Loading SELinux policy
行  4388: 06-19 12:02:14.689998     1     1 I (1)[1:init]SELinux: policy capability network_peer_controls=1
行  4389: 06-19 12:02:14.690014     1     1 I (1)[1:init]SELinux: policy capability open_perms=1
行  4390: 06-19 12:02:14.690019     1     1 I (1)[1:init]SELinux: policy capability extended_socket_class=1
行  4391: 06-19 12:02:14.690023     1     1 I (1)[1:init]SELinux: policy capability always_check_network=0
行  4392: 06-19 12:02:14.690028     1     1 I (1)[1:init]SELinux: policy capability cgroup_seclabel=0
行  4393: 06-19 12:02:14.690033     1     1 I (1)[1:init]SELinux: policy capability nnp_nosuid_transition=1
行  4394: 06-19 12:02:15.148882     1     1 I (0)[1:init]selinux 4: SELinux: Loaded file context from:
行  4395: 06-19 12:02:15.148908     1     1 I (0)[1:init]selinux 4: /system/etc/selinux/plat_file_contexts
行  4396: 06-19 12:02:15.149049     1     1 I (0)[1:init]selinux 3: /system_ext/etc/selinux/system_ext_file_contexts
行  4397: 06-19 12:02:15.149064     1     1 I (0)[1:init]selinux 3: /vendor/etc/selinux/vendor_file_contexts
行  4398: 06-19 12:02:15.149310     1     1 E (0)[1:init]selinux 3: SELinux:  Could not stat /dev/selinux: No such file or directory.
行  4399: 06-19 12:02:15.149380     1     1 E (0)[1:init]init 3: Init Selinux SetupSelinux E SelinuxSetEnforcement
行  4400: 06-19 12:02:15.149495     1     1 E (0)[1:init]init 3: Init Selinux SelinuxSetEnforcement kernel_enforcing is 0
行  4401: 06-19 12:02:15.149519     1     1 E (0)[1:init]init 3: Init Selinux SelinuxSetEnforcement kernel_enforcing is 0
行  4402: 06-19 12:02:15.153931     1     1 E (0)[1:init]init 3: Init Selinux SetupSelinux E
行  4404: 06-19 12:02:15.338551     1     1 I (0)[1:init]selinux: SELinux: Loaded file context from:
行  4405: 06-19 12:02:15.338575     1     1 I (0)[1:init]selinux: /system/etc/selinux/plat_file_contexts
行  4406: 06-19 12:02:15.338586     1     1 I (0)[1:init]selinux: /system_ext/etc/selinux/system_ext_file_contexts
行  4407: 06-19 12:02:15.338597     1     1 I (0)[1:init]selinux: /vendor/etc/selinux/vendor_file_contexts
行  4486: 06-19 12:02:15.503784     1     1 I (0)[1:init]selinux 6: SELinux: Loaded file context from:
行  4487: 06-19 12:02:15.503797     1     1 I (0)[1:init]selinux 6: /system/etc/selinux/plat_file_contexts
行  4488: 06-19 12:02:15.503808     1     1 I (0)[1:init]selinux 6: /system_ext/etc/selinux/system_ext_file_contexts
行  4489: 06-19 12:02:15.503819     1     1 I (0)[1:init]selinux 6: /vendor/etc/selinux/vendor_file_contexts)
行  4767: 06-19 12:02:15.783488   313   313 I (1)[313:ueventd]selinux: SELinux: Loaded file context from:
行  4768: 06-19 12:02:15.783509   313   313 I (1)[313:ueventd]selinux: /system/etc/selinux/plat_file_contexts
行  4769: 06-19 12:02:15.783519   313   313 I (1)[313:ueventd]selinux: /system_ext/etc/selinux/system_ext_file_contexts
行  4770: 06-19 12:02:15.783528   313   313 I (1)[313:ueventd]selinux: /vendor/etc/selinux/vendor_file_contexts
行  5192: 06-19 12:02:17.655100   403   403 I (3)[403:servicemanager]SELinux: SELinux: Loaded service context from:
行  5193: 06-19 12:02:17.655184   403   403 I (3)[403:servicemanager]SELinux: /system/etc/selinux/plat_service_contexts
行  5194: 06-19 12:02:17.655226   403   403 I (3)[403:servicemanager]SELinux: /system_ext/etc/selinux/system_ext_service_contexts
行  5195: 06-19 12:02:17.655266   403   403 I (3)[403:servicemanager]SELinux: /vendor/etc/selinux/vendor_service_context
行  5311: 06-19 12:02:18.024645     1     1 E (1)[1:init]selinux 21: [8398][0]SELinux:  Could not stat /sys/kernel/debug: No such file or directory.
行  5314: 06-19 12:02:18.037227     1     1 I (1)[1:init]selinux 5: [8402][0]SELinux: Skipping restorecon on directory(/metadata)
行  5315: 06-19 12:02:18.040521     1     1 I (2)[1:init]selinux 5: [8413][0]SELinux: Skipping restorecon on directory(/metadata/apex)
行  5608: 06-19 12:02:18.807752     1     1 I (3)[1:init]selinux 23: [9180][0]SELinux: Skipping restorecon on directory(/data/system/shutdown-checkpoints)
行  5716: 06-19 12:02:19.468904     1     1 I (0)[1:init]selinux 5: [9841][85]SELinux: Skipping restorecon on directory(/data)
行  5801: 06-19 12:02:20.321053     1     1 E (1)[1:init]selinux 21: [10654][25]SELinux:  Could not stat /data/dalvik-cache/arm64: No such file or directory.
行  5802: 06-19 12:02:20.321185     1     1 E (1)[1:init]selinux 21: [10654][25]SELinux:  Could not stat /data/dalvik-cache/riscv64: No such file or directory.
行  5803: 06-19 12:02:20.321304     1     1 E (1)[1:init]selinux 5: [10654][25]SELinux:  Could not stat /data/dalvik-cache/x86: No such file or directory.
行  5804: 06-19 12:02:20.321393     1     1 E (1)[1:init]selinux 5: [10654][25]SELinux:  Could not stat /data/dalvik-cache/x86_64: No such file or directory.
行  5811: 06-19 12:02:20.328629     1     1 I (1)[1:init]selinux 5: [10701][0]SELinux: Skipping restorecon on directory(/data/misc/apexdata/com.android.wifi)
行 10868: 06-19 12:02:43.491842  2125  2125 I (0)[2125:init]selinux 5: SELinux: Skipping restorecon on directory(/data/vendor_ce/0)
行 10872: 06-19 12:02:43.510338  2127  2127 I (3)[2127:init]selinux 5: SELinux: Skipping restorecon on directory(/data/misc_ce/0)
行 10959: 06-19 12:02:43.772735     1     1 E (3)[1:init]selinux 5: [34144][0]SELinux: Could not get canonical path for /sys/kernel/debug/tracing/instances/wifi restorecon: No such file or directory.
行 10981: 06-19 12:02:43.989663     1     1 I (1)[1:init]selinux 5: [34359][0]SELinux: Skipping restorecon on directory(/data/misc_ce/0/apexdata/com.android.wifi)

如上日志,对应如下源码:

// The SELinux setup process is carefully orchestrated around snapuserd. Policy  must be loaded off dynamic partitions, and during an OTA, those partitions cannot be read without snapuserd.
// But, with kernel-privileged snapuserd running, loading the policy will immediately trigger audits. We use a five-step process to address this:
//  (1) Read the policy into a string, with snapuserd running.
//  (2) Rewrite the snapshot device-mapper tables, to generate new dm-user devices and to flush I/O.
//  (3) Kill snapuserd, which no longer has any dm-user devices to attach to.
//  (4) Load the sepolicy and issue critical restorecons in /dev, carefully avoiding anything that would read from /system.
//  (5) Re-launch snapuserd and attach it to the dm-user devices from step (2).
// After this sequence, it is safe to enable enforcing mode and continue booting.
int SetupSelinux(char** argv) {//第一步:初始化阶段SetStdioToDevNull(argv);    //重定向标准IO到/dev/nullInitKernelLogging(argv);    //初始化内核日志系统LOG(ERROR) << "Init Selinux SetupSelinux A";if (REBOOT_BOOTLOADER_ON_PANIC) InstallRebootSignalHandlers();//安装崩溃重启处理器boot_clock::time_point start_time = boot_clock::now();MountMissingSystemPartitions(); //挂载缺失的系统分区SelinuxSetupKernelLogging();//第二步:策略预加载阶段LOG(INFO) << "Opening SELinux policy";LOG(ERROR) << "Init Selinux SetupSelinux B";PrepareApexSepolicy();//准备APEX模块的SELinux策略// Read the policy before potentially killing snapuserd.std::string policy;ReadPolicy(&policy);  //将策略文件读入内存字符串(对应五步法的第1步)CleanupApexSepolicy();//清理临时APEX策略//第三步:snapuserd过渡阶段LOG(ERROR) << "Init Selinux SetupSelinux C";auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded();//创建snapuserd辅助对象if (snapuserd_helper) {// Kill the old snapused to avoid audit messages. After this we cannot  read from /system (or other dynamic partitions) until we call FinishTransition().snapuserd_helper->StartTransition();// 终止旧snapuserd并重写设备映射表(对应五步法的第2-3步)}//第四步:策略生效阶段LOG(ERROR) << "Init Selinux SetupSelinux D";LoadSelinuxPolicy(policy);  //加载内存中的策略(对应五步法的第4步)if (snapuserd_helper) {// Before enforcing, finish the pending snapuserd transition.snapuserd_helper->FinishTransition(); //重启snapuserd并绑定新设备(对应五步法的第5步)snapuserd_helper = nullptr;}//第五步:强制模式激活阶段// This restorecon is intentionally done before SelinuxSetEnforcement because the permissions needed to transition files from tmpfs to *_contexts_file context should not be granted to any process after selinux is set into enforcing mode.//安全上下文预恢复阶段:释说明restorecon必须在强制模式前执行,因为从tmpfs转换到*_contexts_file上下文需要特殊权限,这些权限在强制模式下不应被授予。递归修复SELinux策略目录的安全上下文,失败则触发致命错误,/dev/selinux/包含策略文件和运行时状态,其上下文正确性直接影响SELinux功能。if (selinux_android_restorecon("/dev/selinux/", SELINUX_ANDROID_RESTORECON_RECURSE) == -1) {PLOG(FATAL) << "restorecon failed of /dev/selinux failed";}LOG(ERROR) << "Init Selinux SetupSelinux E SelinuxSetEnforcement";//将SELinux从宽容模式切换为强制模式,此后所有进程必须严格遵循策略规则SelinuxSetEnforcement();// We're in the kernel domain and want to transition to the init domain.  File systems that store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here, but other file systems do.  In particular, this is needed for ramdisks such as the recovery image for A/B devices.//注释解释某些文件系统(如ramdisk)需要显式恢复上下文,而ext4等支持xattr的文件系统可自动处理。对/system/bin/init执行非递归的上下文修复(0表示不递归),确保init进程域转换正确,该操作特别针对A/B设备的恢复镜像场景。if (selinux_android_restorecon("/system/bin/init", 0) == -1) {PLOG(FATAL) << "restorecon failed of /system/bin/init failed";}//第六步:进入init进程的第二阶段LOG(ERROR) << "Init Selinux SetupSelinux F";setenv(kEnvSelinuxStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), 1);//设置环境变量主要是更新时间戳const char* path = "/system/bin/init";const char* args[] = {path, "second_stage", nullptr};execv(path, const_cast<char**>(args)); //启动system/bin/init并传递second_stage参数// execv() only returns if an error happened, in which case we panic and never return from this function.PLOG(FATAL) << "execv(\"" << path << "\") failed";return 1;
}

3.1 system init如何进行selinux模式激活?

//system/system/core/init/selinux.cpp
//定义枚举表示当前selinux状态:宽容模式、强制模式
enum EnforcingStatus { SELINUX_PERMISSIVE, SELINUX_ENFORCING };
//通过属性来设置当前selinux状态
EnforcingStatus StatusFromProperty() {//默认强制模式EnforcingStatus status = SELINUX_ENFORCING;//遍历kernel传递上来的参数ImportKernelCmdline([&](const std::string& key, const std::string& value) {//如果找到键值对:androidboot.selinux=permissive,表示设置selinux状态为宽容模式if (key == "androidboot.selinux" && value == "permissive") {status = SELINUX_PERMISSIVE;LOG(ERROR) << "Init Selinux StatusFromProperty A " << " set status is permissive";}});//如果kernel参数没有找到宽容模式的设置,继续在ImportBootconfig中查找if (status == SELINUX_ENFORCING) {ImportBootconfig([&](const std::string& key, const std::string& value) {//如果找到键值对:androidboot.selinux=permissive,表示设置selinux状态为宽容模式if (key == "androidboot.selinux" && value == "permissive") {status = SELINUX_PERMISSIVE;LOG(ERROR) << "Init Selinux StatusFromProperty B" << " set status is permissive";}});}LOG(ERROR) << "Init Selinux StatusFromProperty C" << "status is " << status;return status;
}
bool IsEnforcing() {//如果宏开启进入判断,注意在init/Android.bp中,user版本此宏被设置为0,debug版本此宏被设置为1if (ALLOW_PERMISSIVE_SELINUX) {//如果是debug版本,androidboot.selinux=permissive满足,那么返回false,表示设置为宽容模式return StatusFromProperty() == SELINUX_ENFORCING;}//如果是user版本,默认返回true,表示设置为强制模式return true;
}
void SelinuxSetEnforcement() {bool kernel_enforcing = (security_getenforce() == 1); //获取kernel的selinux状态bool is_enforcing = IsEnforcing();                    //获取init的selinux状态LOG(ERROR) << "Init Selinux SelinuxSetEnforcement " << "kernel_enforcing is " << kernel_enforcing;LOG(ERROR) << "Init Selinux SelinuxSetEnforcement " << "kernel_enforcing is " << is_enforcing;//如果kernel和init的selinux状态不一致if (kernel_enforcing != is_enforcing) {//设置selinux状态if (security_setenforce(is_enforcing)) {PLOG(FATAL) << "security_setenforce(" << (is_enforcing ? "true" : "false") << ") failed";}}if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result.ok()) {LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();}
}

3.2 如何获取kernel参数和boot参数?

3.3 ALLOW_PERMISSIVE_SELINUX宏控是如何被设置?

3.4 getenforce与setenforce的本质

其实第一章在linux kernel阶段就介绍了enforce相关的内容,这里详细的实现了setenforce和getenforce的源码,并且init进程也是通过getenforce去获取kernel selinux状态,也是通过setenforce去设置kernel selinux状态

4、案例之user版本在init selinux中强制宽容模式无法开机

参考Android 关闭SE权限后编译user版本无法开机,开机直接进入FastBoot模式文档,在init selinux.cpp的直接强制返回false会使user版本进入fastboot模式,需要配置CONFIG_SECURITY_SELINUX_DEVELOP宏

根据如上分析,要同时满足kernel CONFIG_SECURITY_SELINUX_DEVELOP=y宏控配置,和selinux.cpp ALLOW_PERMISSIVE_SELINUX=1宏控配置,和androidboot.selinux=permissive即可。当然不需要三个条件都满足,后面两个条件可以合并,所以如下改法:

  • 步骤一:kernel配置CONFIG_SECURITY_SELINUX_DEVELOP=y

注意:在高通A14 T576项目上此宏默认是开启的?有些不可思议

  • 步骤二:init进程强制permissive模式

  • 除了上述暴力强制返回false之外,还可以温柔一点,按照selinux.cpp原有判断逻辑:

  • 配置kernel cmd参数

http://www.lryc.cn/news/578885.html

相关文章:

  • 【.NET Framework 窗体应用程序项目结构介绍】
  • day046-tomcat与部署war包、jar包
  • java实现日志记录-注解方式
  • 使用哪种语言的人更容易通过面试?
  • 【Web前端】优化轮播图展示(源代码)
  • (一)大语言模型的关键技术<-AI大模型构建
  • 360安全卫士占用5037端口(ADB端口)解决方案
  • Wps开放平台v5升级v7上传实体文件踩坑(Java使用restTemplate)
  • 基于开源链动2+1模式AI智能名片S2B2C商城小程序的场景零售创新研究
  • Mac电脑 卸载工具 App Cleaner
  • Java 大视界 -- Java 大数据在智能医疗健康管理中的慢性病风险预测与个性化干预(330)
  • 带GPU启动 Docker 容器
  • FAISS 简介及其与 GPT 的对接(RAG)
  • [CS创世SD NAND征文] 精准控制的坚固基石:CS创世SD NAND在华大HC32F4A0运动控制卡中的高可靠应用
  • 7月2日星期三今日早报简报微语报早读
  • Java AQS(AbstractQueuedSynchronizer)详解
  • 【前端】基础 - HTML基础标签和样式设置
  • Baumer工业相机堡盟工业相机如何实现高精度的硬件同步触发
  • 公用LCU屏的功能、应用场景
  • 微信小程序使用wx.chooseImage上传图片时进行压缩,并添加时间水印
  • 微信小程序入门实例_____打造你的专属单词速记小程序
  • PH热榜 | 2025-07-02
  • zabbix批量生成监控项教程!
  • Benchmarking in Go
  • 利器:NPM和YARN及其他
  • SQL Server 再进阶:类型多样性分析与时间维度扩展(第三课)
  • 解锁医疗AI密码:医疗人工智能专业大学四年学习路径
  • android核心技术摘要
  • 数论基础知识和模板
  • 香港券商交易系统开发与解决方案全景报告:云原生、跨境协同与高性能架构的创新实践