1 efuse and dm-verity
1.1 qcom efuse - 對bootloader簽名
熔絲檔案:sec.dat
1)燒寫signed bootloader
2)將密匙檔案sec.dat燒寫入efuse
3)重啟設備,設備的bootROM會讀取efuse中的密匙pubk驗證bootloader
4)bootloader驗證通過,啟動,開始AVB驗證流程
1.2 編譯時關閉AVB
@ BoardConfig.mk
BOARD_AVB_ENABLE := false
BOARD_BUILD_DISABLED_VBMETAIMAGE := true
AndroidO之后沒有獨立的recovery.img,boot.img根據cmdline引數來決定mount哪個ramdisk,
如果有skip_initramfs引數,那么mount打包在system.img中的normal ramdisk;否則mount打包在boot.img中的recovery ramdisk,
引數BOARD_BUILD_SYSTEM_ROOT_IMAGE的配置決定是將normal ramdisk打包到boot.img中還是打包到system.img中,
打包到boot.img中:
BOARD_BUILD_SYSTEM_ROOT_IMAGE := false
打包到system.img中:
BOARD_BUILD_SYSTEM_ROOT_IMAGE := true
1.3 AVB驗證流程
需要提前掛載磁區的fstab來自于commandline的androidboot.android_dt_dir
1)bootloader使用內置的OEM pubk驗證vbmeta.img,驗證通過后用vbmeta.img中的boot pubk驗證boot.img,如果驗證通過就啟動boot.img
2)init啟動后,init/fs_mgr使用vbmeta.img中的vendor pubk、system pubk、odm pubk驗證vendor.img、system.img、odm.img,驗證通過就mount,否則不會mount
Figure 1-1 dm-verity的作業流程
編譯生成Metadata流程:
@ build/core/Makefile
->
@ build/tools/releasetools/build_image.py
->
BuildVerityTree() - 用來生成dm_verity需要的簽名資料
BuildVerityMetadata() - 生成Metadata資料
->
@ system/extras/verity/build_verity_metadata.py
->
build_verity_metadata()
1.4 Disable System dm-verity
@ device/{ro.boot.hardware}/{ro.board.platform}/fstab.{ro.boot.hardware}
Change
/dev/block/bootdevice/by-name/system /system ext4 ro,barrier=1,discard wait, avb
to
/dev/block/bootdevice/by-name/system /system ext4 ro,barrier=1,discard wait
可以使用內核配置 CONFIG_DM_VERITY_HASH_PREFETCH_MIN_SIZE(默認大小為 128)來啟用 dm-verity 哈希預提取大小,該修改可提升啟動速度,
1.5 Android 8.0 userdebug版本運行時禁止dm-verity
Android 8.0 dm-verity disable flag存在于vbmeta.img(keystore磁區)中;而老版本是放置在system.img磁區的dm-verity metadata中,
1)在設定中打開OEM unlocking選項
2)在設定中打開USB debugging選項
3)adb reboot bootloader
4)fastboot flashing unlock和fastboot oem unlock
5)fastboot reboot
6)adb root
7)adb disable-verity
8)adb reboot
9)adb root
10)adb remount
1.6 Android 8.0 userdebug版本刷機時禁止dm-verity
Android 8.0 dm-verity disable flag存在于vbmeta.img(keystore磁區)中;而老版本是放置在system.img磁區的dm-verity metadata中,
1)在設定中打開OEM unlocking選項
2)在設定中打開USB debugging選項
3)adb reboot bootloader
4)fastboot flashing unlock和fastboot oem unlock
5)fastboot --disable-verity --disable-verification flash vbmeta vbmeta.img
6)fastboot reboot
7)adb root
8)adb remount
1.7 vbmeta for AVB disabled
#!/bin/sh
MY_PATH=${PWD}
TARGET_DIR=${MY_PATH}/out/target/product/${TARGET_PRODUCT}
AVB_TOOL=${MY_PATH}/external/avb/avbtool
TESTKEY=${MY_PATH}/external/avb/test/data/testkey_rsa4096.pem
python ${AVB_TOOL} make_vbmeta_image --output ${TARGET_DIR}/vbmeta_disabled.img \
--include_descriptors_from_image ${TARGET_DIR}/boot.img \
--include_descriptors_from_image ${TARGET_DIR}/system.img \
--include_descriptors_from_image ${TARGET_DIR}/vendor.img \
--setup_rootfs_from_kernel ${TARGET_DIR}/system.img \
--set_hashtree_disabled_flag \
--key ${TESTKEY} \
--algorithm SHA256_RSA4096
2 Android selinux
2.1 LSM(Linux Security Module)的五種實作
AppArmor:應用盔甲,AppArmor is installed by default in Ubuntu
SELinux:Security Enhanced Linux,基于inode,Android當前使用的就是這種
SMACK:Simple Mandatory Access Control Kernel,基于inode
Tomoyo:日本女人名“智代”,日本人實作的代碼,基于path
Yama:來自梵文,中文名為“閻羅”,只處理ptrace和檔案鏈接
2.2 注釋
avc - Access Vector Cache
avd - Access Vector Decision,訪問向量決策
ssid - 主體的安全標識
tsid - 客體的安全標識
tclass - 客體安全型別
requested - 申請檢查的權限
auditdata - 附加的審計資料,主要產生審計日志,供內核kauditd和用戶auditd保存日志到磁盤中,當權限檢查失敗時,內核會列印審計不通過的log,參考博客另一篇文章Linux auditd
2.3 編譯時強制打開selinux
BOARD_KERNEL_CMDLINE += androidboot.selinux=enforcing
2.4 查看設備節點的sepolicy權限
ls -alZ /dev/kmsg
2.5 not_full_treble
如果遇到execute_no_trans無法通過編譯neverallow檢查,就需要用到這個宏,
2.6 根據avc log自動生成Android selinux策略
2.6.1 生成policy文本檔案
1)提取所有的avc log
adb shell "cat /proc/kmsg | grep avc" > avc_log.txt
or
adb shell
dmesg | grep avc > /dev/avc_log.txt
adb pull /dev/avc_log.txt .
2)使用audit2allow直接生成policy
sudo apt-get install policycoreutils
audit2allow -i avc_log.txt -o output_pol.te
vi output_pol.te
2.6.2 直接插入到sepolicy檔案中
adb shell
dmesg > /dev/kern_msg.txt
adb pull /dev/kern_msg.txt .
cat kern_msg.log | audit2allow -p out/target/product/<device>/root/sepolicy
2.7 打開關閉sepolicy
需要Android版本是usereng/eng
adb root
adb shell
關閉:
# setenforce 0
打開:
# setenforce 1
2.8 添加到啟動腳本中禁止security
on nonencrypted
# A/B update verifier that marks a successful boot.
exec - root cache -- /system/bin/update_verifier nonencrypted
class_start main
class_start late_start
in late_start script, add [setenforce 0]
2.9 查找用戶空間支持的所有權限字串
用戶空間宏定義
@ sepolicy/global_macros
內核空間權限字串
@ security/selinux/selinuxfs.c
security_load_policy()
->
@ security/selinux/include/classmap.h
struct security_class_mapping secclass_map[]; // 對應tclass,權限bitmap(每個權限占用一個32bit整數的1bit)
3 audit2allow python demo for OEM
#
# audit2allow, translate avc log to .te file
# Author: George Tso
#
# usage
# dmesg | grep "avc" > /dev/avc.log
# adb pull /dev/avc.log .
# audit2allow avc.log avc.te
import re
import string
import sys
def write_outfile(outfile, hashmap):
for (hm_key, hm_value) in hashmap.items():
#{
allow_value = ''
hm_value.sort()
if (len(hm_value) == 1):
allow_line = hm_key + ' ' + hm_value[0] + ';' + '\n'
else:
for value in hm_value:
allow_value += ' ' + value
allow_line = hm_key + ' {' + allow_value + ' };' + '\n'
outfile.writelines(allow_line)
#}
def has_proc(line, proc):
e_list = line.split()
for e in e_list:
#{
if (e.find('scontext') > -1):
sub = e.split(':')
if (proc == sub[2]):
return True
else:
return False
#}
return False
def _generate_te(proc_list):
src = ''
tgt = ''
tclass = ''
got_tclass = False
hashmap = {}
got_key = False
repeat = False
outfile = open(sys.argv[2], 'w')
for proc in proc_list:
#{
outfile.writelines('\n\n===============' + proc + '================\n')
file = open(sys.argv[1], 'r')
for line in file.readlines():
#{
line = line.strip()
if not len(line) or line.startswith('#'):
continue
if (has_proc(line, proc) == False):
# not this process, continue
continue
# regular expression to extract {}
perm = re.findall(r'[{](.*?)[}]', line)
#print perm[0].strip()
e_list = line.split()
for e in e_list:
#{
if (e.find('scontext') > -1):
sub = e.split(':')
src = sub[2]
elif (e.find('tcontext') > -1):
sub = e.split(':')
tgt = sub[2]
elif (e.find('tclass') > -1):
sub = e.split('=')
tclass = sub[1]
got_tclass = True
if (got_tclass == True):
got_tclass = False
allow_key = 'allow' + ' ' + src + ' ' + tgt + ':' + tclass.strip()
allow_value = perm[0].lstrip().rstrip()
hm_key = ''
hm_value = []
for (hm_key, hm_value) in hashmap.items():
#{
if (hm_key == allow_key):
got_key = True
break;
#}
if (got_key == True):
got_key = False
for value in hm_value:
#{
if (value == allow_value):
repeat = True
break;
#}
if (repeat == False):
hm_value.append(allow_value)
hashmap[allow_key] = hm_value
repeat = False
else:
hm_value = []
hm_value.append(allow_value)
hashmap[allow_key] = hm_value
#} end of for e in e_list
#} end of for line in file.readlines()
write_outfile(outfile, hashmap)
hashmap.clear()
file.close()
#} for proc in proc_list
outfile.close()
def generate_te():
# STEP 1 - FIND ALL THE PROCESSES
proc_list = []
repeat = False
file = open(sys.argv[1], 'r')
for line in file.readlines():
#{
line = line.strip()
if not len(line) or line.startswith('#'):
continue
e_list = line.split()
for e in e_list:
#{
if (e.find('scontext') > -1):
sub = e.split(':')
for proc in proc_list:
#{
if (proc == sub[2]):
repeat = True;
break;
#}
if (repeat == False):
proc_list.append(sub[2])
repeat = False
break
#}
#}
file.close()
proc_list.sort()
print proc_list
# STEP 2 - GENERATE OUTPUT FILE
_generate_te(proc_list)
if __name__ == '__main__':
if (len(sys.argv) < 3):
print(sys.argv[0] + ' ' + '<input_file.log>' + ' ' + '<output_file.te>')
exit(0)
generate_te()
4 Abbreviations
avb:Android Verified Boot,用dm-verify驗證system磁區的完整性,用在Android 8.0之后的fstab中
AVC:Access Vector Cache
DAC:Discretionary Access Control,自主訪問控制
FRP:Factory Reset Protection
LSM:Linux Security Module
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/218812.html
標籤:其他
