1. 介绍
这里介绍的是基于开启selinux的Android 4.4及以上版本添加自启用应用的方法
2. 关于selinux
Android下的selinux被称为SEAndroid, 其原理可以参考Linux下的selinux, 这里不详细介绍
3. 为sshd添加自启动
在前面文章<Android上sshd的使用>中, 笔者为sshd添加自启动由于selinux的存在一直失败
这里作为一个补充为sshd添加seplicy以保证能成功启动
3.1 修改init.rc
对于CM, 其init.rc位于/system/core/rootdir/目录下
笔者这里不使用启动start-sshd脚本的方法, 而直接启动应用程序,
在init.rc将sshd启动配置修改如下
service sshd /system/bin/sshd -f /system/etc/ssh/sshd_config -D
class main
user root
oneshot
3.2 添加sshd.te文件
为sshd定义sepolicy
Android默认的sepolicy位于external/sepolicy/
而厂商自定义sepolicy通常位于devices/platform/platform-sub/sepolicy/
对于i9100, 位于device/samsung/galaxys2-common/selinux
对于CM, 我们添加到external/sepolicy/目录下即可
sshd.te内容如下, 这里只是申明, 并没有规则
# sshd daemon
type sshd, domain;
type sshd_exec, exec_type, file_type;
init_daemon_domain(sshd)
同时要保证sshd.te文件要编译到sepolicy中, 部分系统可能需要修改external/sepolicy/Android.mk
将sshd.te加入BOARD_SEPOLICY_UNION中
笔者使用的CM会自动添加external/sepolicy/*.te, 故只要添加文件即编译到sepolicy中
3.3 修改file_contexts
file_contexts位于external/sepolicy/目录下, 厂商同样也有自定义该
该文件通过正则表达式来描述系统文件的安全上下文
为sshd加入如下内容
/system/bin/sshd u:object_r:sshd_exec:s0 ... /data/ssh(/.*)? u:object_r:sshd_data_file:s0
上面的内容将sshd定义为sshd_exec文件类型, 将sshd配置文件设置为sshd_data_file类型
同时修改external/sepolicy/file.te, 定义sshd_data_file类型
# /data/ssh - sshd conf files
type sshd_data_file, file_type, data_file_type;
3.4 修改selinux模式
在CentOS中selinux有如下三种模式
# SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - No SELinux policy is loaded.
而在Android中则精简为enforcing (1)和permissive (0)两种模式
enforcing模式会严格执行权限操作, 一旦越权则禁止运行; permissive则只是记录行为, 并不终止运行
我们的目的是为了让sshd工作在enforcing模式下, 这里先设置为permissive模式
selinux相关命令如下
# getenforce Enforcing # setenforce 0 # getenforce Permissive
但是上面的命令只能临时生效, 重启后就恢复为默认的模式(enforcing)
所以我们需要编译出默认就是permissive模式的Android版本, 方法有下面两种
3.4.1 通过脚本设置selinux模式
参考<Set Selinux to permissive on boot>的做法
写一个脚本, 在脚本中设置selinux模式, 放在init.d或者su.d目录下, 让init或者su在启动时执行
笔者没有使用该方法, 因为感觉对sshd不一定起作用, 而且这也不是标准做法
3.4.2 配置默认selinux模式
在参考<Disabling SELinux in Android 5.0.1>了解到
selinux由init进程(system/core/init/init.cpp)来初始化, 调用时序为
main() -> selinux_initialize() -> selinux_is_disabled()/selinux_is_enforcing()
-> ALLOW_DISABLE_SELINUX -> selinux_status_from_cmdline()
其中ALLOW_DISABLE_SELINUX宏来判断selinux是否允许被禁用(包括disable和permissive), 否则后面不用再进行判断
ALLOW_DISABLE_SELINUX是在编译时就制定, 位于system/core/init/Android.mk(userdebug和eng为1)
selinux_status_from_cmdline()通过读取内核传递的命令行中androidboot.selinux的值来判断selinux模式
判读依据为disabled和permissive或其他
在笔者的Android上, 命令行参数如下
# cat /proc/cmdline console=ttySAC2,115200 consoleblank=0 androidboot.hardware=smdk4210 loglevel=4 console=ram sec_debug.enable=0 sec_debug.enable_user=0 c1_watchdog.sec_pet=5 sec_log=0x100000@0x4d900000 s3cfb.bootloaderfb=0x5ec00000 ld9040.get_lcdtype=0x2 consoleblank=0 lpj=3981312 vmalloc=144m
那么我们可以配置内核命令行参数来控制selinux的默认模式
内核命令行参数是在编译时通过BOARD_KERNEL_CMDLINE来指定
笔者使用的i9100中该值位于 device/samsung/galaxys2-common/BoardCommonConfig.mk
找到对应位置在后面加上androidboot.selinux=permissive
3.5 编译Android
在上面的修改之后, 重新编译Android
笔者使用lunch xxx命令重新编译升级后发现selinux仍然是enforcing模式
通过/proc/cmdline获取内核命令发现并没有生效
查看编译中间件$PACKG/BOOT/cmdline, $PACKG/BOOT/cmdline也是如此
$PACKG = out/target/product/i9100/obj/PACKAGING/target_files_intermediates/
于是笔者删除$PACKG目录下的所有内容, 再次编译升级
这次仍然没有成功, 也不清楚是什么原因, 这卧槽谁受得了
懒得去折腾了, 修改selinux_is_enforcing()函数直接返回SELINUX_PERMISSIVE
3.6 sshd权限
3.6.1 截取avc log
此时sshd应该已经成功启动, 为了查看所有sshd需要的权限, 使用ssh client进行一次连接
同时连接sftp及scp, 传递文件等动作
然后通过logcat截取log, 然后找到所有sshd相关的log
12-13 19:28:25.050 2009 2009 I sshd : type=1400 audit(0.0:15): avc: denied {open
} for name="ssh_host_rsa_key" dev=mmcblk0p10 ino=49165 scontext=u:r:sshd
:s0 tcontext=u:object_r:system_data_file
:s0 tclass=file
permissive=1
3.6.2 生成规则
对照被deny的项目可以按照如下方法来生产规则
scontext tcontext tclass avc denied allowsshd system_data_file: file open
网上称使用audit2allow工具可以批量生成规则
由于在我的CentOS 7上一直提示指定policy文件, 不深究
3.6.3 添加规则
将所有生成的规则加入到sshd.te中, 然后重新编译升级
sshd.te文件内容如下
# sshd daemon
type sshd, domain; type sshd_exec, exec_type, file_type; #init_daemon_domain(sshd) net_domain(sshd) allow sshd self:capability { setuid setgid net_admin net_raw net_bind_service }; allow sshd sshd_exec:file execute_no_trans; allow sshd sshd_data_file:file { open read create getattr setattr append write link unlink rename }; allow sshd sshd_data_file:dir { create setattr add_name remove_name rmdir rename }; allow sshd ptmx_device:chr_file { open read write ioctl getattr setattr }; allow sshd devpts:chr_file { open read write ioctl getattr setattr }; allow sshd shell_exec:file rx_file_perms; allow sshd system_file:file rx_file_perms;
上面的方法在一定程度上适用, 但部分功能仍然受限制
不折腾了, init.cpp中的修改已经完全够用了
4. 应用层的自启动
上面的自启动是基于C或者说底层的自启动,下面介绍一种在应用层面或者Java层面的自启动方法
具体<How to Start an Application at Device Bootup in Android>
参考:
<android init.rc文件语法详解>
<深入理解SELinux SEAndroid>
<Android 5.x 权限问题解决方法>
<android中SELINUX规则分析和语法简介>
<Android 4.0及以上版本接收开机广播BOOT_COMPLETED、开机自启动服务>