rilproxy分析 FFOS 1.4
作用:
This repo contains utilities for forwarding the rild socket connection out to non radio account owned processes. 翻译理解如下: Rilproxy 向非radio 用户的进程转发rild socket 链接 |
RILD进程 如下:
Adb shell ps 结果如下: USER PID PPID VSIZE RSS WCHAN PC NAME radio 882 1 9704 980 ffffffff b6f4de7c S /system/bin/rild_sp radio 883 1 10728 1016 ffffffff b6f64e7c S /system/bin/rild_sp |
adb shell busybox ps –efl 结果如下: PID USER TIME COMMAND 882 1001 0:00 /system/bin/rild_sp -l /system/lib/libreference-ril_sp.so 883 1001 0:01 /system/bin/rild_sp -l /system/lib/libreference-ril_sp.so |
Rilproxy 进程如下:
Adb shell ps 结果如下: USER PID PPID VSIZE RSS WCHAN PC NAME root 1 0 576 408 c00e0080 0001a2b4 S /init radio 95 1 920 372 c00e0080 b6f5c7bc S /system/bin/rilproxy radio 96 1 920 372 c00e0080 b6f777bc S /system/bin/rilproxy radio 106 1 920 364 c00e0080 b6f8b7bc S /system/bin/rilproxy |
adb shell busybox ps –efl 结果如下: PID USER TIME COMMAND 95 1001 0:00 /system/bin/rilproxy -c 1 96 1001 0:00 /system/bin/rilproxy -c 2 |
B2g 进程如下:
adb shell ps 结果如下: USER PID PPID VSIZE RSS WCHAN PC NAME root 897 1 219028 82400 ffffffff b6f29734 S /system/b2g/b2g |
adb shell busybox ps –efl 结果如下: PID USER TIME COMMAND 897 0 6:02 /system/b2g/b2g |
在init.b2g.rc 中
在Init.xxx.rc 中
1. 调用 create_socket() (system/core/init/util.c), 创建一个Socket fd, 将这个fd 与某个文件(/dev/socket/xxx,xx就是上面列到的名字,比如,zygote) 绑定(bind), 根据init.rc 里面定义来设定相关的用户,组和权限。最后返回这个fd。
2. 将socket 名字和 fd 注册到init 进程的环境变量里,这样所有的其他进程(所有进程都是init的子进程)都可以通过 getenv(name)获取到这个fd.
Adb shell ,查看当前运行的rilproxy 进程如下:
我们来看ril_proxy 的代码:
在rilproxy 中一共有4个函数,分别为:
void switchUser()
staticint writeToSocket(int fd,constvoid*buffer, size_t len)
constchar* getSocketName(constchar* defval,unsignedint client_id)
int main(int argc,char**argv)
switchUser函数
switchUser函数设置进程uid,设置进程权限。
具体实现如下:
void switchUser(){ /* EUID主要用于权限检查,多数情况下,EUID和UID相同,但是当设置了setuid位之后,任何运行该程序的进程均可获得该文件拥有者的权限,即EUID在此时等于程序拥有者的UID。 参考:passwd进程,用户可以修改自身的密码信息,而passwd文件的属主是root。 */ prctl(PR_SET_KEEPCAPS,1,0,0,0); /*在要fork出新的Process时,若使用者不为Root,会通过PR_SET_KEEPCAPS设置,以让当新的Process 改变UID時,所被赋予的权限不被清掉*/ setuid(1001); //设置进程pid
struct __user_cap_header_struct header; struct __user_cap_data_struct cap; header.version = _LINUX_CAPABILITY_VERSION; header.pid =0; cap.effective = cap.permitted =1<< CAP_NET_ADMIN; cap.inheritable =0; //设置进程权限 CAP_NET_ADMIN capset(&header,&cap); } |
CAP_NET_ADMIN功能: |
writeToSocket函数
staticint writeToSocket(int fd,constvoid*buffer, size_t len){ size_t write_offset =0; const uint8_t *to_write;
to_write =(const uint8_t *)buffer;
while(write_offset < len){ ssize_t written; do{ //向fd socket里面写相应数据 written = write (fd, to_write + write_offset, len - write_offset); }while(written <0&& errno == EINTR);
if(written >=0){ write_offset += written; }else{ LOGE("RIL Response: unexpected error on write errno:%d", errno); close(fd); return-1; } }
return0; } |
getSocketName函数
constchar* getSocketName(constchar* defval,unsignedint client_id){ staticchar buf[128]; staticint offset =0; if(client_id >0){ constchar*p = buf + offset; offset += snprintf(buf + offset,sizeof(buf)- offset,"%s%u", defval, client_id); offset++; return p; //返回组装后的socketname } return defval; } |
main函数
代码如下:
int main(int argc,char**argv){
int rild_rw; int rilproxy_conn; int ret; unsignedint client_id =0; constchar* rild_socket =NULL; constchar* rilproxy_socket =NULL;
// while 循环,解析传入参数 // 如:rilproxy2 /system/bin/rilproxy -c 2
while((ret = getopt(argc, argv,"c:s:"))!=-1){ // getopt 函数,获取执行rilproxy 的参数,有两个一个是 –c 另一个是-s
switch(ret){ case'c':{ if(sscanf(optarg,"%u",&client_id)!=1){ // 将传入参数组装成client_id ,此时client_id = 2 LOGE("invalid client id specified: %s", optarg); return-1; } break; } case's':{ rild_socket = optarg; break; } default: return-1; } }
rilproxy_socket = getSocketName(RILPROXY_SOCKET_NAME, client_id); // 组装socket 的name,此处rilproxy_socket = rilproxy2 if(!rild_socket){ rild_socket = getSocketName(RILD_SOCKET_NAME, client_id); }
// connect to the rilproxy socket //创建rilproxy socket 对象,具体实现在(b2g\system\core\libcutils\ Socket_local_server.c) rilproxy_conn = socket_local_server( rilproxy_socket, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM ); if(rilproxy_conn <0){ LOGE("Could not connect to %s socket: %s\n", rilproxy_socket, strerror(errno)); return1; }
// switchUser 函数,设置进程uid 以及进程权限 switchUser(); struct passwd *pwd =NULL; pwd = getpwuid(getuid()); if(pwd !=NULL){ if(strcmp(pwd->pw_name,"radio")==0){ LOGD("Converted to radio account"); }else{ LOGE("Cannot convert to radio account"); } }else{ LOGE("Cannot convert to radio account, getpwuid error."); }
int connected =0;
while(1) { LOGD("Waiting on socket"); int rilproxy_rw; struct pollfd connect_fds; struct sockaddr_un peeraddr; socklen_t socklen =sizeof(peeraddr);
connect_fds.fd = rilproxy_conn; connect_fds.events = POLLIN; connect_fds.revents =0; poll(&connect_fds,1,-1); //等待连接 rilproxy_rw = accept(rilproxy_conn,(struct sockaddr*)&peeraddr,&socklen);
if(rilproxy_rw <0){ LOGE("Error on accept() errno:%d", errno); /* start listening for new connections again */ continue; } ret = fcntl(rilproxy_rw, F_SETFL, O_NONBLOCK);
if(ret <0){ LOGE ("Error setting O_NONBLOCK errno:%d", errno); }
LOGD("Socket connected"); connected =1;
while(1){ //链接rild LOGD("Connecting to socket %s\n", rild_socket); rild_rw = socket_local_client( rild_socket, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM ); if(rild_rw >=0){ break; } LOGE("Could not connect to %s socket, retrying: %s\n", rild_socket, strerror(errno));
connect_fds.fd = rilproxy_conn; connect_fds.events = POLLIN; connect_fds.revents =0; if(poll(&connect_fds,1,1000)>0){ goto reconnect_rilproxy; } } LOGD("Connected to socket %s\n", rild_socket); char data[1024];
struct pollfd fds[2]; fds[0].fd = rilproxy_rw; fds[0].events = POLLIN; fds[0].revents =0; fds[1].fd = rild_rw; fds[1].events = POLLIN; fds[1].revents =0;
while(connected) { poll(fds,2,-1); if(fds[0].revents >0) { fds[0].revents =0; while(1) { //从rilproxy_rw 读数据 ret = read(rilproxy_rw, data,1024); if(ret >0){ //写入rild socket读数据 writeToSocket(rild_rw, data, ret); } elseif(ret <=0) { LOGE("Failed to read from rilproxy socket, closing..."); connected =0; break; } if(ret <1024) { break; } } } if(fds[1].revents >0) { fds[1].revents =0; while(1){ //从rild socket 读数据 ret = read(rild_rw, data,1024); if(ret >0){ //写入rilproxy socket writeToSocket(rilproxy_rw, data, ret); } elseif(ret <=0){ LOGE("Failed to read from rild socket, closing..."); connected =0; break; } if(ret <1024){ break; } } } } close(rild_rw); reconnect_rilproxy: close(rilproxy_rw); } return0; } |