Android应用层对设备的访问权限的实现

android应用层对设备的访问权限的实现


如果应用程序出现打开设备权限不够的错误,可能是创建设备节点时赋予的权限不够。

问题:摄像头总是权限不够,只能在shell下重新设置可用。
分析:android对设备节点的管理不是使用udev,在init里面,system/core/init/下的init.c和devices.c里对设备节点的创建设定了权限。


Andoid安全机制包括两个层次:系统层和应用层。应用层的安全机制建立在授权与申请基础上,本文不讲。系统层的安全机制包括给 每个用户进程分配单独的uid和gid,使用进程本身可以防止地址空间的共享,从而避免使用线程方式对数据的全局可见性。使用了uid则对于外存也加了封 锁,当然这得感谢UNIX的用户空间机制。系统层安全机制还包括对设备访问的控制,在这个方面,Android的做法与传统有所不同。

Android除了给予用户进程以单独的uid外,给系统服务也分配了固定的uid,诸如system/core/include/private/android_filesystem_config.h文件中定义了这些固定的uid:

  1. define AID_SYSTEM 1000 
    #define AID_RADIO 1001 
    #define AID_BLUETOOTH 1002 
    #define AID_GRAPHICS 1003 
    #define AID_INPUT 1004 
    #define AID_AUDIO 1005 
    #define AID_CAMERA 1006 
    #define AID_LOG 1007 
    ......................................

传统的做法是,除了root,其它全是普通用户,两类用户的权限在内核里是规定死的,这也保证了UNIX内核的安全性。比如dev目录下的设备文 件,一般用户主是root,而且对其他用户不开放读写能力。用户使用设备一般通过系统调用如ioctl,而系统调用属于受信代码。

Android的问题是,引入的这些系统用户,实际上在权限方面是无法与普通uid区分的,如果系统用户能访问一个设备,那么一般用户也 能。所以,Andoid没有别的选择,只能默认开启设备文件的全局读写。这在systemcore/init/device.c做了定义:

{ "/dev/urandom", 0666, AID_ROOT, AID_ROOT, 0 },
{ "/dev/ashmem", 0666, AID_ROOT, AID_ROOT, 0 },
{ "/dev/binder", 0666, AID_ROOT, AID_ROOT, 0 },

.....................................

设备文件当然还是存放于/dev目录下,但dev目录的填充不是由udev做的,而是由Android的init进程做的。这个步骤由make_device函数完成,各个设备的权限来自于上述device.c文件的规定。

这种设备权限分配的潜在危险是,任何用户进程都可以操作设备,如果底层设备驱动有漏洞,那么整个系统的安全性就是存在风险的,而UNIX系统最大的安全隐患,正是来自于设备驱动。


在Android中,由于没有mdev和udev,所以它没有办法动态的生成设备节点,那么它是如何做的呢?

我们可以在system/core/init/下的init.c和devices.c中找到答案:

init.c中的int main(int argc, char **argv) 
创建了一些基本的设备节点。

int main(int argc, char **argv) 

... 

/* Get the basic filesystem setup we need put 
* together in the initramdisk on / and then we'll 
* let the rc file figure out the rest. 
*/ 
mkdir("/dev", 0755); 
mkdir("/proc", 0755); 
mkdir("/sys", 0755); 

mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755"); 
mkdir("/dev/pts", 0755); 
mkdir("/dev/socket", 0755); 
mount("devpts", "/dev/pts", "devpts", 0, NULL); 
mount("proc", "/proc", "proc", 0, NULL); 
mount("sysfs", "/sys", "sysfs", 0, NULL); 

for(;;) { 
... 
if (ufds[0].revents == POLLIN) 
handle_device_fd(device_fd); 

if (ufds[1].revents == POLLIN) 
handle_property_set_fd(property_set_fd); 
if (ufds[3].revents == POLLIN) 
handle_keychord(keychord_fd); 


return 0; 
}


我们再来看看handle_device_fd(),该函数定义在devices.c中
void handle_device_fd(int fd) 

... 
handle_device_event(&uevent); 
handle_firmware_event(&uevent); 


而handle_device_event定义如下:
static void handle_device_event(struct uevent *uevent) 

... 
if(!strcmp(uevent->action, "add")) { 
make_device(devpath, block, uevent->major, uevent->minor); 
return; 

... 

make_device定义如下:
static void make_device(const char *path, int block, int major, int minor) 

... 
mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR); 
dev = (major << 8) | minor; 
... 
setegid(gid); 
mknod(path, mode, dev); 
chown(path, uid, -1); 
setegid(AID_ROOT);
}

其他动态设备的节点创建,android也规定好了设备节点的名字和权限等。下面这个函数会返回你要创建的设备节点的权限,如果列表中没 有,就会使用默认600,当然这样的话,应用程序使用设备就会出现问题,所以,你要把你的设备加到列表 static struct perms_ devperms[] 中。

我们看看get_device_perm如下实现:
static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid) 

mode_t perm; 

if (get_device_perm_inner(qemu_perms, path, uid, gid, &perm) == 0) { 
return perm; 
} else if (get_device_perm_inner(devperms, path, uid, gid, &perm) == 0) { 
return perm; 
} else { 
struct listnode *node; 
struct perm_node *perm_node; 
struct perms_ *dp; 

/* Check partners list. */ 
list_for_each(node, &devperms_partners) { 
perm_node = node_to_item(node, struct perm_node, plist); 
dp = &perm_node->dp; 

if (dp->prefix) { 
if (strncmp(path, dp->name, strlen(dp->name))) 
continue; 
} else { 
if (strcmp(path, dp->name)) 
continue; 

/* Found perm in partner list. */ 
*uid = dp->uid; 
*gid = dp->gid; 
return dp->perm; 

/* Default if nothing found. */ 
*uid = 0; 
*gid = 0; 
return 0600; 


我们最后可以看到在devperms中定义了要生成的设备节点:
static struct perms_ devperms[] = { 
{ "/dev/null", 0666, AID_ROOT, AID_ROOT, 0 }, 
{ "/dev/zero", 0666, AID_ROOT, AID_ROOT, 0 }, 
{ "/dev/full", 0666, AID_ROOT, AID_ROOT, 0 }, 
{ "/dev/ptmx", 0666, AID_ROOT, AID_ROOT, 0 }, 
{ "/dev/tty", 0666, AID_ROOT, AID_ROOT, 0 }, 
{ "/dev/random", 0666, AID_ROOT, AID_ROOT, 0 }, 
{ "/dev/urandom", 0666, AID_ROOT, AID_ROOT, 0 }, 
{ "/dev/ashmem", 0666, AID_ROOT, AID_ROOT, 0 }, 
{ "/dev/binder", 0666, AID_ROOT, AID_ROOT, 0 }, 

/* logger should be world writable (for logging) but not readable */ 
{ "/dev/log/", 0662, AID_ROOT, AID_LOG, 1 }, 

/* the msm hw3d client device node is world writable/readable. */ 
{ "/dev/msm_hw3dc", 0666, AID_ROOT, AID_ROOT, 0 }, 

/* gpu driver for adreno200 is globally accessible */ 
{ "/dev/kgsl", 0666, AID_ROOT, AID_ROOT, 0 }, 

/* these should not be world writable */ 
{ "/dev/diag", 0660, AID_RADIO, AID_RADIO, 0 }, 
{ "/dev/diag_arm9", 0660, AID_RADIO, AID_RADIO, 0 }, 
{ "/dev/android_adb", 0660, AID_ADB, AID_ADB, 0 }, 
{ "/dev/android_adb_enable", 0660, AID_ADB, AID_ADB, 0 }, 
{ "/dev/ttyMSM0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 }, 
{ "/dev/ttyHS0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 }, 
{ "/dev/uinput", 0660, AID_SYSTEM, AID_BLUETOOTH, 0 }, 
{ "/dev/alarm", 0664, AID_SYSTEM, AID_RADIO, 0 }, 
{ "/dev/tty0", 0660, AID_ROOT, AID_SYSTEM, 0 }, 
{ "/dev/graphics/", 0660, AID_ROOT, AID_GRAPHICS, 1 }, 
{ "/dev/msm_hw3dm", 0660, AID_SYSTEM, AID_GRAPHICS, 0 }, 
{ "/dev/input/", 0660, AID_ROOT, AID_INPUT, 1 }, 
{ "/dev/eac", 0660, AID_ROOT, AID_AUDIO, 0 }, 
{ "/dev/cam", 0660, AID_ROOT, AID_CAMERA, 0 }, 
{ "/dev/pmem", 0660, AID_SYSTEM, AID_GRAPHICS, 0 }, 
{ "/dev/pmem_adsp", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
{ "/dev/pmem_camera", 0660, AID_SYSTEM, AID_CAMERA, 1 }, 
{ "/dev/oncrpc/", 0660, AID_ROOT, AID_SYSTEM, 1 }, 
{ "/dev/adsp/", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
{ "/dev/snd/", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
{ "/dev/mt9t013", 0660, AID_SYSTEM, AID_SYSTEM, 0 }, 
{ "/dev/msm_camera/", 0660, AID_SYSTEM, AID_SYSTEM, 1 }, 
{ "/dev/akm8976_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 }, 
{ "/dev/akm8976_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 }, 
{ "/dev/akm8973_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 }, 
{ "/dev/akm8973_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 }, 
{ "/dev/bma150", 0640, AID_COMPASS, AID_SYSTEM, 0 }, 
{ "/dev/cm3602", 0640, AID_COMPASS, AID_SYSTEM, 0 }, 
{ "/dev/akm8976_pffd", 0640, AID_COMPASS, AID_SYSTEM, 0 }, 
{ "/dev/lightsensor", 0640, AID_SYSTEM, AID_SYSTEM, 0 }, 
{ "/dev/msm_pcm_out", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
{ "/dev/msm_pcm_in", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
{ "/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
{ "/dev/msm_snd", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
{ "/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
{ "/dev/audience_a1026", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
{ "/dev/tpa2018d1", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
{ "/dev/msm_audpre", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 
{ "/dev/msm_audio_ctl", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 
{ "/dev/htc-acoustic", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 
{ "/dev/vdec", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 
{ "/dev/q6venc", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 
{ "/dev/snd/dsp", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 
{ "/dev/snd/dsp1", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 
{ "/dev/snd/mixer", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 
{ "/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 }, 
{ "/dev/qemu_trace", 0666, AID_SYSTEM, AID_SYSTEM, 0 }, 
{ "/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 }, 
{ "/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 }, 
{ "/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 }, 
{ "/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 }, 
/* CDMA radio interface MUX */ 
{ "/dev/ts0710mux", 0640, AID_RADIO, AID_RADIO, 1 }, 
{ "/dev/ppp", 0660, AID_RADIO, AID_VPN, 0 }, 
{ "/dev/tun", 0640, AID_VPN, AID_VPN, 0 }, 
{ NULL, 0, 0, 0, 0 }, 
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
除了游戏之外,Android 应用几乎全部是使用 Java 编写的,但是最近 Google 内部正在悄悄地测试另一种高性能的 Android 编程方式,那就 Google 的 Sky 项目。Sky 项目使用网页开发语言 Dart 开发原生 Android 应用,强调应用的运行速度和与 Web 的高度集成。Javascript 已经有 20 年的历史,有很多理念已经跟不上时代,编程体验也很差,因此 Chrome V8 引擎团队开发了 Dart 语言。最近 Google 的技术发布会展示了 Dart on Android 项目。它有另一个好记的名字,叫做 Sky。快速响应是 Sky 最大的目标之一。60 FPS 普遍意义上应用流畅的标准,即需要每 16 ms 绘制一帧,但是却也是很多 Android 开发者始终无法达到的目标。但是 Sky 不一样:Sky 官方的 demo 已经达到了 60 FPS,而 Sky 官方则是要致力于带来 120 FPS 的应用体验。Sky 团队提供了一个简单的 demo, 并且已经达到了 1.2 ms 绘制一帧的惊人速度。虽然这个界面很简单,但是至少也能证明 Sky 达到 120 FPS 的目标(8 ms 一帧)不仅仅是一句空话。并且Dart 团队表示,Sky 的界面渲染和内部执行并不会互相干扰。即便可能因为网络问题或者其他问题导致内部运行速度很慢,界面仍然流畅灵敏。Sky 项目的 Web 背景使得任何 Sky 的可移植性大大提高。只要装上 Dart 虚拟机,那么任何平台都可以执行 Sky 应用,包括 iOS。虽然 Sky 应用的格式是 APK,但是实际上 Sky 是基于 HTTP 协议的,当然也通过浏览器的兼容性实现了自己的兼容性部署,是的任何人都能运行最新版的应用。除此之外,URLs 也是 Dart 的基础层之一。因此有人认为,Sky 应用完全依赖网络,没有网络的情况下应用便不能运行,并且启动应用的时候都需要先用一两秒下载数据。但是实际上,这些都可以通过缓存解决。通过 HTTP 协议提供服务可以大大缩短开发时间。和普通的“编写、编译、安装”三部曲不同的是,Sky 应用可以完全在 HTTP 上编辑代码,客户端只需要关闭,然后打开,“刷新”一下,便可以不更新而直接使用最新版的应用。除此之外,Sky 还为 Android 开发者提供一系列的设计工具,例如 action bar,出没效果、导航面板、以及其他各种你所想得到想不到的组件。当然,Sky 也有许多安全问题有待解决。Sky 应用具备 Android 应用的所有特点,和普通的 Android 应用一样,是有权限访问所有的 Android API 的。但是考虑到 Sky 会从网页上更新应用和数据,那么安全性便不容忽视。Sky 团队的 Github Pages 上写着“我们正在频繁地更新 Sky,因此 Sky 框架还没有完全定型,不同版本的框架和底层也可能会产生兼容性问题”。示例代码:<sky> [removed] import 'package:your_app_name/main.dart'; void main() {   new HelloWorldApp(); } [removed] </sky>库:import 'package:sky/framework/fn.dart'; class HelloWorldApp extends App {   UINode build() {     return new Text('Hello, world!');   } }介绍内容来自 segmentfault

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值