Android framework强制修改系统属性
文章目录
- 前言
- 一、系统属性的设置
- 二、源码走读
- 1. SystemProperties
- 2. android_os_SystemProperties
- 3. properties
- 4. system_property_set
- 5. property_service
- 6. system_property_api
- 7. system_properties
- 三、修改源码
- 1. 绕过SELinux校验
- 2. 绕过更新ro属性限制
- 总结
前言
在修改Android系统源码时,我有一个需求,那就是可以动态修改系统的设备标识(设备型号),如果直接使用系统提供的API进行修改,会发现提示SELinux权限不通过,或者无权限修改ro只读属性。那么本章将从源码层面直接去除限制。
注意:本平台基于Android 16系统源代码。
一、系统属性的设置
系统属性可通过SystemProperties类的set方法进行设置(新属性的添加或者旧属性的更新)
import android.os.SystemPropertiesString key = "ro.xxx";
String val = "xxx";
SystemProperties.set(key, val);
直接进行设置会发现存在SELinux的问题,当然如果我们有root权限,可以直接绕过限制(adb shell setenforce 0),绕过限制后,发现可以进行设置ro属性的数据,但也仅限于设置新属性的数据,若对已存在属性进行值的更新,发现会报错:
# 以下操作以root用户身份执行# 绕过SELinux
adb shell setenforce 0# 设置新属性
adb shell setprop ro.aa a# 更新已存在属性的值
adb shell setprop ro.aa b
# 更新已存在属性的值失败,报错信息如下
Failed to set property 'ro.aa' to 'b'.
See dmesg for error reason.# 系统日志
2025-11-14 05:47:39.013 0-0 <no-tag> kernel E c1 588 init: Unable to set property 'ro.aa' from uid:0 gid:0 pid:4858: Read-only property was already set
2025-11-14 05:47:39.023 4858-4858 libc pid-4858 W Unable to set property "ro.aa" to "b": PROP_ERROR_READ_ONLY_PROPERTY (0xb)
二、源码走读
可以阅读setprop可执行的二进制文件跟踪设置属性的逻辑,或者直接从Android提供的API上追踪。本章直接从Android提供的API上直接追踪。
1. SystemProperties
从源码中可知,最后会直接走native_set方法
[frameworks/base/core/java/android/os/SystemProperties.java]// _NOT_ FastNative: native_set performs IPC and can block@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)private static native void native_set(String key, String def);@UnsupportedAppUsagepublic static void set(@NonNull String key, @Nullable String val) {if (val != null && !key.startsWith("ro.") && val.getBytes(StandardCharsets.UTF_8).length> PROP_VALUE_MAX) {throw new IllegalArgumentException("value of system property '" + key+ "' is longer than " + PROP_VALUE_MAX + " bytes: " + val);}if (TRACK_KEY_ACCESS) onKeyAccess(key);native_set(key, val);}
2. android_os_SystemProperties
属性的设置调用了__system_property_set方法
[frameworks/base/core/jni/android_os_SystemProperties.cpp]163 void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ,
164 jstring valJ)
165 {
166 ScopedUtfChars key(env, keyJ);
167 if (!key.c_str()) {
168 return;
169 }
170 std::optional<ScopedUtfChars> value;
171 if (valJ != nullptr) {
172 value.emplace(env, valJ);
173 if (!value->c_str()) {
174 return;
175 }
176 }
177 // Calling SystemProperties.set() with a null value is equivalent to an
178 // empty string, but this is not true for the underlying libc function.
179 const char* value_c_str = value ? value->c_str() : "";
180 // Explicitly clear errno so we can recognize __system_property_set()
181 // failures from failed system calls (as opposed to "init rejected your
182 // request" failures).
183 errno = 0;
184 bool success;
185 success = !__system_property_set(key.c_str(), value_c_str);.....
199 }
3. properties
查看源码时要注意,system/libbase/properties.cpp代码下的 __system_property_set方法,在Android中实际时不调用的。当#if defined(__BIONIC__)为真(即 Android 设备环境)时,代码依赖 Bionic 库提供的__system_property_set实现
[system/libbase/properties.cpp]19 #if defined(__BIONIC__)
20 #include <sys/system_properties.h>
21 #endif46 #define SYSPROP_WEAK __attribute__((weak)) // Linux平台 弱符号(SYSPROP_WEAK)
// 弱符号的特性是:若存在同名的强符号(非弱符号),则优先使用强符号。
71 SYSPROP_WEAK int __system_property_set(const char* key, const char* value) { ... }
4. system_property_set
需要观察的是,根据不同版本的protocol协议走不同的发送逻辑。本源代码是基于Android 16平台,走的是kProtocolVersion2,所以需要查看else的逻辑:
(1)通过socket进行跨进程通信,连接服务端成功后,使用writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()代码,发送属性设置的消息。
(2)使用connection.RecvInt32(&result)代码,读取属性设置的结果。
[bionic/libc/bionic/system_property_set.cpp]274 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
275 int __system_property_set(const char* key, const char* value) {
276 if (key == nullptr) return -1;
277 if (value == nullptr) value = "";
278
279 if (g_propservice_protocol_version == 0) {
280 detect_protocol_version();
281 }
282
283 if (g_propservice_protocol_version == kProtocolVersion1) {
284 // Old protocol does not support long names or values
285 if (strlen(key) >= PROP_NAME_MAX) return -1;
286 if (strlen(value) >= PROP_VALUE_MAX) return -1;
287
288 prop_msg msg;
289 memset(&msg, 0, sizeof msg);
290 msg.cmd = PROP_MSG_SETPROP;
291 strlcpy(msg.name, key, sizeof msg.name);
292 strlcpy(msg.value, value, sizeof msg.value);
293
294 return send_prop_msg(&msg);
295 } else {
296 // New protocol only allows long values for ro. properties only.
297 if (strlen(value) >= PROP_VALUE_MAX && strncmp(key, "ro.", 3) != 0) return -1;
298 // Use proper protocol
299 PropertyServiceConnection connection(key);
300 if (!connection.IsValid()) {
301 errno = connection.GetLastError();
302 async_safe_format_log(ANDROID_LOG_WARN, "libc",
303 "Unable to set property \"%s\" to \"%s\": connection failed: %m", key,
304 value);
305 return -1;
306 }
307
308 SocketWriter writer(&connection);
309 if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
310 errno = connection.GetLastError();
311 async_safe_format_log(ANDROID_LOG_WARN, "libc",
312 "Unable to set property \"%s\" to \"%s\": write failed: %m", key,
313 value);
314 return -1;
315 }
316
317 int result = -1;
318 if (!connection.RecvInt32(&result)) {
319 errno = connection.GetLastError();
320 async_safe_format_log(ANDROID_LOG_WARN, "libc",
321 "Unable to set property \"%s\" to \"%s\": recv failed: %m", key, value);
322 return -1;
323 }
324
325 if (result != PROP_SUCCESS) {
326 async_safe_format_log(ANDROID_LOG_WARN, "libc",
327 "Unable to set property \"%s\" to \"%s\": %s (0x%x)", key, value,
328 __prop_error_to_string(result), result);
329 return -1;
330 }
331
332 return 0;
333 }
334 }
5. property_service
代码过多需要耐心阅读。跨进程和property_service类进行通信,这里也是设置属性的主要逻辑。可以发现:
(1)权限的校验在CheckPermissions方法中,包含有selinux的校验逻辑(CheckMacPerms=>selinux_check_access)
(2)已存在属性的更新限制在PropertySet方法中(StartsWith(name, "ro."))
(3)已存在属性的设置通过__system_property_update方法设置,新属性的设置通过__system_property_add方法设置
[system/core/init/property_service.cpp]169 static bool CheckMacPerms(const std::string& name, const char* target_context,
170 const char* source_context, const ucred& cr) {
171 if (!target_context || !source_context) {
172 return false;
173 }
174
175 PropertyAuditData audit_data;
176
177 audit_data.name = name.c_str();
178 audit_data.cr = &cr;
179
180 auto lock = std::lock_guard{selinux_check_access_lock};
181 return selinux_check_access(source_context, target_context, "property_service", "set",
182 &audit_data) == 0;
183 }
......385 static std::optional<uint32_t> PropertySet(const std::string& name, const std::string& value,
386 SocketConnection* socket, std::string* error) {
387 size_t valuelen = value.size();
388
389 if (!IsLegalPropertyName(name)) {
390 *error = "Illegal property name";
391 return {PROP_ERROR_INVALID_NAME};
392 }
393
394 if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
395 *error = result.error().message();
396 return {PROP_ERROR_INVALID_VALUE};
397 }
398
399 if (name == "sys.powerctl") {
400 // No action here - NotifyPropertyChange will trigger the appropriate action, and since this
401 // can come to the second thread, we mustn't call out to the __system_property_* functions
402 // which support multiple readers but only one mutator.
403 } else {
404 prop_info* pi = (prop_info*)__system_property_find(name.c_str());
405 if (pi != nullptr) {
406 // ro.* properties are actually "write-once".
407 if (StartsWith(name, "ro.")) {
408 *error = "Read-only property was already set";
409 return {PROP_ERROR_READ_ONLY_PROPERTY};
410 }
411
412 __system_property_update(pi, value.c_str(), valuelen);
413 } else {
414 int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
415 if (rc < 0) {
416 *error = "__system_property_add failed";
417 return {PROP_ERROR_SET_FAILED};
418 }
419 }
420
421 // Don't write properties to disk until after we have read all default
422 // properties to prevent them from being overwritten by default values.
423 bool need_persist = StartsWith(name, "persist.") || StartsWith(name, "next_boot.");
424 if (socket && persistent_properties_loaded && need_persist) {
425 if (persist_write_thread) {
426 persist_write_thread->Write(name, value, std::move(*socket));
427 return {};
428 }
429 WritePersistentProperty(name, value);
430 }
431 }
432
433 NotifyPropertyChange(name, value);
434 return {PROP_SUCCESS};
435 }
......504 // This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
505 uint32_t CheckPermissions(const std::string& name, const std::string& value,
506 const std::string& source_context, const ucred& cr, std::string* error) {
507 if (!IsLegalPropertyName(name)) {
508 *error = "Illegal property name";
509 return PROP_ERROR_INVALID_NAME;
510 }
511
512 if (StartsWith(name, "ctl.")) {
513 if (!CheckControlPropertyPerms(name, value, source_context, cr)) {
514 *error = StringPrintf("Invalid permissions to perform '%s' on '%s'", name.c_str() + 4,
515 value.c_str());
516 return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
517 }
518
519 return PROP_SUCCESS;
520 }
521
522 const char* target_context = nullptr;
523 const char* type = nullptr;
524 property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
525
526 if (!CheckMacPerms(name, target_context, source_context.c_str(), cr)) {
527 *error = "SELinux permission check failed";
528 return PROP_ERROR_PERMISSION_DENIED;
529 }
530
531 if (!CheckType(type, value)) {
532 *error = StringPrintf("Property type check failed, value doesn't match expected type '%s'",
533 (type ?: "(null)"));
534 return PROP_ERROR_INVALID_VALUE;
535 }
536
537 return PROP_SUCCESS;
538 }
......540 // This returns one of the enum of PROP_SUCCESS or PROP_ERROR*, or std::nullopt
541 // if asynchronous.
542 std::optional<uint32_t> HandlePropertySet(const std::string& name, const std::string& value,
543 const std::string& source_context, const ucred& cr,
544 SocketConnection* socket, std::string* error) {
545 if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
546 return {ret};
547 }
548
549 if (StartsWith(name, "ctl.")) {
550 return {SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error)};
551 }
552
553 // sys.powerctl is a special property that is used to make the device reboot. We want to log
554 // any process that sets this property to be able to accurately blame the cause of a shutdown.
555 if (name == "sys.powerctl") {
556 std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
557 std::string process_cmdline;
558 std::string process_log_string;
559 if (ReadFileToString(cmdline_path, &process_cmdline)) {
560 // Since cmdline is null deliminated, .c_str() conveniently gives us just the process
561 // path.
562 process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
563 }
564 LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
565 << process_log_string;
566 if (value == "reboot,userspace") {
567 *error = "Userspace reboot is deprecated.";
568 return {PROP_ERROR_INVALID_VALUE};
569 }
570 }
571
572 // If a process other than init is writing a non-empty value, it means that process is
573 // requesting that init performs a restorecon operation on the path specified by 'value'.
574 // We use a thread to do this restorecon operation to prevent holding up init, as it may take
575 // a long time to complete.
576 if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) {
577 static AsyncRestorecon async_restorecon;
578 async_restorecon.TriggerRestorecon(value);
579 return {PROP_SUCCESS};
580 }
581
582 return PropertySet(name, value, socket, error);
583 }
......594
595 static void handle_property_set_fd(int fd) {
596 static constexpr uint32_t kDefaultSocketTimeout = 5000; /* ms */
597
598 int s = accept4(fd, nullptr, nullptr, SOCK_CLOEXEC);
599 if (s == -1) {
600 return;
601 }
602
603 ucred cr;
604 socklen_t cr_size = sizeof(cr);
605 if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
606 close(s);
607 PLOG(ERROR) << "sys_prop: unable to get SO_PEERCRED";
608 return;
609 }
610
611 SocketConnection socket(s, cr);
612 uint32_t timeout_ms = kDefaultSocketTimeout;
613
614 uint32_t cmd = 0;
615 if (!socket.RecvUint32(&cmd, &timeout_ms)) {
616 PLOG(ERROR) << "sys_prop: error while reading command from the socket";
617 socket.SendUint32(PROP_ERROR_READ_CMD);
618 return;
619 }
620
621 switch (cmd) {
......
651
652 case PROP_MSG_SETPROP2: {
653 std::string name;
654 std::string value;
655 if (!socket.RecvString(&name, &timeout_ms) ||
656 !socket.RecvString(&value, &timeout_ms)) {
657 PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
658 socket.SendUint32(PROP_ERROR_READ_DATA);
659 return;
660 }
661
662 std::string source_context;
663 if (!socket.GetSourceContext(&source_context)) {
664 PLOG(ERROR) << "Unable to set property '" << name << "': getpeercon() failed";
665 socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
666 return;
667 }
668
669 // HandlePropertySet takes ownership of the socket if the set is handled asynchronously.
670 const auto& cr = socket.cred();
671 std::string error;
672 auto result = HandlePropertySet(name, value, source_context, cr, &socket, &error);
673 if (!result) {
674 // Result will be sent after completion.
675 return;
676 }
677 if (*result != PROP_SUCCESS) {
678 LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
679 << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
680 }
681 socket.SendUint32(*result);
682 break;
683 }
......
690 }
6. system_property_api
[bionic/libc/bionic/system_property_api.cpp]......
85 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
86 int __system_property_get(const char* name, char* value) {
87 return system_properties.Get(name, value);
88 }
89
90 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
91 int __system_property_update(prop_info* pi, const char* value, unsigned int len) {
92 return system_properties.Update(pi, value, len);
93 }
94
95 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
96 int __system_property_add(const char* name, unsigned int namelen, const char* value,
97 unsigned int valuelen) {
98 return system_properties.Add(name, namelen, value, valuelen);
99 }
......
7. system_properties
prop_area是系统属性的共享内存存储区,所有进程通过映射该区域访问属性。
serial_pa用于存储属性序列号(标记属性变更,供监听机制使用)。
GetPropAreaForName根据属性名获取对应的存储区。
[bionic/libc/system_properties/system_properties.cpp]......
162 const prop_info* SystemProperties::Find(const char* name) {
163 if (!initialized_) {
164 return nullptr;
165 }
166
167 prop_area* pa = contexts_->GetPropAreaForName(name);
168 if (!pa) {
169 async_safe_format_log(ANDROID_LOG_WARN, "libc", "Access denied finding property \"%s\"", name);
170 return nullptr;
171 }
172
173 return pa->find(name);
174 }
......259 int SystemProperties::Get(const char* name, char* value) {
260 const prop_info* pi = Find(name);
261
262 if (pi != nullptr) {
263 return Read(pi, nullptr, value);
264 } else {
265 value[0] = 0;
266 return 0;
267 }
268 }
......270 int SystemProperties::Update(prop_info* pi, const char* value, unsigned int len) {
271 if (len >= PROP_VALUE_MAX) {
272 return -1;
273 }
274
275 if (!initialized_) {
276 return -1;
277 }
278 bool have_override = appcompat_override_contexts_ != nullptr;
279
280 prop_area* serial_pa = contexts_->GetSerialPropArea();
281 prop_area* override_serial_pa =
282 have_override ? appcompat_override_contexts_->GetSerialPropArea() : nullptr;
283 if (!serial_pa) {
284 return -1;
285 }
286 prop_area* pa = contexts_->GetPropAreaForName(pi->name);
287 prop_area* override_pa =
288 have_override ? appcompat_override_contexts_->GetPropAreaForName(pi->name) : nullptr;
289 if (__predict_false(!pa)) {
290 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Could not find area for \"%s\"", pi->name);
291 return -1;
292 }
293 CHECK(!have_override || (override_pa && override_serial_pa));
294
295 auto* override_pi = const_cast<prop_info*>(have_override ? override_pa->find(pi->name) : nullptr);
296
297 uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
298 unsigned int old_len = SERIAL_VALUE_LEN(serial);
299
300 // The contract with readers is that whenever the dirty bit is set, an undamaged copy
301 // of the pre-dirty value is available in the dirty backup area. The fence ensures
302 // that we publish our dirty area update before allowing readers to see a
303 // dirty serial.
304 memcpy(pa->dirty_backup_area(), pi->value, old_len + 1);
305 if (have_override) {
306 memcpy(override_pa->dirty_backup_area(), override_pi->value, old_len + 1);
307 }
308 atomic_thread_fence(memory_order_release);
309 serial |= 1;
310 atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
311 strlcpy(pi->value, value, len + 1);
312 if (have_override) {
313 atomic_store_explicit(&override_pi->serial, serial, memory_order_relaxed);
314 strlcpy(override_pi->value, value, len + 1);
315 }
316 // Now the primary value property area is up-to-date. Let readers know that they should
317 // look at the property value instead of the backup area.
318 atomic_thread_fence(memory_order_release);
319 int new_serial = (len << 24) | ((serial + 1) & 0xffffff);
320 atomic_store_explicit(&pi->serial, new_serial, memory_order_relaxed);
321 if (have_override) {
322 atomic_store_explicit(&override_pi->serial, new_serial, memory_order_relaxed);
323 }
324 __futex_wake(&pi->serial, INT32_MAX); // Fence by side effect
325 atomic_store_explicit(serial_pa->serial(),
326 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
327 memory_order_release);
328 if (have_override) {
329 atomic_store_explicit(override_serial_pa->serial(),
330 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
331 memory_order_release);
332 }
333 __futex_wake(serial_pa->serial(), INT32_MAX);
334
335 return 0;
336 }
......338 int SystemProperties::Add(const char* name, unsigned int namelen, const char* value,
339 unsigned int valuelen) {
340 if (namelen < 1) {
341 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
342 "__system_property_add failed: name length 0");
343 return -1;
344 }
345
346 if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) {
347 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
348 "__system_property_add failed: \"%s\" value too long: %d >= PROP_VALUE_MAX",
349 name, valuelen);
350 return -1;
351 }
352
353 if (!initialized_) {
354 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
355 "__system_property_add failed: properties not initialized");
356 return -1;
357 }
358
359 prop_area* serial_pa = contexts_->GetSerialPropArea();
360 if (serial_pa == nullptr) {
361 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
362 "__system_property_add failed: property area not found");
363 return -1;
364 }
365
366 prop_area* pa = contexts_->GetPropAreaForName(name);
367 if (!pa) {
368 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
369 "__system_property_add failed: access denied for \"%s\"", name);
370 return -1;
371 }
372
373 if (!pa->add(name, namelen, value, valuelen)) {
374 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
375 "__system_property_add failed: add failed for \"%s\"", name);
376 return -1;
377 }
378
379 if (appcompat_override_contexts_ != nullptr) {
380 bool is_override = is_appcompat_override(name);
381 const char* override_name = name;
382 if (is_override) override_name += strlen(APPCOMPAT_PREFIX);
383 prop_area* other_pa = appcompat_override_contexts_->GetPropAreaForName(override_name);
384 prop_area* other_serial_pa = appcompat_override_contexts_->GetSerialPropArea();
385 CHECK(other_pa && other_serial_pa);
386 // We may write a property twice to overrides, once for the ro.*, and again for the
387 // ro.appcompat_override.ro.* property. If we've already written, then we should essentially
388 // perform an Update, not an Add.
389 auto other_pi = const_cast<prop_info*>(other_pa->find(override_name));
390 if (!other_pi) {
391 if (other_pa->add(override_name, strlen(override_name), value, valuelen)) {
392 atomic_store_explicit(
393 other_serial_pa->serial(),
394 atomic_load_explicit(other_serial_pa->serial(), memory_order_relaxed) + 1,
395 memory_order_release);
396 }
397 } else if (is_override) {
398 // We already wrote the ro.*, but appcompat_override.ro.* should override that. We don't
399 // need to do the usual dirty bit setting, as this only happens during the init process,
400 // before any readers are started. Check that only init or root can write appcompat props.
401 CHECK(getpid() == 1 || getuid() == 0);
402 atomic_thread_fence(memory_order_release);
403 strlcpy(other_pi->value, value, valuelen + 1);
404 }
405 }
406
407 // There is only a single mutator, but we want to make sure that
408 // updates are visible to a reader waiting for the update.
409 atomic_store_explicit(serial_pa->serial(),
410 atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1,
411 memory_order_release);
412 __futex_wake(serial_pa->serial(), INT32_MAX);
413 return 0;
414 }
三、修改源码
1. 绕过SELinux校验
当目标为调用者为system用户或者shell用户时,允许绕过selinux的校验
[system/core/init/property_service.cpp]169 static bool CheckMacPerms(const std::string& name, const char* target_context,
170 const char* source_context, const ucred& cr) {
171 if (!target_context || !source_context) {
172 return false;
173 }
+ // 1000:system
+ // 2000:shell
+ // 0: root
+ if(cr.uid == 1000 || cr.uid == 2000) {
+ return true;
+ }
174
175 PropertyAuditData audit_data;
176
177 audit_data.name = name.c_str();
178 audit_data.cr = &cr;
179
180 auto lock = std::lock_guard{selinux_check_access_lock};
181 return selinux_check_access(source_context, target_context, "property_service", "set",
182 &audit_data) == 0;
183 }
2. 绕过更新ro属性限制
直接删除或者注释if (StartsWith(name, "ro."))代码块
[system/core/init/property_service.cpp]385 static std::optional<uint32_t> PropertySet(const std::string& name, const std::string& value,
386 SocketConnection* socket, std::string* error) {
387 size_t valuelen = value.size();
388
389 if (!IsLegalPropertyName(name)) {
390 *error = "Illegal property name";
391 return {PROP_ERROR_INVALID_NAME};
392 }
393
394 if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
395 *error = result.error().message();
396 return {PROP_ERROR_INVALID_VALUE};
397 }
398
399 if (name == "sys.powerctl") {
400 // No action here - NotifyPropertyChange will trigger the appropriate action, and since this
401 // can come to the second thread, we mustn't call out to the __system_property_* functions
402 // which support multiple readers but only one mutator.
403 } else {
404 prop_info* pi = (prop_info*)__system_property_find(name.c_str());
405 if (pi != nullptr) {
+ // 删除或者注释如下校验代码
- // ro.* properties are actually "write-once".
- if (StartsWith(name, "ro.")) {
- *error = "Read-only property was already set";
- return {PROP_ERROR_READ_ONLY_PROPERTY};
- }
411
412 __system_property_update(pi, value.c_str(), valuelen);
413 } else {
414 int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
415 if (rc < 0) {
416 *error = "__system_property_add failed";
417 return {PROP_ERROR_SET_FAILED};
418 }
419 }
420
421 // Don't write properties to disk until after we have read all default
422 // properties to prevent them from being overwritten by default values.
423 bool need_persist = StartsWith(name, "persist.") || StartsWith(name, "next_boot.");
424 if (socket && persistent_properties_loaded && need_persist) {
425 if (persist_write_thread) {
426 persist_write_thread->Write(name, value, std::move(*socket));
427 return {};
428 }
429 WritePersistentProperty(name, value);
430 }
431 }
432
433 NotifyPropertyChange(name, value);
434 return {PROP_SUCCESS};
435 }
总结
从追踪代码的流程到定制修改,是非常需要耐心的,最好结合现在大模型AI能力,进行辅助性阅读,会提供不少的帮助。
