以Android L读取系统所有logcat并写入文件为例分析Android 以添加系统进程的方式申请selinux的权限执行shell脚本,以及avc:dined应该怎么申请权限

添加selinux较好的文章,可以通过adb shell dmesg > kenel.log 获取kmesg 可以看到 avc:dined 相关内容

首先说说环境:

基于Android L的aosp修改(修改对于此文基本无影响)过的sorce code.

本来的思路是通过setenforcing permissive来开启宽容模式,可是宽容模式就是selinux的debug模式就相当于关掉了seliux毫无安全可言,而下面说到的,是以我的读取系统logcat并写入文件为例,来讲在selinux中申请我们所需的权限。

系统服务:

在init.rc里面声明service,这个service并不是android的service,而是进程,用我启动logcat的服务为例:

首先为了格式,找到声明service的地方。然后添加:

service start_logcat /system/bin/start_logcat.sh
       oneshot
      disabled
 
   on property:service.start_logcat=1
       start start_logcat
 

看看代码。

第一段:

第一行:service代表声明,start_logcat是service的名字 /system/bin/start_logcat.sh是指的这个service指向的(要执行的脚本的路径) 注意了,这个路径指的是安卓系统也就是build之后的路径,而我放在system/bin下是因为这里的start_logcat.sh被我赋予了可执行的权限(后面会说怎么赋予),我第一次做的时候创建了脚本用chmod 777给的权限,实际是毫无意义的。

扫描二维码关注公众号,回复: 6189264 查看本文章

第二行代码的oneshot指的是只执行一次。

第三行代码的disabled指的是开机不启动。

第二段:

第一行代码的on跟java代码的if同意 后面用property关键字声明了一个key为 service.start_logcat的property。整行的意思就是 声明一个key是service.start_logcat的property并且在其value是1的时候执行下一行代码。

第二行代码显然易见启动 start_logcat service。

也就是说 我们在安卓程序里 只要调用( 其中SystemProperties可能需要用到反射来调用set方法):

SystemProperties.set("service.start_logcat", "1");

系统监听到key为service.start_logcat的property的value变为1的时候就会去启动这个service去执行脚本.

还有一种启动方式 是不需要上面的第二段代码只声明一个service 然后在调用的时候通过这种方式:

SystemProperties.set("ctl.start", "start_logcat");
这种方式也会启动我们的系统服务去执行指向的脚本。


好,接下来说重点,重点是,我这个脚本执行(别忘记将脚本在.mk文件中cp到system/bin下)的内容是:

logcat -v time -f /sdcard/logcat -r 600000-n 1

也就是在sdcard下创建名为logcat的文件,大小为600M。一共2个文件交替着去记录logcat 超过600M就交替。

上篇文章说到了Android L之后selinux相关的权限限制,有兴趣的可以去看看。

接下来就说说遇到的问题。

首先,会报一个叫service:start_logcat  selinux needs a domian 是这个错,大致是这么写的。

然后下面会报avc:dined的错误(待会会详细说这个错误怎么解决)。

后面会着重讲解avc:dined的错误,先看第一个错。第一个错的意思呢就是我们的service在执行脚本的时候selinux约束必须有domain 

具体做法就是去device/xx/common/sepolicy 里面添加 一个.te文件(同级目录下有一个system_app.te,如果在这儿添加是不需要用system service的方式的,但是会开放对所有systemapp的权限,请谨慎处理),以logcat为例,创建start_logcat.te 并且在 file_contexts 下添加:

/system/bin/start_logcat.sh  u:object_r:start_logcat_exec:s0
这个就是上面说到的让 /system/bin/start_logcat.sh具备可以执行的权限。

接下来看看.te文件,同样以logcat为例:

  #Additional rules for shell
  type start_logcat, domain;
  type start_logcat_exec, exec_type, file_type;
   
  init_daemon_domain(start_logcat)
  
  # allow shell to run dmesg
  allow start_logcat kernel:system syslog_read;
  allow start_logcat toolbox_exec:file { read getattr open execute execute_no_trans };
  allow start_logcat logcat_exec:file { read getattr open execute execute_no_trans };
  allow start_logcat serial_device:chr_file rw_file_perms;
  allow start_logcat shell_exec:file read;
  allow start_logcat self:capability dac_override;
  allow start_logcat system_data_file:dir { write add_name };
  allow start_logcat system_data_file:file { create open append };
  allow start_logcat logd:unix_stream_socket {connectto};
  allow start_logcat vfat:dir { search write add_name create };
  allow start_logcat logdr_socket:sock_file {create write};
  allow start_logcat vfat:file create_file_perms;
  allow start_logcat system_file:file execute_no_trans;
将一个类型设置为另一个类型的属性可以通过type语句实现,type start_logcat, domain; 表示将类型 domain设置为start_logcat的属性。这样就可以表明start_logcat描述的类型是用来描述进程的安全上下文的。
对于type start_logcat_exec, exec_type, file_type; 同理。

在# allow shell to run dmesg 这行注释下面的代码都是为start_logcat这个服务在selinux申请的权限。当然logcat可能不需要这么多权限, 我是考别的文件 然后在基础上添加需要的。

接下来问题来了,我们怎么知道都需要哪些权限。

有趣的是,我并不知道我需要什么权限,wtf。

能想到的唯一答案就是通过avc:dined的报错来分析我需要什么样的权限。

那么首先就要会看avc:dined的错误。

还是以logcat为例:

avc: denied { connectto } for pid=1712 comm="logcat" path="/dev/socket/logdr" scontext=u:r:start_logcat:s0 tcontext=u:r:logd:s0 tclass=unix_stream_socket permissive=0
这个呢 就是selinux在enforcing模式下的安全策略的限制报出的错。

接下来看看这个log我们应该怎么看:

denied {}     代表缺少什么          connectto

scontext      代表谁缺少             start_logcat

tcontext      代表对哪个文件       logd

tclass           代表文件类型           unix_stream_socket


现在再来看看上面的报错。 也就是说 我们的start_logcat的服务 对unix_stream_socket类型的logd文件缺少connectto的权限。

那么我们自然知道.te的规则文件怎么写了,在start_logcat.te中添加 :

allow start_logcat logd:unix_stream_socket {connectto};
允许start_logcat对unix_stream_socket类型的logd文件有connectto的操作。

酱紫(继续build,然后如果报错,按上所述添加需要的权限),我们就完成了安卓向selinux申请所需权限并执行所需脚本从0到有的整个过程。


ps:如果有更好的可以知道做什么需要什么权限的办法 ,欢迎告知,学习为主。

顺便附上查看kernellog的命令:

adb shell cat /proc/kmsg

这个是以我自己的logcat为例来讲述的整个selinux申请所需权限的过程,如果有不对,欢迎指出,共同进步。
 

猜你喜欢

转载自blog.csdn.net/sdkdlwk/article/details/88814380