歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

為Android應用程序讀取/dev下設備而提權

倘若應用程序需要對/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中,詳細分析如下:
  1. //分別遍歷/sys/class /sys/block /sys/devices   
  2. device_init()  
  3. {  
  4.   coldboot(fd,"/sys/class");  
  5.   coldboot(fd,"/sys/block");  
  6.   coldboot(fd,"/sys/devices");  
  7. }  
  8.      
  9. //後面有個遞歸 /sys下是內核生成的設備,這就相當於udev的作用   
  10. do_coldboot()  
  11. {  
  12.   if(fd>= 0) {  
  13.   write(fd,"add\n", 4);  
  14.   close(fd);  
  15.   handle_device_fd(event_fd);  
  16.   }  
  17. }  
  18.   
  19. //從socket裡讀出add處理   
  20. handle_device_fd()   
  21. {  
  22.   if(!strcmp(uevent->action,"add")) {  
  23.   make_device(devpath,block, uevent->major, uevent->minor);  
  24.   return;  
  25.   }  
  26. }  
  27.   
  28. //得到設備的相關信息創建設備節點   
  29. make_device()   
  30. {  
  31.   mode= get_device_perm(path,&uid, &gid) | (block ? S_IFBLK : S_IFCHR);  
  32.   dev= (major << 8) | minor;  
  33.   mknod(path,mode, dev);  
  34.   chown(path,uid, gid);  
  35. }  
  36.   
  37. get_device_perm()  
  38. {  
  39.   if(get_device_perm_inner(qemu_perms, path, uid, gid, &perm) == 0) {  
  40.   returnperm;  
  41.   }elseif(get_device_perm_inner(devperms,path, uid, gid, &perm) == 0){  
  42.    returnperm;  
  43.   }else{  
  44.                 …….  
  45. }  
  46.   
  47. //得到devperms結構體的信息   
  48. get_device_perm_inner  
  49. {  
  50.  for(i= 0; perms[i].name; i++) {  
  51.   
  52.  if(perms[i].prefix){  
  53.  if(strncmp(path,perms[i].name, strlen(perms[i].name)))  
  54.  continue;  
  55.  }else{  
  56.  if(strcmp(path,perms[i].name))  
  57.  continue;  
  58.  }  
  59.  *uid= perms[i].uid;  
  60.  *gid= perms[i].gid;  
  61.  *perm= perms[i].perm; //權限位   
  62.  return0;  
  63.  }  
  64. }  
  65.   
  66. 這是devperms的具體內容  
  67. structperms_ {  
  68.    char*name;  
  69.    mode_tperm;  
  70.    unsignedintuid;  
  71.    unsignedintgid;  
  72.    unsignedshortprefix;  
  73. };  
  74. staticstructperms_ devperms[] = {  
  75. {"/dev/null", 0666, AID_ROOT, AID_ROOT, 0 },  
  76. {"/dev/zero", 0666, AID_ROOT, AID_ROOT, 0 },  
  77. {"/dev/full", 0666, AID_ROOT, AID_ROOT, 0 },  
  78. {"/dev/ptmx", 0666, AID_ROOT, AID_ROOT, 0 },  
  79. {"/dev/tty", 0666, AID_ROOT, AID_ROOT, 0 },  
  80. {"/dev/random", 0666, AID_ROOT, AID_ROOT, 0 },  
  81. {"/dev/urandom", 0666, AID_ROOT, AID_ROOT, 0 },  
  82. {"/dev/ashmem", 0666, AID_ROOT, AID_ROOT, 0 },  
  83. {"/dev/binder", 0666, AID_ROOT, AID_ROOT, 0 },  
  84.   
  85. /* logger should be world writable (for logging) but not readable*/  
  86. {"/dev/log/", 0662, AID_ROOT, AID_LOG, 1 },  
  87.   
  88. /*these should not be world writable */  
  89. {"/dev/Android_adb", 0660, AID_ADB, AID_ADB, 0 },  
  90. {"/dev/android_adb_enable", 0660, AID_ADB, AID_ADB, 0 },  
  91. {"/dev/ttyMSM0", 0660, AID_BLUETOOTH, AID_BLUETOOTH, 0 },  
  92. {"/dev/alarm", 0664, AID_SYSTEM, AID_RADIO, 0 },  
  93. {"/dev/tty0", 0666, AID_ROOT, AID_SYSTEM, 0 },  
  94. {"/dev/graphics/", 0660, AID_ROOT, AID_GRAPHICS, 1 },  
  95. {"/dev/hw3d", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },  
  96. {"/dev/input/", 0660, AID_ROOT, AID_INPUT, 1 },  
  97. {"/dev/eac", 0660, AID_ROOT, AID_AUDIO, 0 },  
  98. {"/dev/cam", 0660, AID_ROOT, AID_CAMERA, 0 },  
  99. {"/dev/pmem", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },  
  100. {"/dev/pmem_gpu", 0660, AID_SYSTEM, AID_GRAPHICS, 1 },  
  101. {"/dev/pmem_adsp", 0660, AID_SYSTEM, AID_AUDIO, 1 },  
  102. {"/dev/pmem_camera", 0660, AID_SYSTEM, AID_CAMERA, 1 },  
  103. {"/dev/oncrpc/", 0660, AID_ROOT, AID_SYSTEM, 1 },  
  104. {"/dev/adsp/", 0660, AID_SYSTEM, AID_AUDIO, 1 },  
  105. {"/dev/mt9t013", 0660, AID_SYSTEM, AID_SYSTEM, 0 },  
  106. {"/dev/akm8976_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 },  
  107. {"/dev/akm8976_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 },  
  108. {"/dev/akm8976_pffd", 0640, AID_COMPASS, AID_SYSTEM, 0 },  
  109. {"/dev/msm_pcm_out", 0660, AID_SYSTEM, AID_AUDIO, 1 },  
  110. {"/dev/msm_pcm_in", 0660, AID_SYSTEM, AID_AUDIO, 1 },  
  111. {"/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 },  
  112. {"/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 },  
  113. {"/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 },  
  114. {"/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 },  
  115. {"/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 },  
  116. {"/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 },  
  117. {"/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 },  
  118. {"/dev/htc-acoustic", 0640, AID_RADIO, AID_RADIO, 0 },  
  119. {NULL, 0, 0, 0, 0 },  
  120. };  

✿ init.c

       init.rc腳本和老版本android中的init.goldfish.rc腳本很早就被parse_config_file()函數解析將腳本內容分為幾個段,early-init,init,early-boot,boot,和各個服務。然後在不同的時間點上執行各個段得命令或者開啟各種服務。
   
init.c的一段節選:
  1. int main(intargc, char**argv)  
  2. {  
  3.   ……  
  4.   mkdir("/dev",0755);   
  5.   mkdir("/proc",0755);  
  6.   mkdir("/sys",0755);  
  7.   mount("tmpfs","/dev""tmpfs", 0, "mode=0755");  
  8.   mkdir("/dev/pts",0755);  
  9.   mkdir("/dev/socket",0755);  
  10.   mount("devpts","/dev/pts""devpts", 0, NULL);  
  11.   mount("proc","/proc""proc", 0, NULL);  
  12.   mount("sysfs","/sys""sysfs", 0, NULL);  
  13.   … …  
  14.   INFO("readingconfig file\n");  
  15.   parse_config_file("/init.rc");   
  16. //調用parse_config解析init.rc腳本   
  17. //經過解析,init.rc的內容就被分為多少個段,被串在action_list鏈表中。   
  18. //on開頭的都是action類型的段,比如init段,init段用一個結構體struct action表示,其中name是init,   
  19. //所有這個段內的命令,都被串在commands鏈表中。   
  20.   
  21.   action_for_each_trigger("early-init",action_add_queue_tail);   
  22. //遍歷action_list鏈表,查找name是early-init的那個action,將這個節點放在action_queue的尾部。   
  23.   drain_action_queue();  
  24. //將action_queue尾部的節點遍歷,然後刪除。   
  25. //就相當於遍歷name是early-init的action節點內的commands鏈表。   
  26. //就是在執行init.rc腳本中onearly-init段內的所有命令。   
  27.   
  28. ……  
  29.   INFO("deviceinit\n");  
  30.   device_fd= device_init(); //常見必要的設備節點   
  31.   
  32.   property_init();//init 以後的任務就是proper_service   
  33.   
  34.   action_for_each_trigger("init",action_add_queue_tail); //將init段,加入action_queue   
  35.   drain_action_queue();// 執行init段得命令   
  36.   
  37. … …  
  38. }  

✿ 本節小結

       device_init其實就是linux中的udev的一個簡單的替代。把/sys/下的所有內核提供的設備都安排在/dev下創建設備節點。如果要改動/dev/一些設備的權限,可以把chmod 777寫在init.rc中,但是要注意寫的位置,不能太早執行,不能寫在early-init段內,因為那時/dev/下的設備節點還沒有被創建。
      在devices.c中修改的方法隱藏的較深不容易被發現,但是如果init.rc內再次修改就可能把之前的修改覆蓋掉。
Copyright © Linux教程網 All Rights Reserved