倘若應用程序需要對/dev/xxx進行讀寫操作,就需要提升其權限。提權方法不唯一,需要根據具體需求情況而選擇。歸根結底,終究都落到chmod 777 /dev/xxx 上,不同的是,chmod操作被執行在何時何地,在此做個分析總結。
內核啟動後會執行/system/init,傳說中的系統1號進程,init程序起初的任務是初始化,包括各種mkdir來構建文件系統,得到硬件信息建立設備節點,安裝SIGCHLD信號來回收僵屍進程的資源,解析init.rc啟動腳本等等,然後init程序變身為property_service來管理系統的權限。我們可以下手的地方有兩處: device_init和init.rc 。
✿ init.rc
這個方案是大家用的比較多的,在其中添加chmod操作很簡單不多說。
✿ device.c
這個方案用的比較少,先了解下device.c。
device_init在/system/core/init/device.c中,詳細分析如下:
- //分別遍歷/sys/class /sys/block /sys/devices
- device_init()
- {
- coldboot(fd,"/sys/class");
- coldboot(fd,"/sys/block");
- coldboot(fd,"/sys/devices");
- }
-
- //後面有個遞歸 /sys下是內核生成的設備,這就相當於udev的作用
- do_coldboot()
- {
- if(fd>= 0) {
- write(fd,"add\n", 4);
- close(fd);
- handle_device_fd(event_fd);
- }
- }
-
- //從socket裡讀出add處理
- handle_device_fd()
- {
- if(!strcmp(uevent->action,"add")) {
- make_device(devpath,block, uevent->major, uevent->minor);
- return;
- }
- }
-
- //得到設備的相關信息創建設備節點
- make_device()
- {
- mode= get_device_perm(path,&uid, &gid) | (block ? S_IFBLK : S_IFCHR);
- dev= (major << 8) | minor;
- mknod(path,mode, dev);
- chown(path,uid, gid);
- }
-
- get_device_perm()
- {
- if(get_device_perm_inner(qemu_perms, path, uid, gid, &perm) == 0) {
- returnperm;
- }elseif(get_device_perm_inner(devperms,path, uid, gid, &perm) == 0){
- returnperm;
- }else{
- …….
- }
-
- //得到devperms結構體的信息
- get_device_perm_inner
- {
- for(i= 0; perms[i].name; i++) {
-
- if(perms[i].prefix){
- if(strncmp(path,perms[i].name, strlen(perms[i].name)))
- continue;
- }else{
- if(strcmp(path,perms[i].name))
- continue;
- }
- *uid= perms[i].uid;
- *gid= perms[i].gid;
- *perm= perms[i].perm; //權限位
- return0;
- }
- }
-
- 這是devperms的具體內容
- structperms_ {
- char*name;
- mode_tperm;
- unsignedintuid;
- unsignedintgid;
- unsignedshortprefix;
- };
- staticstructperms_ devperms[] = {
- {"/dev/null", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/zero", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/full", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/ptmx", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/tty", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/random", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/urandom", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/ashmem", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/binder", 0666, AID_ROOT, AID_ROOT, 0 },
-
- /* logger should be world writable (for logging) but not readable*/
- {"/dev/log/", 0662, AID_ROOT, AID_LOG, 1 },
-
- /*these should not be world writable */
- {"/dev/Android_adb", 0660, AID_ADB, AID_ADB, 0 },
- {"/dev/android_adb_enable", 0660, AID_ADB, AID_ADB, 0 },
- {"/dev/ttyMSM0", 0660, AID_BLUETOOTH, AID_BLUETOOTH, 0 },
- {"/dev/alarm", 0664, AID_SYSTEM, AID_RADIO, 0 },
- {"/dev/tty0", 0666, AID_ROOT, AID_SYSTEM, 0 },
- {"/dev/graphics/", 0660, AID_ROOT, AID_GRAPHICS, 1 },
- {"/dev/hw3d", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },
- {"/dev/input/", 0660, AID_ROOT, AID_INPUT, 1 },
- {"/dev/eac", 0660, AID_ROOT, AID_AUDIO, 0 },
- {"/dev/cam", 0660, AID_ROOT, AID_CAMERA, 0 },
- {"/dev/pmem", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },
- {"/dev/pmem_gpu", 0660, AID_SYSTEM, AID_GRAPHICS, 1 },
- {"/dev/pmem_adsp", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- {"/dev/pmem_camera", 0660, AID_SYSTEM, AID_CAMERA, 1 },
- {"/dev/oncrpc/", 0660, AID_ROOT, AID_SYSTEM, 1 },
- {"/dev/adsp/", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- {"/dev/mt9t013", 0660, AID_SYSTEM, AID_SYSTEM, 0 },
- {"/dev/akm8976_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 },
- {"/dev/akm8976_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- {"/dev/akm8976_pffd", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- {"/dev/msm_pcm_out", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- {"/dev/msm_pcm_in", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- {"/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- {"/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- {"/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 },
- {"/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 },
- {"/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 },
- {"/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 },
- {"/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 },
- {"/dev/htc-acoustic", 0640, AID_RADIO, AID_RADIO, 0 },
- {NULL, 0, 0, 0, 0 },
- };
✿ init.c
init.rc腳本和老版本android中的init.goldfish.rc腳本很早就被parse_config_file()函數解析將腳本內容分為幾個段,early-init,init,early-boot,boot,和各個服務。然後在不同的時間點上執行各個段得命令或者開啟各種服務。
init.c的一段節選:
- int main(intargc, char**argv)
- {
- ……
- mkdir("/dev",0755);
- mkdir("/proc",0755);
- mkdir("/sys",0755);
- mount("tmpfs","/dev", "tmpfs", 0, "mode=0755");
- mkdir("/dev/pts",0755);
- mkdir("/dev/socket",0755);
- mount("devpts","/dev/pts", "devpts", 0, NULL);
- mount("proc","/proc", "proc", 0, NULL);
- mount("sysfs","/sys", "sysfs", 0, NULL);
- … …
- INFO("readingconfig file\n");
- parse_config_file("/init.rc");
- //調用parse_config解析init.rc腳本
- //經過解析,init.rc的內容就被分為多少個段,被串在action_list鏈表中。
- //on開頭的都是action類型的段,比如init段,init段用一個結構體struct action表示,其中name是init,
- //所有這個段內的命令,都被串在commands鏈表中。
-
- action_for_each_trigger("early-init",action_add_queue_tail);
- //遍歷action_list鏈表,查找name是early-init的那個action,將這個節點放在action_queue的尾部。
- drain_action_queue();
- //將action_queue尾部的節點遍歷,然後刪除。
- //就相當於遍歷name是early-init的action節點內的commands鏈表。
- //就是在執行init.rc腳本中onearly-init段內的所有命令。
-
- ……
- INFO("deviceinit\n");
- device_fd= device_init(); //常見必要的設備節點
-
- property_init();//init 以後的任務就是proper_service
-
- action_for_each_trigger("init",action_add_queue_tail); //將init段,加入action_queue
- drain_action_queue();// 執行init段得命令
-
- … …
- }
✿ 本節小結
device_init其實就是linux中的udev的一個簡單的替代。把/sys/下的所有內核提供的設備都安排在/dev下創建設備節點。如果要改動/dev/一些設備的權限,可以把chmod 777寫在init.rc中,但是要注意寫的位置,不能太早執行,不能寫在early-init段內,因為那時/dev/下的設備節點還沒有被創建。
在devices.c中修改的方法隱藏的較深不容易被發現,但是如果init.rc內再次修改就可能把之前的修改覆蓋掉。