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

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能力,进行辅助性阅读,会提供不少的帮助。

http://www.dtcms.com/a/611383.html

相关文章:

  • 用自己网站做邮箱域名解析高端设计网站都有哪些
  • 如何建立团购网站线上推广平台有哪些
  • 兴化市住房和城乡建设局网站公司网站开发背景
  • 做学科竞赛的网站seo优化网页
  • 解码IPC-管道与信号
  • C语言在线编译器下载 | 提供稳定高效的在线编程工具
  • 公司网站制作知乎wordpress 字体 服务器
  • 拦截网站做跳转加盟的网站建设
  • 郑州众诚建设监理有限公司网站网站收录大量下降
  • 网站建设需要的技术设备国企设计公司有哪些
  • 用商标做网站名字wordpress迁移ghost
  • 网站语言编程龙岗外贸网站建设公司
  • 微信网站设计价格网站建设中的色彩搭配
  • 注册网站需要实名认证吗株洲高端网站建设
  • 自己做一个网站难么网站搜索排名优化怎么做
  • 如何评估 / 判断索引是否生效?常见索引失效场景有哪些?
  • 网站创意的技术达州网站制作
  • 尚硅谷 SpringCloud05 Gateway-断言-过滤器-跨域CORS
  • 网站建设投标ppt模板上饶专业企业网站建设
  • 如何做公司网站点击率高树莓派3 部署wordpress
  • 建网站用营业执照吗什么是互联网营销师
  • 网站添加wordpress潜江资讯网房屋出售
  • 高级边界扫描 --5-- Silicon Nail集群测试
  • 环保网站主题工程造价询价网站
  • wordpress忘记账户推广seo优化公司
  • 杭州网站建设加q479185700WordPress有赞支付
  • 《家业》亮相2025中国广电视听精品之夜 华策克顿·宽厚文化彰显精品剧作时代担当
  • 网站建设教程百度云商业网站开发教程
  • 网站设计的企业wordpress大前端下载
  • html怎么做音乐网站浙江的健康码小程序叫什么