Android6.0系统源码加自启动shell脚本service服务,并增加SELinux策略sepolicy权限

实现功能:开机时自动执行set_xxx.sh脚本,把system/yyy 目录下的 zzz.db 文件复制到 data/data/com.android.ppp/databases 文件夹下(xxx、yyy、zzz、ppp为举例用,增加替换成自己的名字)

第一步:

新建set_xxx.sh脚本,内容如下(脚本执行log通过echo输出内容到data/zzz_log.txt,调试完建议注释掉)

#!/system/bin/sh

Top_Path="/"
System_Path="${Top_Path}system"
Data_Path="${Top_Path}data"
NewDatabase="${System_Path}/vendor/yyy/zzz.db"
NewDatabaseJournal="${System_Path}/vendor/yyy/zzz.db-journal"
Database_Dir="${Data_Path}/data/com.android.ppp/databases"
Database="${Database_Dir}/zzz.db"
DatabaseJournal="${Database_Dir}/zzz.db-journal"
Log_file="${Data_Path}/copy_db_log.txt"

newDbMd5="1"
preDbMd5="0"
#判断存放log的文件是否存在,不存在就新建
if [ ! -f "/data/$Log_file" ];then
	cd $Data_Path
	touch $Data_Path/copy_db_log.txt
	cd $Top_Path
	echo "-----------copy db-----------" > $Log_file
	echo "Log_file is no exit, make it." >> $Log_file
fi
#判断数据库所在路径中的文件夹是否存在,不存在就新建
if [ -d $Database_Dir ];then
	echo "Database_Dir is exit" >> $Log_file
else
	echo "Database_Dir is not exit, mkdir..." >> $Log_file
	if [ ! -d $Data_Path ]; then
		cd $Top_Path
		mkdir -p "data"
	fi
	cd $Data_Path
	mkdir -p "data/com.android.ppp/databases"
fi
#判断数据库文件是否存在,存在就删除
if [ -f $Database ];then
	echo "Database database is exit" >> $Log_file
	rm -rf ${Database}
	echo "${Database} database is removed" >> $Log_file
fi

echo "Database database is not exit, it will cp!" >> $Log_file

i=0
#进行拷贝数据库操作,拷贝成功会跳出循环,失败就循环执行,尝试3次
while ((i<3))
do  
	cp -f $NewDatabase $Database
	sync
	cp -f $NewDatabaseJournal $DatabaseJournal
	sync
	preDbMd5=$(md5sum $Database | busybox awk '{print $1}')
	newDbMd5=$(md5sum $NewDatabase | busybox awk '{print $1}')
	echo "preDbMd5="$preDbMd5" newDbMd5="$newDbMd5" is copy finish!" >> $Log_file
	if [ "$newDbMd5" == "$preDbMd5" ];then
		echo "Database copy success!" >> $Log_file
		chmod 771 $Database_Dir
		chmod 660 $Database
		chmod 400 $NewDatabaseJournal
        #这里system:system是文件所有者和所在组,要与文件夹保持一致,可以在开机时用adb进入ls -al查看文件夹
		chown -R system:system $Database_Dir 
		break
	fi
	echo "Database while do "$i" >>>>" >> $Log_file
	let i++
	echo "Database copying sleep 0.5 >>>>" >> $Log_file
	sleep 0.5
done

echo "Database copy done, ok!!!" >> $Log_file

第二步:

进入自己的项目路径,例如:device/board/project(board板型或方案,project具体项目),找到sepolicy文件夹,project文件夹中没有就到device/下面的common中,反正找到自己项目用的sepolicy目录,在目录下file_contexts文件中,在最后添加:

# add
/system/bin/set_xxx.sh    u:object_r:set_xxx_exec:s0

意思是将/system/bin/set_xxx.sh文件在打包system.img时设置安全上下文为u:object_r:set_xxx_exec:s0,用于保护其不被别的进程可以随意调用执行/system/bin/set_xxx.sh,只有具有权限执行type为set_xxx_exec的进程才可以执行set_xxx.sh。

第三步:

为了使其能够添加到servicemanager中去并且能够访问系统资源,我们还要再在sepolicy目录下添加set_xxx.te文件,在文件里面添加脚本要用到的权限,内容如下:

##############################
# add
#
# set_xxx sh selinux
##############################
#设置set_xxx属于domain域,是一个进程的type;mlstrustedsubject设置shelld是一个可信任的主题
type set_xxx, domain, mlstrustedsubject; 
#设置set_xxx_exec属于可执行文件的类型
type set_xxx_exec, exec_type, file_type;

#for debug,下面这行permissive是在不知道具体要哪些权限的时候打开,用来暂时获得所有权限,
#具体需要的权限可以通过logcat里的提示逐一添加,添加完权限把这里注释掉
#permissive set_xxx;

init_daemon_domain(set_xxx)
#具体需要的权限:
allow set_xxx shell_exec:file { entrypoint read };
allow set_xxx self:capability { dac_override chown };
allow set_xxx system_data_file:dir  { write add_name create add_name setattr read open };
allow set_xxx system_data_file:file { create open write append setattr };
allow set_xxx system_file:file { execute_no_trans };
allow set_xxx self:process execmem;

查看需要添加哪些权限的方法,先用上面说的permissive暂时获得所有权限,然后抓logcat,搜关键字avc,类似下面的log:

11-18 19:01:38.970 14835 14835 W cp      : type=1400 audit(0.0:16179): avc: denied { write } for name="com.android.inputmethod" dev="mmcblk0p20" ino=113346 scontext=u:r:set_xxx:s0 tcontext=u:object_r:system_data_file:s0:c512,c768 tclass=file permissive=0

这条log可以大概解读为在执行cp 拷贝命令的时候,set_xxx需要system_data_filefile文件类型的wirte权限,也就是:

allow set_xxx system_data_file:file { write };

其它的类似逐个添加上就行,全部添加完,确认logcat中没有再提示用到哪些权限,就可以注释掉permissive这一行。

注意:如果编译的时候提示有的权限不被允许添加使用,可以在android/external/sepolicy/domain.te文件中,找到对应权限限制的地方,排除掉我们的sh的限制,比如:

neverallow {
  domain
  -recovery
  -system_server
  -system_app
  -init
  -rild
  -radio_config
  -emsd
  -lc-elog
  -lc-dump
  -lc-poweron-log
  -lc-oms-mla
  -lc-mla-manager
  -lc-oms-amt
  -amt-local
  -installd # for relabelfrom and unlink, check for this in explicit neverallow
  -lc-oms-sa
  -logd
  -factory
  -akmd09911
  -set_xxx #add 排除system_data_file:file不能写的系统限制
} system_data_file:file no_w_file_perms;

第四步:

在init.rc文件中添加如下内容:

#add
on property:persist.sys.cpdb=0
    stop set_xxx
on property:persist.sys.cpdb=1
    start set_xxx

service set_xxx /system/bin/sh /system/bin/set_xxx.sh
    user root
    group root
    oneshot
    seclabel u:r:set_xxx:s0

通过改变属性persist.sys.cpdb的值来改变是否后续开机需要启动该脚本service。

可能碰到开机的时候sh脚本先start执行,然后再stop的问题,这会造成cp的db文件已开始拷贝,但是因为没拷贝完不能用,只需要在sh文件中执行前添加上sleep 零点几秒即可,如下

#!/system/bin/sh

#加上0.4s的sleep,防止先start执行脚本,再stop
sleep 0.4

Top_Path="/"
System_Path="${Top_Path}system"
Data_Path="${Top_Path}data"

第五步:

在具体的项目的device.mk中添加如下内容:

#add
PRODUCT_PROPERTY_OVERRIDES += \
        persist.sys.cpdb=1

到此,我们添加的sh文件service服务就能正常执行启动了,上层源码可以通过如下方法控制开启/关闭:

//获取属性的值
int sp = SystemProperties.getInt("persist.sys.cpdb",1);
//设置属性的值,控制开关
SystemProperties.set("persist.sys.cpdb","0");

记录以备下次用,如有错误,欢迎留意指正,谢谢!

参考:

Android 6.0中SELinux的TE简介

init.rc中添加服务以在开机时启动脚本

RK3399 Android 7.1.2 添加.sh的开机服务

--------------------------2021.9.8 更新 分割线----------------------------

主体(Subject):等同于进程。

目标/对象(Target/Object):被主体访问的资源,如文件、设备、端口等等,也可以称呼客体。

上面的log:

11-18 19:01:38.970 14835 14835 W cp      : type=1400 audit(0.0:16179): avc: denied { write } for name="com.android.inputmethod" dev="mmcblk0p20" ino=113346 scontext=u:r:set_xxx:s0 tcontext=u:object_r:system_data_file:s0:c512,c768 tclass=file permissive=0

这条log可以重新解读为:

执行cp 拷贝命令的时候,主体上下文 set_xxx 需要目标客体上下文 system_data_file 的 file 文件类型的 wirte 权限。

ps -Z 查看主体安全上下文

ls -Z 查看客体安全上下文

参考:

SELinux MAC安全机制简介_林多

Android-SEAndroid权限问题指南_IT先森

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值