firefox1.4 rilproxy.c 浅析

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主要用于权限检查,多数情况下,EUIDUID相同,但是当设置了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功能:
 允许配置接口
允许管理IP防火墙IP伪装和帐户
允许配置socket调试选项
允许修改路由表
允许配置socket上的进程的组属性
允许绑定所有地址的透明代理
允许配置TOS(服务类型)
允许配置混杂模式
允许清除驱动状态
允许多点传送
允许读或写系统记录

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;

}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值