详解Android 安全机制

时间:2012-04-29来源:网络
被卸载,但数据还有保留),或者 package 数据结构中根本不含有这个 permission-tree ,那么将这个permission-tree 清除。

  2. 清除不一致的 permission 信息。如果 packageSettings 或者 package 结构为空(未解析该 package 或者被卸载,但数据有保留),或者package 中根本没有定义该 permission ,那么将该 permission 清除。

  第九步。对每一个 package 进行轮询,并进行 permission 授权。

  1. 对申请的权限进行检查,并更新 grantedPermissions 列表

  2. 如果其没有设置 shared user id ,那么将其 gids 初始化为 mGlobalGids ,它从 permission.xml 中读取。

  3. 遍历所有申请的权限,进行如下检查

  1 )如果是该权限是 normal 或者 dangerous 的。通过检查。

  2 )如果权限需要签名验证。如果签名验证通过。还需要进行如下检查

  * 如果程序升级,而且是 system package 。那么是否授予该权限要看原来的 package 是否被授予了该权限。如果被授予了,那么通过检查,否则不通过。

  * 如果是新安装的。那么检查通过。

  4. 如果 3 中检查通过,那么将这个 permission 添加到 package 的 grantedPermissions 列表中,表示这个 permission 申请成功( granted)。申请成功的同时会将这个申请到的 permission 的 gids 添加到这个 package 的 gids 中去。

  5. 将 permissionsFixed 字段标准为 ture ,表示这个 packge 的 permission 进行过修正。后续将禁止对非 system 的 app 的权限进行再次修正。

  2.1.3 Dynamic permission 的管理

  PackageManagerService 提供了 addPermission/ removePermission 接口用来动态添加和删除一些权限。但是这些权限必须是所谓的动态权限( BasePermission.TYPE_DYNAMIC )。

  一个 Package 如果要添加 Dynamic permissions ,首先必须要在 manifest 中申明 permission-tree> 标签,它实际上是一个权限的名字空间(例如,“ com.foo.far ”这个权限就是 permission-tree “com.foo ”的成员),本身不是一个权限。一个 Package 只能为自己的 permission-tree 或者拥有相同的 uid 的 package 添加或者删除权限。

  Package 不能够通过这种接口去修改在 manifest 中静态申请的权限,否则抛出异常。

  首先查找这个 permission 在全局 permission 列表 mSettings.mPermissions 中是否存在。如果存在,而且类型为BasePermission.TYPE_DYNAMIC 那么根据传入的权限信息修改全局表中的权限信息,并触发 permissions.xml 的持久化。

  如果在全局的 permission 列表 mSettings.mPermissions 中没有找到,先找到这个 permission 所在 permissionTree ,然后添加到全局permission 列表 mSettings.mPermissions 中去,并触发 permissions.xml 的持久化。

  2.1.4 Uri permission 的管理

  下面两个 接口 主要用于 Uri permission 的管理 (其实现在 ActivityManagerService 中)。

  // 为指定的 uid 和 targetPkg 添加对某个 content Uri 的读或者写权限。

  public void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri, int mode) throws RemoteException;

  // 清除所有通过 grantUriPermission 对某个 Uri 授予的权限。

  public void revokeUriPermission(IApplicationThread caller, Uri uri, int mode) throws RemoteException;

  grantUriPermission 主要的实现过程分析。

  grantUriPermission 分析:

  1. 验证 caller 的 ProcessRecord 和 targetPkg 不为空。否则检测不通过。

  2. 验证所请求的 mode 为 Intent.FLAG_GRANT_READ_URI_PERMISSION 或者为 Intent.FLAG_GRANT_WRITE_URI_PERMISSION ,否则不通过。

  3. 确保参数 Uri 是一个 content Uri 。否则,则检测不通过。

  4. 通过 Uri 得到目标 ContentProvider ,如果不存在,则检测不通过。

  5. 从 PackageManagerService 中获得 targetPkg 对应的 uid 。

  6. 检查 target uid 所对应的 package 是否真正需要这个权限?

  先判断要申请的是读还是写权限,然后查看对应的 ContentProvider 中对应的 readPermission writePermission 字段是否保存了权限名称。如果该字段不为空,则以 target uid 和该权限名去PackageManagerService 中去查找该 uid 是否被 granted 了该权限。如果已经获得了该权限,那么无需再去为这个 Activity 去申请这个 Uri 权限了,返回。否者继续执行如下操作。

  7. 检查这个 ContentProvider 的 grantUriPermissions 开关变量,是否允许对其它 package 进行权限的 grant 操作。如果禁止,那么抛出异常。

  8. 检查这个 ContentProvider 是否设置了 Uri 的过滤类型 uriPermissionPatterns ,如果设置了过滤类型,则将需要申请权限的 Uri 与之匹配。匹配不同过,则抛出异常。

  9. 检查调用者自己是否有权限访问这个 Uri 。如果没有,抛出异常。

  10. 从 mGrantedUriPermissions 中取得 target uid 对应的 HashMap《Uri, UriPermission》 数据结构。用 target uid 和 Uri 生成UriPermission 并保存在 mGrantedUriPermissions 中。

  revokeUriPermission 实现分析。

  找到该 Uri 对应的 ContentProvider ,然后删除 mGrantedUriPermissions 中与 Uri 对应的所有权限。

  2.2 permission 的动态检查

  这里的动态检查是指是 package 在程序运行过程中进行某些操作或者数据访问时才进行的 check ,与之对应的是应用程序安装或者升级时 PackageManagerService 通过扫描包中的静态权限信息相对应。

  系统与权限 检查 相关的机制的实现主要集中在 PackageManagerService 和 ActivityManagerService 中。 ActivityManagerService 主要负责的是底层的 uid 层次的身份检查; PackageManagerService 则维护了 uid 到自己拥有的和被授予的权限的一张表。在通过 ActivityManagerService 的身份检查后, PackageManagerService 根据请求者的 uid 来查看这张表,判断其是否具有相应的权限。

  除此之外, per-URI permission 机制的实现也需要一张表,它维护在 ActivityManagerService 中,它建立了从 content URI 到被授权访问这个 URI 的 component 之间的映射。但是它也需要借助 PackageManagerService 的机制来辅助实现。

  2.2.1 framework 提供的接口

  Android framework 中提供了一些接口用来对外来的访问(包括自己)进行权限检查 。 这些接口 主要通过 ContextWrapper 提供,具体实现在 ContextImpl 中 。如果 package 接受到外来访问者的操作请求,那么可以调用这些接口进行权限检查。一般情况下可以把这些接口的检查接口分为两种,一种是返回错误,另一种是抛出异常。

  主要包含如下几组:

  n permission 和 uid 检查 API

  下面这一组接口主要用来检查某个调用(或者是其它 package 或者是自己)是否拥有访问某个 permission 的权限。参数中 pid 和 uid 可以指定,如果没有指定,那么 framework 会通过 Binder 来获取调用者的 uid 和 pid 信息,加以填充。返回值为 PackageManager.PERMISSION_GRANTED 或者 PackageManager.PERMISSION_DENIED 。

  public int checkPermission(String permission, int pid, int uid) // 检查某个 uid 和 pid 是否有 permission 权限

  public int checkCallingPermission(String permission) // 检查调用者是否有 permission 权限,如果调用者是自己那么返回PackageManager.PERMISSION_DENIED

  public int checkCallingOrSelfPermission(String permission) // 检查自己或者其它调用者是否有 permission 权限

  下面这一组和上面类似,如果遇到检查不通过时,会抛出异常,打印消息 。

  public void enforcePermission(String permission, int pid, int uid, String message)

  public void enforceCallingPermission(String permission, String message)

  public void enforceCallingOrSelfPermission(String permission, String message)

  n per-URI 检查 API

  为某个 package 添加访问 content Uri 的读或者写权限。

  public void grantUriPermission(String toPackage, Uri uri, int modeFlags)

  public void revokeUriPermission(Uri uri, int modeFlags)

  检查某个 pid 和 uid 的 package 是否拥有 uri 的读写权限,返回值表示是否被 granted 。

  public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags)

  public int checkCallingUriPermission(Uri uri, int modeFlags)

  public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags)

  public int checkUriPermission(Uri uri, String readPermission,String writePermission, int pid, int uid, int modeFlags)

  检查某个 pid 和 uid 的 package 是否拥有 uri 的读写权限,如果失败则抛出异常,打印消息 。

  public void enforceUriPermission(Uri uri, int pid, int uid, int modeFlags, String message)

  public void enforceCallingUriPermission(Uri uri, int modeFlags, String m

1 2 3

关键词: Android 安全机制 签名机制 权限

加入微信
获取电子行业最新资讯
搜索微信公众号:EEPW

或用微信扫描左侧二维码

相关文章

查看电脑版