Summary of Android selinux knowledge points

1 Efuse and Dm-verity
1.1 Efuse-Sign the bootloader
Fuse file: sec.dat

1) Burn signed bootloader
2) Burn the key file sec.dat to efuse
3) Restart the device, the bootROM of the device will read efuse The key pubk in the verification bootloader
4) Bootloader verification is passed, start, start the AVB verification process

1.2 Turn off AVB when compiling
@ BoardConfig.mk
BOARD_AVB_ENABLE := false
BOARD_BUILD_DISABLED_VBMETAIMAGE := true

After AndroidO, there is no independent recovery.img, boot.img according to cmdline Parameters to determine which ramdisk to mount.
If there is skip_initramfs parameter, then mount the normal ramdisk packaged in system.img; otherwise, mount the recovery ramdisk packaged in boot.img.

The configuration of the parameter BOARD_BUILD_SYSTEM_ROOT_IMAGE determines whether to pack the normal ramdisk into boot.img or into system.img.
Pack it into boot.img:
BOARD_BUILD_SYSTEM_ROOT_IMAGE := false

Pack it into system.img:
BOARD_BUILD_SYSTEM_ROOT_IMAGE := true

1.3 AVB verification process
The fstab of the partition that needs to be mounted in advance comes from the androidboot.android_dt_dir of the commandline

1) The bootloader uses the built-in OEM pubk to verify the vbmeta.img, and after the verification is passed, use the boot pubk in the vbmeta.img to verify the boot.img , If the verification is passed, start boot.img
2) After init is started, init/fs_mgr uses the vendor pubk, system pubk, and odm pubk in vbmeta.img to verify vendor.img, system.img, odm.img, and mount if the verification passes. Otherwise, it will not mount

Figure 1-1 Dm-verity workflow

编译生成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

You can use the kernel configuration CONFIG_DM_VERITY_HASH_PREFETCH_MIN_SIZE (the default size is 128) to enable the dm-verity hash prefetch size. This modification can improve the startup speed.

1.5 AndroidO userdebug version prohibits dm-verity when running
AndroidO dm-verity disable flag exists in vbmeta.img (keystore partition); while the old version is placed in dm-verity metadata in system.img partition.
1) Open the OEM unlocking option
in the settings 2) Open the USB debugging option in the settings
3) adb reboot bootloader
4) fastboot flashing unlock and fastboot oem unlock
5) fastboot reboot
6) adb root
7) adb disable-verity
8) adb reboot
9) adb root
10) adb remount

1.6 AndroidO userdebug version prohibits dm-verity
AndroidO dm-verity disable flag exists in vbmeta.img (keystore partition) when flashing, while the old version is placed in dm-verity metadata in system.img partition in.
1) Open the OEM unlocking option
in the settings 2) Open the USB debugging option in the settings
3) adb reboot bootloader
4) fastboot flashing unlock and fastboot oem unlock
5) fastboot --disable-verity --disable-verification flash vbmeta vbmeta.img
6) fastboot reboot
7) adb root
8) adb remount

2 Android selinux How-to
2.1 Five implementations of LSM (Linux Security Module)
SELinux: Security Enhanced Linux, based on inode, Android currently uses this
SMACK: Simple Mandatory Access Control Kernel, based on inode
Tomoyo: Japanese female name "Chidai", implemented by the Japanese Code, based on path
AppArmor: application armor, AppArmor is installed by default in Ubuntu
Yama: from Sanskrit, Chinese name is "Yan Luo", only ptrace and file links are processed

2.2 Annotation
avc-Access Vector Cache
avd-Access Vector Decision, Access Vector Decision
ssid-the security identifier of the
subject tsid-the security identifier of the
object tclass-the security type of the object
requested-requested permission to check
auditdata-additional audit data, which mainly generates audit logs for the kernel kauditd and user auditd to save logs to disk. When the permission check fails, the kernel will print the log that the audit failed. Refer to another article Linux auditd

2.3 compile selinux
BOARD_KERNEL_CMDLINE += androidboot.selinux=enforcing

2.4 View the sepolicy permissions of the device node
ls -alZ /dev/kmsg

2.5 not_full_treble
If you encounter execute_no_trans that cannot pass the compilation neverallow check, you need to use this macro

2.6 According to Avc log automatically generates Android Selinux policy
2.6.1 Generates policy text file
1) Extract all 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) Use audit2allow to directly generate policy
sudo apt-get install policycoreutils
audit2allow -i avc_log.txt -o output_pol.te

vi output_pol.te

2.6.2 Insert directly into the sepolicy file
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 Opening and closing Sepolicy
requires the android version to be usereng/eng

adb root
adb shell to

close:
# setenforce 0 to
open:
# setenforce 1

2.8 Add to the startup script to prohibit 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 Find all permission strings supported by
user space User space macro definition
@ sepolicy/global_macros

kernel space permission string
@ security/selinux/selinuxfs.c
security_load_policy()
->
@ security/selinux/include/classmap.h
struct security_class_mapping secclass_map[]; // corresponding to tclass, permission bitmap (each permission occupies 1bit of a 32bit integer)

2.10 Dump sepolicy DB
@ security/selinux/ss/services.c

#include <linux/moduleparam.h>
static int oem_sepolicy_db_show(char *buffer, const struct kernel_param *kp)
{     unsigned i, j;     struct sidtab_node *cur;     char *context_name = NULL;     u32 length;     i = 0;     while (secclass_map[i].name) i++;     printk(KERN_DEBUG "(tclass_cnt, current_mapping_size, SIDTAB_SIZE) = "









            "(%d, %d, %d)\n\n",
            i, current_mapping_size, SIDTAB_SIZE);
    // step1
    if (!current_mapping) {
        goto out;
    }
    for (i = 0; i < current_mapping_size; i++) {
        printk("%d (value, num_perms, permission_bitmap) = (%d, %d",
                i, current_mapping[i].value, current_mapping[i].num_perms);
        if (!current_mapping[i].num_perms) {
            printk(")\n");
            continue;
        } else {
            printk(" - ");
        }
        for (j = 0; j < current_mapping[i].num_perms; j++) {
            if (j == (current_mapping[i].num_perms - 1)) {
                printk("%x", current_mapping[i].perms[j]);
            } else {
                printk("%x ", current_mapping[i].perms[j]);
            }
        }
        printk(")\n");
    }

    // step2
    printk("\n");
    for (i = 0; i < SIDTAB_SIZE; i++) {
        cur = sidtab.htable[i];
        while (cur) {
            if (context_struct_to_string(&(cur->context),
                        &context_name, &length) < 0)
                continue;
            printk("(%d %s)", cur->sid, context_name);
            kfree(context_name);

            cur = cur->next;
            if (cur) {                 printk(" ### ");             }         }         printk("\n");     } out:     // no output log to userspace     return 0; } static struct kernel_param_ops oem_sepolicy_db_ops = {     .get = oem_sepolicy_db_show, }; module_param_cb(oem_sepolicy_db, &oem_sepolicy_db_ops, NULL, 0600); MODULE_PARM_DESC(oem_sepolicy_db, "show sepolicy db"); 3 Abbreviations avb: Android-Verified Boot In fstab after Android 8.0, AVC: Access Vector Cache DAC: Discretionary Access Control, autonomous access control




















FRP:Factory Reset Protection
LSM:Linux Security Module

Appendix
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()

Guess you like

Origin blog.csdn.net/zoosenpin/article/details/73580947