Android 9.x userdebug版本关闭adb root功能

引言

公司某行招标软件版本是userdebug,需要关闭adb root功能,保留安装应用等功能
刚开始修改系统属性值ro.secure=1,没有效果,只得去撸源码,最后修改成功,特此记录源码分析过程

“解决方案”

这个需求,不是很简单嘛,就是一个系统属性值的问题

diff --git a/build/make/core/main.mk b/build/make/core/main.mk
index fedddff3df..c2e0a82f04 100755
--- a/build/make/core/main.mk
+++ b/build/make/core/main.mk
@@ -294,7 +294,7 @@ else # !user_variant
   # Turn on checkjni for non-user builds.
   ADDITIONAL_BUILD_PROPERTIES += ro.kernel.android.checkjni=1
   # Set device insecure for non-user builds.
-  ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=0
+  ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=1
   # Allow mock locations by default for non user builds
   ADDITIONAL_DEFAULT_PROPERTIES += ro.allow.mock.location=1
 endif # !user_variant

编译,烧机,adb connect,adb root,adb remount

C:\Users\lc\Desktop
$ adb remount
remount succeeded

纳尼!!居然root成功了

分析源码过程

没办法,撸adb源码吧,源码见真章
/system/core/adb/daemon/main.cpp

int main(int argc, char** argv) {
240    while (true) {
241        static struct option opts[] = {
242            {"root_seclabel", required_argument, nullptr, 's'},
243            {"device_banner", required_argument, nullptr, 'b'},
244            {"version", no_argument, nullptr, 'v'},
245        };
246
247        int option_index = 0;
		   //解析命令行参数
248        int c = getopt_long(argc, argv, "", opts, &option_index);
249        if (c == -1) {
250            break;
251        }
253        switch (c) {
254        case 's':
			   //安全标签,adbd的权限说明
255            root_seclabel = optarg;
256            break;
257        case 'b':
			   //设备类型:android设备,主机
258            adb_device_banner = optarg;
259            break;
260        case 'v':
261            printf("Android Debug Bridge Daemon version %d.%d.%d\n", ADB_VERSION_MAJOR,
262                   ADB_VERSION_MINOR, ADB_SERVER_VERSION);
263            return 0;
264        default:
265            // getopt already prints "adbd: invalid option -- %c" for us.
266            return 1;
267        }
268    }
269    //关闭标准输入
       //指向标准输出文件描述结构体的STDIN_FILENO指向标准输出文件"/dev/null"
270    close_stdin();
271    //程序异常退出诊断
272    debuggerd_init(nullptr);
       //获取系统属性persist.adb.trace_mask,调用setup_trace_mask()设置为trace掩码
273    adb_trace_init(argv);
274
275    D("Handling main()");
       //adbd默认通信端口:5037
276    return adbd_main(DEFAULT_ADB_PORT);
277}

着重看下adbd_main()方法

int adbd_main(int server_port) {
       //设置新建文件的默认值
       //这个与chmod相反,这里相当于新建文件后的权限为666
176    umask(0);
177    //SIG_IGN,表示忽略SIGPIPE信号
178    signal(SIGPIPE, SIG_IGN);
179    //初始化adbd的传输连接
180    init_transport_registration();
182    //保证文件操作安全
184    adbd_cloexec_auth_socket();
185
186    if (ALLOW_ADBD_NO_AUTH && !android::base::GetBoolProperty("ro.adb.secure", false)) {
187        auth_required = false;
188    }
189    //adbd授权初始化
190    adbd_auth_init();
191
192    // Our external storage path may be different than apps, since
193    // we aren't able to bind mount after dropping root.
194    const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
195    if (adb_external_storage != nullptr) {
196        setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
197    } else {
198        D("Warning: ADB_EXTERNAL_STORAGE is not set.  Leaving EXTERNAL_STORAGE"
199          " unchanged.\n");
200    }
201    //降低特权
202    drop_privileges(server_port);
203
204    bool is_usb = false;
205    if (access(USB_FFS_ADB_EP0, F_OK) == 0) {
206        // Listen on USB.
207        usb_init();
208        is_usb = true;
209    }
210
211    // If one of these properties is set, also listen on that port.
212    // If one of the properties isn't set and we couldn't listen on usb, listen
213    // on the default port.
214    std::string prop_port = android::base::GetProperty("service.adb.tcp.port", "");
215    if (prop_port.empty()) {
216        prop_port = android::base::GetProperty("persist.adb.tcp.port", "");
217    }
218
219    int port;
220    if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) {
221        D("using port=%d", port);
222        // Listen on TCP port specified by service.adb.tcp.port property.
223        setup_port(port);
224    } else if (!is_usb) {
225        // Listen on default port.
226        setup_port(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
227    }
228
229    D("adbd_main(): pre init_jdwp()");
230    init_jdwp();
231    D("adbd_main(): post init_jdwp()");
232
233    D("Event loop starting");
234    fdevent_loop();
235
236    return 0;
237}

ro.adb.secure

主要来看下这段代码,分析一下ro.adb.secure属性值的作用

186    if (ALLOW_ADBD_NO_AUTH && !android::base::GetBoolProperty("ro.adb.secure", false)) {
187        auth_required = false;
188    }

用grep命令查一下ALLOW_ADBD_NO_AUTH 在哪里初始化

****@****:~/work/mt8788_9$ grep -inr "ALLOW_ADBD_NO_AUTH" system/core/adb/
system/core/adb/Android.mk:347:LOCAL_CFLAGS += -DALLOW_ADBD_NO_AUTH=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)

获取当前编译环境中的编译版本属性TARGET_BUILD_VARIANT,
如果是userdebug或eng的话,ALLOW_ADBD_NO_AUTH为1,否者为0。

继续查一下auth_required初始化之后在哪里用到
/system/core/adb/adb.cpp

static void handle_new_connection(atransport* t, apacket* p) {
320    if (t->GetConnectionState() != kCsOffline) {
321        t->SetConnectionState(kCsOffline);
322        handle_offline(t);
323    }
324
325    t->update_version(p->msg.arg0, p->msg.arg1);
326    parse_banner(p->payload, t);
327
328#if ADB_HOST
329    handle_online(t);
330#else
331    if (!auth_required) {
332        handle_online(t);
333        send_connect(t);
334    } else {
335        send_auth_request(t);
336    }
337#endif
338
339    update_transports();
340}

当auth_required=true时,设置online标志位为1,调用send_connect()去连接,往下走流程
当auth_required=false时,输出需要认证的消息到终端

在这里做个测试,设置ro.adb.secure=false,然后执行adb命令

C:\Users\lc\Desktop
$ adb root
adb: unable to connect for root: device unauthorized.
This adb server's $ADB_VENDOR_KEYS is not set
Try 'adb kill-server' if that seems wrong.
Otherwise check for a confirmation dialog on your device.

C:\Users\lc\Desktop
$ adb devices
List of devices attached
10.12.200.186:5555      unauthorized

此时设备处入未认证的状态,adb install失效,不符合我们的需求。

drop_privileges()

看drop_privileges函数名,知道它是用来降低权限的,对调用者权限从root到shell的控制

static void drop_privileges(int server_port) {
99    ScopedMinijail jail(minijail_new());
100
101    // Add extra groups:
102    // AID_ADB to access the USB driver
103    // AID_LOG to read system logs (adb logcat)
104    // AID_INPUT to diagnose input issues (getevent)
105    // AID_INET to diagnose network issues (ping)
106    // AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
107    // AID_SDCARD_R to allow reading from the SD card
108    // AID_SDCARD_RW to allow writing to the SD card
109    // AID_NET_BW_STATS to read out qtaguid statistics
110    // AID_READPROC for reading /proc entries across UID boundaries
111    // AID_UHID for using 'hid' command to read/write to /dev/uhid
112    gid_t groups[] = {AID_ADB,          AID_LOG,          AID_INPUT,    AID_INET,
113                      AID_NET_BT,       AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
114                      AID_NET_BW_STATS, AID_READPROC,     AID_UHID};
115    minijail_set_supplementary_gids(jail.get(), arraysize(groups), groups);
116
117    //安全模式下,不监听端口(默认为5037),以非root用户身份运行
119    if (should_drop_privileges()) {
120        const bool should_drop_caps = should_drop_capabilities_bounding_set();
121
122        if (should_drop_caps) {
123            minijail_use_caps(jail.get(), CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID));
124        }
125		   //更改群组为AID_SHELL
126        minijail_change_gid(jail.get(), AID_SHELL);
           //更改用户为AID_SHELL
127        minijail_change_uid(jail.get(), AID_SHELL);
128        // minijail_enter() will abort if any priv-dropping step fails.
129        minijail_enter(jail.get());
130
131        //清除clearing the inheritable, effective, and permitted sets.
135        using ScopedCaps =
136            std::unique_ptr<std::remove_pointer<cap_t>::type, std::function<void(cap_t)>>;
137        ScopedCaps caps(cap_get_proc(), &cap_free);
138        if (cap_clear_flag(caps.get(), CAP_INHERITABLE) == -1) {
139            PLOG(FATAL) << "cap_clear_flag(INHERITABLE) failed";
140        }
141        if (cap_clear_flag(caps.get(), CAP_EFFECTIVE) == -1) {
142            PLOG(FATAL) << "cap_clear_flag(PEMITTED) failed";
143        }
144        if (cap_clear_flag(caps.get(), CAP_PERMITTED) == -1) {
145            PLOG(FATAL) << "cap_clear_flag(PEMITTED) failed";
146        }
147        if (cap_set_proc(caps.get()) != 0) {
148            PLOG(FATAL) << "cap_set_proc() failed";
149        }
150
151        D("Local port disabled");
152    } else {
153        // minijail_enter() will abort if any priv-dropping step fails.
154        minijail_enter(jail.get());
155
156        if (root_seclabel != nullptr) {
157            if (selinux_android_setcon(root_seclabel) < 0) {
158                LOG(FATAL) << "Could not set SELinux context";
159            }
160        }
161        std::string error;
162        std::string local_name =
163            android::base::StringPrintf("tcp:%d", server_port);
164        if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
165            LOG(FATAL) << "Could not install *smartsocket* listener: " << error;
166        }
167    }
168}

通过should_drop_privileges()函数来判断是否需要降低权限

   static bool should_drop_privileges() {
63#if defined(ALLOW_ADBD_ROOT)
64    // The properties that affect `adb root` and `adb unroot` are ro.secure and
65    // ro.debuggable. In this context the names don't make the expected behavior
66    // particularly obvious.
67    //
68    // ro.debuggable:
69    //   Allowed to become root, but not necessarily the default. Set to 1 on
70    //   eng and userdebug builds.
71    //
72    // ro.secure:
73    //   Drop privileges by default. Set to 1 on userdebug and user builds.
74    bool ro_secure = android::base::GetBoolProperty("ro.secure", true);
75    bool ro_debuggable = __android_log_is_debuggable();
76
77    // Drop privileges if ro.secure is set...
78    bool drop = ro_secure;
79
80    // ... except "adb root" lets you keep privileges in a debuggable build.
81    std::string prop = android::base::GetProperty("service.adb.root", "");
82    bool adb_root = (prop == "1");
83    bool adb_unroot = (prop == "0");
84    if (ro_debuggable && adb_root) {
85        drop = false;
86    }
87    // ... and "adb unroot" lets you explicitly drop privileges.
88    if (adb_unroot) {
89        drop = true;
90    }
91
92    return drop;
93#else
94    return true; // "adb root" not allowed, always drop privileges.
95#endif // ALLOW_ADBD_ROOT
96}

看了这里的逻辑才恍然大悟,难怪只是设置ro.secure的值没用,真的需要判断的条件是__android_log_is_debuggable()和service.adb.root属性值。

真丶解决方案

/system/core/liblog/properties.c

280LIBLOG_ABI_PUBLIC int __android_log_is_debuggable() {
281  static uint32_t serial;
282  static struct cache_char tag_cache;
283  static const char key[] = "ro.debuggable";
284  int ret;
285
286  if (tag_cache.c) { /* ro property does not change after set */
287    ret = tag_cache.c == '1';
288  } else if (lock()) {
289    struct cache_char temp_cache = { { NULL, -1 }, '\0' };
290    refresh_cache(&temp_cache, key);
291    ret = temp_cache.c == '1';
292  } else {
293    int change_detected = check_cache(&tag_cache.cache);
294    uint32_t current_serial = __system_property_area_serial();
295    if (current_serial != serial) {
296      change_detected = 1;
297    }
298    if (change_detected) {
299      refresh_cache(&tag_cache, key);
300      serial = current_serial;
301    }
302    ret = tag_cache.c == '1';
303
304    unlock();
305  }
306
307  return ret;
308}

然后查一下service.adb.root属性值的初始化

****@****:~/work/mt8788_9$ grep -inr "service.adb.root" system/core/adb/
system/core/adb/daemon/main.cpp:81:    std::string prop = android::base::GetProperty("service.adb.root", "");
system/core/adb/services.cpp:87:        android::base::SetProperty("service.adb.root", "1");
system/core/adb/services.cpp:98:        android::base::SetProperty("service.adb.root", "0");

/system/core/adb/services.cpp

void restart_root_service(int fd, void *cookie) {
    if (getuid() == 0) {
        WriteFdExactly(fd, "adbd is already running as root\n");
        adb_close(fd);
    } else {
        if (!__android_log_is_debuggable()) {
            WriteFdExactly(fd, "adbd cannot run as root in production builds\n");
            adb_close(fd);
            return;
        }

        android::base::SetProperty("service.adb.root", "1");
        WriteFdExactly(fd, "restarting adbd as root\n");
        adb_close(fd);
    }
}

void restart_unroot_service(int fd, void *cookie) {
    if (getuid() != 0) {
        WriteFdExactly(fd, "adbd not running as root\n");
        adb_close(fd);
    } else {
        android::base::SetProperty("service.adb.root", "0");
        WriteFdExactly(fd, "restarting adbd as non root\n");
        adb_close(fd);
    }
}

可以看到service.adb.root的属性值是动态设置的,判断条件也是__android_log_is_debuggable()方法
修改ro.debuggable的值

diff --git a/build/make/core/main.mk b/build/make/core/main.mk
index c2e0a82f04..14ca69b4a4 100755
--- a/build/make/core/main.mk
+++ b/build/make/core/main.mk
@@ -301,7 +301,7 @@ endif # !user_variant

 ifeq (true,$(strip $(enable_target_debugging)))
   # Target is more debuggable and adbd is on by default
-  ADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=1
+  ADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=0
   # Enable Dalvik lock contention logging.
   ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.lockprof.threshold=500
   # Include the debugging/testing OTA keys in this build.

编译,烧机之后,验证功能

C:\Users\lc\Desktop
$ adb disconnect & adb connect 10.12.200.27:5555 & adb root & adb remount
disconnected everything
connected to 10.12.200.27:5555
Not running as root. Try "adb root" first.

C:\Users\lc\Desktop
$ adb install -r antutu_v8.4.8.apk
Performing Streamed Install
adb: failed to install antutu_v8.4.8.apk: Failure [-9999: **** signature error for com.antutu.ABenchMark]

注:-9999是增加的第三方验签功能,这里无关紧要。
root功能失效,应用安装功能等保留,问题解决。

总结

遇事多看看源码,看源码之前,看看大佬的博客,有助于我们阅读源码
ADB(二)_ADBD_main()函数代码梳理
ADB(三)_ADBD_adbd_main()函数代码梳理
ADB(四)_host端的启动流程代码梳理

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值