zoukankan      html  css  js  c++  java
  • ANDROID BINDER机制浅析

    Binder是Android上一种IPC机制,重要且较难理解。由于Linux上标准IPC在灵活和可靠性存在一定不足,Google基于OpenBinder的设计和构想实现了Binder。

    本文只简单介绍其实现,并重点讨论Binder安全相关的内容。详细的Binder设计与实现分析,参考附录4篇文章。

    一、Binder 实现

    Android Binder由Client、Server、Service Manager和Binder驱动4个部件组成,下图引自网络。

    在类UNIX系统中,进程是相互独立的,一个进程不能访问另一个进程的内存空间。然而内核控制着所有进程,因此可以暴露一个接口用作IPC。在Binder中这个接口就是/dev/binder设备,该设备由Binder内核驱动程序实现。

    Binder驱动是整个Binder架构的核心,所有IPC都通过它来实现。

    上图的Client与Server可以看作2个进程,其IPC通过对/dev/binder的ioctl实现。从Android源码可以看到,ioctl使用binder_write_read的结构体收发数据。

    其中write_buffer包含驱动要执行的命令,read_buffer包含用户层需要执行的命令:

    binder_write实现对bs->fd的ioctl()操作:

    bs->fd是打开/dev/binder得到的文件描述符:

    实际数据如何在进程间传输呢?

    Binder驱动管理着每个进程的一部分地址空间。Binder管理的内存,对于进程是只读的,其写操作由内核模块实施。当一个进程向另一个进程发送消息时,内核在目标进程的内存空间申请一部分空间,接着直接将数据从发送进程复制进去。然后它将接收消息的具体位置,通过一个短消息通知给接收进程。因为消息在接收者的内存空间,接收者可以直接访问到消息。当进程不再需要这个数据时,它通知Binder驱动来释放这一内存块。

    可以发现,数据经过了一次复制,所以Binder的效率不如共享内存。

    Android中更高层次的IPC抽象,如Intent(跨进程组件间传递带有关联数据的命令),Messenger(支持跨进程消息通信的对象),ContentProvider(暴露跨进程数据管理接口的组件),均是基于Binder实现的。

    二、Binder 安全

    下图展示Binder IPC架构的一个简单例子。

    每个通过Binder框架实现IBinder接口,允许被访问调用的对象都可被称作Binder对象。对Binder对象的调用在一个Binder事务处理(transaction)内部实现,其中包括一个对目标对象的引用、需执行方法的ID和一个数据缓冲区。

    Binder驱动会将调用进程的ID(PID)和有效用户ID(EUID)自动添加到事务处理数据。被调用进程可以检查PID和EUID,然后基于内部实现逻辑来决定是否执行所请求的方法。

    因为PID和EUID是由内核填写的,所以调用者进程不能通过伪造身份标识来获取超出系统允许的权限。这是Android安全模型的核心之一,所有更高层次抽象,比如权限,均是建立在它之上。调用者的PID和EUID通过类android.os.Binder的getCallingPid()和getCallingUid()来访问,他们是Android公开API的一部分。

    三、Binder 令牌

    Binder对象的一个重要属性是它具有跨进程、独一无二的身份标识。因此如果进程A创建了一个Binder对象,然后将之传递给进程B,进程B再将之传递给进程C,那么对这3个进程的调用,均由同一个Binder对象处理。实际上,进程A会通过内存地址直接引用Binder对象,而进程B和C使用Binder对象的句柄。

    内核负责维护活动的Binder对象与它们在其他进程中的句柄之间的映射关系。因为一个Binder的标志符是独一无二的,并且由内核负责维护,所以用户空间进程除非通过IPC机制处理,否则不可能创建一个Binder对象的副本或获取相关引用(后面介绍如何获得Binder对象引用)。因此Binder对象是唯一的、不可伪造的、可通信的对象,可以作为安全令牌使用。

    这也使得Android可以使用基于权能的安全模型(capability-based security)。

    基于权能的安全模型中,通过赋予程序一个不可伪造的权能,授权程序对特定资源的访问权限。在Android中,Binder对象可以表示权能。

    在这种使用方式下,Binder对象又被称作Binder令牌(Binder Token)。一个Binder令牌可以是一种权能,也可以是一个目标资源。一个进程拥有一个Binder令牌,授权该进程对Binder对象的完全访问控制权限,从而使其能够在目标对象上执行Binder事务处理操作。如果Binder对象实现了多个动作(基于Binder事务处理的code参数,选择要执行的动作),只要调用者拥有一个Binder对象的引用,就可以执行任意操作。如果需要更细粒度的访问控制,那么每个操作需要相应实现必要的权限检查,这通常利用调用者进程的PID和EUID来实现。

    以上看到,获取了Binder对象引用(Binder令牌)后,就获取了目标Binder对象的完全访问权限,如果Binder事务处理操作涉及敏感动作,这是危险的。

    在Android中,通常对于system(UID 10000)或root(UID 0)权限下运行的调用进程,允许执行所有操作,而对于其他进程要执行额外的权限检查。因此控制对一个重要Binder对象的访问,有2种方式:一是通过限制谁可以获得Binder对象的引用,另一个是执行该Binder对象动作前,检查调用者的身份标志(需要Binder对象自己实现)。

    Binder对象可以没有其他功能实现,只被作为权能使用。这种模式下,多个协作进程可同时拥有同一个Binder对象,而作为服务端的进程(处理客户端请求)使用Binder令牌来验证它的客户端,就像Web服务器使用会话Cookie一样。

    四、Binder 对象访问

    出于安全考虑,Android控制着对Binder对象的访问,与Binder对象通信的唯一方法是使用该对象的引用。但很多Binder对象需要被全局访问的(尤其是系统服务)。分发所有Binder对象到每个进程是不切实际的,所以需要一种机制,来允许进程主动发现和获取这些Binder对象的引用。

    Android使用servicemanger原生守护进程实现了这种发现机制。

    servicemanger先于系统服务启动,因此系统服务在启动时,传递服务名和一个Binder对象引用到servicemanger进行注册。一旦注册成功,任何客户端都可以通过服务名获取它的Binder对象引用。然而大部分系统服务有额外的权限检查,所以获得引用不能自动确保对它所有功能的访问。

    同时因为在servicemanger上注册后,任何人都可以访问该Binder对象引用,所以出于安全考虑,只有一部分在白名单内的系统进程才可以注册为系统服务。

    可以通过service list命令查看已注册系统服务列表,该命令返回每个已注册服务的名称和实现的IBinder接口。

    五、附录

    Android进程间通信(IPC)机制Binder简要介绍和学习计划

    Android深入浅出之Binder机制

    Android Bander设计与实现 - 设计篇

    Android Binder设计与实现 - 实现篇

  • 相关阅读:
    git线上操作
    IDEA快捷方式
    Java 四种线程池
    java 获取当前天之后或之前7天日期
    如何理解AWS 网络,如何创建一个多层安全网络架构
    申请 Let's Encrypt 通配符 HTTPS 证书
    GCE 部署 ELK 7.1可视化分析 nginx
    使用 bash 脚本把 AWS EC2 数据备份到 S3
    使用 bash 脚本把 GCE 的数据备份到 GCS
    nginx 配置 https 并强制跳转(lnmp一键安装包)
  • 原文地址:https://www.cnblogs.com/gm-201705/p/9864065.html
Copyright © 2011-2022 走看看