Android P SELinux (一) 基础概念
Android P SELinux (二) 开机初始化与策略文件编译过程
Android P SELinux (三) 权限检查原理与调试
Android P SELinux (四) CTS neverallow处理总结

目录

  • 引子
  • 一、权限检测原理
    • 1、拥有的权限
    • 2、需要的权限
    • 3、裁决
    • 4、其他
  • 二、avc denied信息分析
  • 三、调试
    • 1、快速编译和替换
      • 1.1 编译和替换
      • 1.2 load_policy
    • 2、尽量使用宏
    • 3、使用属性
    • 4、setools工具
  • 四、参考文章

引子

我们在处理SELinux权限问题的时候,avc denied信息是最关键的,那么avc denied 的打印信息要怎么看、里面的内容每一个字段是什么意思?kernel log的avc denied信息是哪里打印出来的?

以前有个想法,我们系统的操作、命令都是有限的,那其实脚本写完之后需要什么权限都是确定的,那可不可能更快的加好te规则呢?

带着上面的一些疑问,接着在代码想找到是怎么检查权限的,下文会简单介绍一些目前了解到的知识:

假设有如下脚本以及te规则

  • /vendor/bin/testA.sh
#!/vendor/bin/shecho "hello world" > /data/vendor/test.txt
  • /android/device/xxxx/common/sepolicy/file_contexts
/vendor/bin/testA.sh     u:object_r:testA_exec:s0
  • /android/device/xxxx/common/sepolicy/testA.te
type testA, domain;
type testA_exec, exec_type, vendor_file_type, file_type;init_daemon_domain(testA)allow testA console_device:chr_file { write open getattr ioctl };
allow testA vendor_toolbox_exec:file { execute_no_trans };
allow testA vendor_data_file:dir { add_name };

执行脚本后,会有如下报错信息:

[ 5424.996583@0]- type=1400 audit(1577887433.668:59): avc: denied { write } for pid=4021 comm="testA.sh"
name="vendor" dev="mmcblk0p20" ino=7395 scontext=u:r:testA:s0 tcontext=u:object_r:vendor_data_file:s0 tclass=dir permissive=0

一、权限检测原理

这部分的代码集中在两个部分

  • kernel的代码,里面的security/selinux
  • /android/external/selinux

一开始,/data/vendor/test.txt是不存在的;testA.sh脚本运行起来之后,它的安全上下文是u:r:testA:s0,type为testA的进程,要拥有对type为vendor_data_file的目录(dir)的写(write)权限,才能创建一个不存在的文件

权限检测其实就是针对进程访问对象的两个权限:拥有的权限和需要的权限,将两者进行计算得出结果,即允许还是拒绝

1、拥有的权限

te规则定义的权限保存在哪里?

testA.te里面它拥有add_name权限,前面的文章有提到te策略文件的编译过程,这个规则最终会生成在二进制策略文件precompiled_sepolicy里面,而policydb这个数据结构是用来组织起所有数据的

其中te规则保存在这个成员里面

/* type enforcement access vectors and transitions */
avtab_t te_avtab;

这里面的数据结构比较复杂,里面主要需要理解几个数据结构:

  • 位图ebitmap
  • 链表
  • 哈希表hashtab
  • 符号表symtab

这里面的内容太多了,我只是简单分析了其中te规则一部分代码,有兴趣可以结合参考文章《Linux多安全策略和动态安全策 略框架模块代码分析报告》(见参考文章)来阅读源码深入了解

下面分析的一些结论,如有问题请指出:

testA这个type的进程,对type为vendor_data_file的dir(目录)所拥有的权限是用一个整数u32来表示的:

它的值是:

0x00120010

下面简单看看这个值是怎么生成的?

(allow testA_28_0 vendor_data_file_28_0 (dir (add_name)))

接着看看 /android/external/selinux/libsepol/cil/src/cil_binary.c 里面的__cil_perms_to_datum函数

int __cil_perms_to_datum(struct cil_list *perms, class_datum_t *sepol_class, uint32_t *datum)
{int rc = SEPOL_ERR;char *key = NULL;struct cil_list_item *curr_perm;struct cil_perm *cil_perm;uint32_t data = 0;cil_list_for_each(curr_perm, perms) {cil_perm = curr_perm->data;key = cil_perm->datum.fqn;rc = __perm_str_to_datum(key, sepol_class, &data);if (rc != SEPOL_OK) {goto exit;}}*datum = data;return SEPOL_OK;exit:return rc;
}int __perm_str_to_datum(char *perm_str, class_datum_t *sepol_class, uint32_t *datum)
{int rc;perm_datum_t *sepol_perm;common_datum_t *sepol_common;sepol_perm = hashtab_search(sepol_class->permissions.table, perm_str);if (sepol_perm == NULL) {sepol_common = sepol_class->comdatum;sepol_perm = hashtab_search(sepol_common->permissions.table, perm_str);if (sepol_perm == NULL) {cil_log(CIL_ERR, "Failed to find datum for perm %s\n", perm_str);rc = SEPOL_ERR;goto exit;}}*datum |= 1 << (sepol_perm->s.value - 1);return SEPOL_OK;exit:return rc;
}

datum 里面保存的值就是0x00120010

看最关键的一句话:

*datum |= 1 << (sepol_perm->s.value - 1);

上面的操作其实就是将对应的位置1,代表它拥有的权限,那每一个位对应的权限是什么呢?
这个要看:

/android/system/sepolicy/private/access_vectors

common file
{ioctlreadwritecreategetattrsetattrlockrelabelfromrelabeltoappendmapunlinklinkrenameexecutequotaonmounton
}class dir
inherits file
{add_nameremove_namereparentsearchrmdiropenaudit_accessexecmod
}

sepol_perm->s.value可以理解成是解析过程中某个权限在access_vectors定义的class里面的index值,它会用符号表和对应的字符串关联起来,比如add_name在集合里面的是第18个,对应的值是0x00020000

我们这里的是dir,将其合并下:

{ioctl,read,write,create,getattr,setattr,lock,relabelfrom,relabelto,append,map,unlink,link,rename,execute,quotaon,mounton,add_name,remove_name,reparent,search,rmdir,open,audit_access,execmod
}

上面那句话的操作就是将datum的第18位置成1

那么最后计算出来的0x00120010就是:

翻译过来,是这个规则

allow testA vendor_data_file:dir { search add_name getattr };

奇怪的是,这里怎么会多出来两个权限呢,我都没有加上去

原因是来自这条规则:
这个在domain.te里面

allow domain vendor_data_file:dir { getattr search };

2、需要的权限

要分析操作vendor_data_file:dir所需要的权限,借助打印堆栈信息来分析:

[ 5424.899991@1]d CPU: 1 PID: 4119 Comm: testA.sh Tainted: P           O    4.9.113 #14
[ 5424.907561@1]d Hardware name: Generic DT based system
[ 5424.912595@1]d [bc3c7a84+  16][<c020dc10>] show_stack+0x20/0x24
[ 5424.918447@1]d [bc3c7aa4+  32][<c05443ec>] dump_stack+0x90/0xac
[ 5424.924311@1]d [bc3c7aec+  72][<c04d5954>] slow_avc_audit+0x88/0xa8
[ 5424.930515@1]d [bc3c7b34+  72][<c04da498>] audit_inode_permission+0x80/0x88
[ 5424.937417@1]d [bc3c7bac+ 120][<c04daf20>] selinux_inode_permission+0x2d0/0x314
[ 5424.944664@1]d [bc3c7bcc+  32][<c04d1f44>] security_inode_permission+0x4c/0x68
[ 5424.951824@1]d [bc3c7bec+  32][<c03a5bc8>] __inode_permission2+0x50/0xf0
[ 5424.958455@1]d [bc3c7bfc+  16][<c03a5cb0>] inode_permission2+0x20/0x54
[ 5424.964930@1]d [bc3c7c84+ 136][<c03a9048>] path_openat+0xb30/0x118c
[ 5424.971137@1]d [bc3c7d2c+ 168][<c03aabe4>] do_filp_open+0x7c/0xe0
[ 5424.977179@1]d [bc3c7d7c+  80][<c0397b34>] do_sys_open+0x124/0x238
[ 5424.983303@1]d [bc3c7d8c+  16][<c0397c90>] SyS_openat+0x1c/0x20
[ 5424.989165@1]d [00000000+   0][<c02085c0>] ret_fast_syscall+0x0/0x48用addr2line看看对应的代码调用逻辑
1  show_stack c020dc10
show_stack
kernelcode/arch/arm/kernel/traps.c:2632  dump_stack c05443ec
dump_stack
kernelcode/lib/dump_stack.c:533  slow_avc_audit c04d5954
slow_avc_audit
kernelcode/security/selinux/avc.c:7754  audit_inode_permission c04da498
audit_inode_permission
kernelcode/security/selinux/hooks.c:30055  selinux_inode_permission c04daf20
selinux_inode_permission
kernelcode/security/selinux/hooks.c:30586  security_inode_permission c04d1f44
security_inode_permission
kernelcode/security/security.c:611 (discriminator 5)7  __inode_permission2 c03a5bc8
__inode_permission2
kernelcode/fs/namei.c:4368  inode_permission2 c03a5cb0
inode_permission2
kernelcode/fs/namei.c:4869  path_openat c03a9048
may_o_create
kernelcode/fs/namei.c:301810  do_filp_open c03aabe4
do_filp_open
kernelcode/fs/namei.c:356911  do_sys_open c0397b34
do_sys_open
kernelcode/fs/open.c:107312  SyS_openat c0397c90
SyS_openat
kernelcode/fs/open.c:109313  ret_fast_syscall c02085c0
ret_fast_syscall
kernelcode/arch/arm/kernel/entry-common.S:37

堆栈打印添加在kernel代码里面:

kernelcode$ git diff security/selinux/avc.c

diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index e60c79d..79cea20 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -771,7 +771,7 @@ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,sad.result = result;a->selinux_audit_data = &sad;
-
+       dump_stack();common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback);return 0;}

跟着堆栈简单看一遍代码,不难发现,需要的权限是从这里来的

may_o_create

kernelcode/fs/namei.c:3018

static int may_o_create(const struct path *dir, struct dentry *dentry, umode_t mode)
{struct user_namespace *s_user_ns;int error = security_path_mknod(dir, dentry, mode, 0);if (error)return error;s_user_ns = dir->dentry->d_sb->s_user_ns;if (!kuid_has_mapping(s_user_ns, current_fsuid()) ||!kgid_has_mapping(s_user_ns, current_fsgid()))return -EOVERFLOW;error = inode_permission2(dir->mnt, dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);if (error)return error;return security_inode_create(dir->dentry->d_inode, dentry, mode);
}

inode_permission2的第三个参数 MAY_WRITE | MAY_EXEC

会一直传递到 kernelcode/security/selinux/hooks.c

selinux_inode_permission这个函数的第二参数mask

static int selinux_inode_permission(struct inode *inode, int mask)
{const struct cred *cred = current_cred();u32 perms;bool from_access;unsigned flags = mask & MAY_NOT_BLOCK;struct inode_security_struct *isec;u32 sid;struct av_decision avd;int rc, rc2;u32 audited, denied;from_access = mask & MAY_ACCESS;//mask = MAY_WRITE | MAY_EXEC;mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);/* No permission to check.  Existence test. */if (!mask)return 0;validate_creds(cred);if (unlikely(IS_PRIVATE(inode)))return 0;//mask = MAY_WRITE | MAY_EXEC;//perms = DIR__WRITE | DIR__SEARCH//perms = 0x00400004perms = file_mask_to_av(inode->i_mode, mask);sid = cred_sid(cred);isec = inode_security_rcu(inode, flags & MAY_NOT_BLOCK);if (IS_ERR(isec))return PTR_ERR(isec);//主要是获取av_decision信息,里面包含了权限信息,先从avc cache里面获取,如果没有就从policydb里面计算得出rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd);//这个就是审计、裁决的动作了,计算拥有的权限avd和需要的权限perms,得出缺失的权限audited = avc_audit_required(perms, &avd, rc,from_access ? FILE__AUDIT_ACCESS : 0,&denied);//大部分情况下,如果没有权限问题,到这儿就结束了if (likely(!audited))return rc;//再往下就要开始收集信息,打印avc denied信息了rc2 = audit_inode_permission(inode, perms, audited, denied, rc, flags);if (rc2)return rc2;return rc;
}

这里面file_mask_to_av计算出来的perms就是我们现在操作dir所需要的权限

DIR__WRITE 、 DIR__SEARCH的定义是av_permissions.h头文件里面

不过不是这个 /android/external/selinux/libselinux/include/selinux/av_permissions.h

而是编译生成,路径在:/android/out/target/product/xxxxx/obj/KERNEL_OBJ/security/selinux/av_permissions.h

#define DIR__WRITE                                0x00000004UL
#define DIR__SEARCH                               0x00400000UL

也就是perms = 0x00400004

实际上,这里面这个权限也是每一位代表了一个权限,和上面的不同的是,这个是根据classmap.h里面定义的值来计算的

kernelcode/security/selinux/include/classmap.h

#define COMMON_FILE_SOCK_PERMS "ioctl", "read", "write", "create", \"getattr", "setattr", "lock", "relabelfrom", "relabelto", "append"#define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \"rename", "execute", "quotaon", "mounton", "audit_access", \"open", "execmod"#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \"listen", "accept", "getopt", "setopt", "shutdown", "recvfrom",  \"sendto", "name_bind"#define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \"write", "associate", "unix_read", "unix_write"#define COMMON_CAP_PERMS  "chown", "dac_override", "dac_read_search", \"fowner", "fsetid", "kill", "setgid", "setuid", "setpcap", \"linux_immutable", "net_bind_service", "net_broadcast", \"net_admin", "net_raw", "ipc_lock", "ipc_owner", "sys_module", \"sys_rawio", "sys_chroot", "sys_ptrace", "sys_pacct", "sys_admin", \"sys_boot", "sys_nice", "sys_resource", "sys_time", \"sys_tty_config", "mknod", "lease", "audit_write", \"audit_control", "setfcap"#define COMMON_CAP2_PERMS  "mac_override", "mac_admin", "syslog", \"wake_alarm", "block_suspend", "audit_read"/** Note: The name for any socket class should be suffixed by "socket",*   and doesn't contain more than one substr of "socket".*/
struct security_class_mapping secclass_map[] = {{ "security",{ "compute_av", "compute_create", "compute_member","check_context", "load_policy", "compute_relabel","compute_user", "setenforce", "setbool", "setsecparam","setcheckreqprot", "read_policy", "validate_trans", NULL } },{ "process",{ "fork", "transition", "sigchld", "sigkill","sigstop", "signull", "signal", "ptrace", "getsched", "setsched","getsession", "getpgid", "setpgid", "getcap", "setcap", "share","getattr", "setexec", "setfscreate", "noatsecure", "siginh","setrlimit", "rlimitinh", "dyntransition", "setcurrent","execmem", "execstack", "execheap", "setkeycreate","setsockcreate", NULL } },{ "system",{ "ipc_info", "syslog_read", "syslog_mod","syslog_console", "module_request", "module_load", NULL } },{ "capability",{ COMMON_CAP_PERMS, NULL } },{ "filesystem",{ "mount", "remount", "unmount", "getattr","relabelfrom", "relabelto", "associate", "quotamod","quotaget", NULL } },{ "file",{ COMMON_FILE_PERMS,"execute_no_trans", "entrypoint", NULL } },{ "dir",{ COMMON_FILE_PERMS, "add_name", "remove_name","reparent", "search", "rmdir", NULL } },{ "fd", { "use", NULL } },{ "lnk_file",{ COMMON_FILE_PERMS, NULL } },{ "chr_file",{ COMMON_FILE_PERMS, NULL } },{ "blk_file",{ COMMON_FILE_PERMS, NULL } },{ "sock_file",{ COMMON_FILE_PERMS, NULL } },{ "fifo_file",{ COMMON_FILE_PERMS, NULL } },{ "socket",{ COMMON_SOCK_PERMS, NULL } },{ "tcp_socket",{ COMMON_SOCK_PERMS,"node_bind", "name_connect",NULL } },{ "udp_socket",{ COMMON_SOCK_PERMS,"node_bind", NULL } },{ "rawip_socket",{ COMMON_SOCK_PERMS,"node_bind", NULL } },{ "node",{ "recvfrom", "sendto", NULL } },{ "netif",{ "ingress", "egress", NULL } },{ "netlink_socket",{ COMMON_SOCK_PERMS, NULL } },{ "packet_socket",{ COMMON_SOCK_PERMS, NULL } },{ "key_socket",{ COMMON_SOCK_PERMS, NULL } },{ "unix_stream_socket",{ COMMON_SOCK_PERMS, "connectto", NULL } },{ "unix_dgram_socket",{ COMMON_SOCK_PERMS, NULL } },{ "sem",{ COMMON_IPC_PERMS, NULL } },{ "msg", { "send", "receive", NULL } },{ "msgq",{ COMMON_IPC_PERMS, "enqueue", NULL } },{ "shm",{ COMMON_IPC_PERMS, "lock", NULL } },{ "ipc",{ COMMON_IPC_PERMS, NULL } },{ "netlink_route_socket",{ COMMON_SOCK_PERMS,"nlmsg_read", "nlmsg_write", NULL } },{ "netlink_tcpdiag_socket",{ COMMON_SOCK_PERMS,"nlmsg_read", "nlmsg_write", NULL } },{ "netlink_nflog_socket",{ COMMON_SOCK_PERMS, NULL } },{ "netlink_xfrm_socket",{ COMMON_SOCK_PERMS,"nlmsg_read", "nlmsg_write", NULL } },{ "netlink_selinux_socket",{ COMMON_SOCK_PERMS, NULL } },{ "netlink_iscsi_socket",{ COMMON_SOCK_PERMS, NULL } },{ "netlink_audit_socket",{ COMMON_SOCK_PERMS,"nlmsg_read", "nlmsg_write", "nlmsg_relay", "nlmsg_readpriv","nlmsg_tty_audit", NULL } },{ "netlink_fib_lookup_socket",{ COMMON_SOCK_PERMS, NULL } },{ "netlink_connector_socket",{ COMMON_SOCK_PERMS, NULL } },{ "netlink_netfilter_socket",{ COMMON_SOCK_PERMS, NULL } },{ "netlink_dnrt_socket",{ COMMON_SOCK_PERMS, NULL } },{ "association",{ "sendto", "recvfrom", "setcontext", "polmatch", NULL } },{ "netlink_kobject_uevent_socket",{ COMMON_SOCK_PERMS, NULL } },{ "netlink_generic_socket",{ COMMON_SOCK_PERMS, NULL } },{ "netlink_scsitransport_socket",{ COMMON_SOCK_PERMS, NULL } },{ "netlink_rdma_socket",{ COMMON_SOCK_PERMS, NULL } },{ "netlink_crypto_socket",{ COMMON_SOCK_PERMS, NULL } },{ "appletalk_socket",{ COMMON_SOCK_PERMS, NULL } },{ "packet",{ "send", "recv", "relabelto", "forward_in", "forward_out", NULL } },{ "key",{ "view", "read", "write", "search", "link", "setattr", "create",NULL } },{ "dccp_socket",{ COMMON_SOCK_PERMS,"node_bind", "name_connect", NULL } },{ "memprotect", { "mmap_zero", NULL } },{ "peer", { "recv", NULL } },{ "capability2",{ COMMON_CAP2_PERMS, NULL } },{ "kernel_service", { "use_as_override", "create_files_as", NULL } },{ "tun_socket",{ COMMON_SOCK_PERMS, "attach_queue", NULL } },{ "binder", { "impersonate", "call", "set_context_mgr", "transfer",NULL } },{ "cap_userns",{ COMMON_CAP_PERMS, NULL } },{ "cap2_userns",{ COMMON_CAP2_PERMS, NULL } },{ "bpf",{"map_create", "map_read", "map_write", "prog_load", "prog_run"} },{ NULL }};

把dir所对应的展开一下:

{ "dir",{ "ioctl", "read", "write", "create", "getattr", "setattr","lock", "relabelfrom", "relabelto", "append", "unlink", "link","rename", "execute", "quotaon", "mounton", "audit_access","open", "execmod","add_name", "remove_name","reparent", "search", "rmdir", NULL }
},

其实这里对应的就是权限:“write"和"search”

也就是说,这一次权限检查,要检查的权限是对type为vendor_data_file的目录(dir)的"write"和"search"权限

其他的其实也是一样的道理,kernel里面的代码规定了进程在访问某些对象的时候所需要的权限

再比如:

mkdir /data/testdir[ 2336.839823@1] type=1400 audit(1230741525.976:909): avc: denied { getattr } for pid=18561 comm="mkdir"
path="/data/testdir" dev="mmcblk0p21" ino=1149 scontext=u:r:testA:s0 tcontext=u:object_r:system_data_file:s0 tclass=dir permissive=0[ 2336.754088@3] [bc6e5b7c+  16][<c020e3c0>] show_stack+0x20/0x24
[ 2336.759889@3] [bc6e5b9c+  32][<c05daf0c>] dump_stack+0x90/0xac
[ 2336.765696@3] [bc6e5bf4+  88][<c055e978>] slow_avc_audit+0x108/0x128
[ 2336.772019@3] [bc6e5c74+ 128][<c055f040>] avc_has_perm+0x13c/0x170
[ 2336.778172@3] [bc6e5c8c+  24][<c0560334>] inode_has_perm+0x48/0x5c
[ 2336.784326@3] [bc6e5cb4+  40][<c0562b00>] selinux_inode_getattr+0x6c/0x74
[ 2336.791085@3] [bc6e5cd4+  32][<c055ab40>] security_inode_getattr+0x4c/0x68
[ 2336.797934@3] [bc6e5cec+  24][<c03a1ff4>] vfs_getattr+0x20/0x38
[ 2336.803826@3] [bc6e5d24+  56][<c03a20d4>] vfs_fstatat+0x70/0xb0
[ 2336.809718@3] [bc6e5d8c+ 104][<c03a2804>] SyS_fstatat64+0x24/0x40
[ 2336.815787@3] [00000000+   0][<c0208680>] ret_fast_syscall+0x0/0x48inode_has_perm
kernelcode/security/selinux/hooks.c:1705selinux_inode_getattr
kernelcode/security/selinux/hooks.c:3089security_inode_getattr
kernelcode/security/security.c:631 (discriminator 5)vfs_getattr
kernelcode/fs/stat.c:70vfs_fstatat
kernelcode/fs/stat.c:110SYSC_fstatat64
kernelcode/fs/stat.c:440

首先检查的需要的权限是:getattr

static int selinux_inode_getattr(const struct path *path)
{return path_has_perm(current_cred(), path, FILE__GETATTR);
}#define FILE__GETATTR                             0x00000010UL

3、裁决

前面的分析,我们知道了需要的权限是0x00400004,拥有的权限是0x00120010

那代码是怎么来判断权限是否都ok呢?

先看看权限是怎么从policydb里面读取,然后转换的

inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,u16 tclass, u32 requested,unsigned flags,struct av_decision *avd)
{......node = avc_lookup(ssid, tsid, tclass);if (unlikely(!node))node = avc_compute_av(ssid, tsid, tclass, avd, &xp_node);elsememcpy(avd, &node->ae.avd, sizeof(*avd));......
}

首先从avc cache里面找看看有没有缓存值,这个是为了提高运行效率的,系统里面成千上万条规则,如果每一次判断权限都要从文件里面读取然后计算结果,这将会是一个巨大的工作量

所以采用了内存里面缓存之前计算的结果,如果没有的话那就调用avc_compute_av函数计算一次

接着调用security_compute_av

kernelcode/security/selinux/ss/services.c

void security_compute_av(u32 ssid,u32 tsid,u16 orig_tclass,struct av_decision *avd,struct extended_perms *xperms)
{......context_struct_compute_av(scontext, tcontext, tclass, avd, xperms);map_decision(orig_tclass, avd, policydb.allow_unknown);......
}

函数比较长,这里只看最重要的两句

context_struct_compute_av是从policydb里面读取出来的权限值,在这里就是0x00120010

map_decision会将权限值做一个映射关系,如果认真对比classmap.h和access_vectors里面dir权限的顺序,会发现其实不是完全一样的

static void map_decision(u16 tclass, struct av_decision *avd,int allow_unknown)
{if (tclass < current_mapping_size) {unsigned i, n = current_mapping[tclass].num_perms;u32 result;for (i = 0, result = 0; i < n; i++) {if (avd->allowed & current_mapping[tclass].perms[i])result |= 1<<i;if (allow_unknown && !current_mapping[tclass].perms[i])result |= 1<<i;}avd->allowed = result;......}
}//current_mapping 初始化的时候,是从classmap.h的secclass_map读取的
rc = selinux_set_mapping(&policydb, secclass_map,¤t_mapping,¤t_mapping_size);

这里会将0x00120010转成0x00480010

和上面一样的道理:

0x00480010二进制表示:
0000 0000 0100 1000 0000 0000 0001 0000这里的每一个位代表着不同的权限,1是有权限,0是没有权限

那么0x00480010对应的权限:

和前面的权限是一致的,这里没有搞清楚为什么要有一个映射关系,感觉直接搞成一样的顺序不是更方便吗?

那接下来要比较的权限就是0x00480010(拥有的权限)和0x00400004(需要的权限)

找到0x00400004(需要的权限)为1 但是 0x00480010(拥有的权限)不为 1的那一位,就是缺少权限的

计算方法可以看看函数:

static inline u32 avc_audit_required(u32 requested,struct av_decision *avd,int result,u32 auditdeny,u32 *deniedp)
{u32 denied, audited;//最重要的就是这个计算denied = requested & ~avd->allowed;......
}

那么最后计算的结果就是

0x00400004 & ~0x00480010 = 0x00000004

根据前面的描述,这个权限就是 “write”

所以会看到avc denied信息里面会提示你缺少write权限

[ 5424.996583@0]- type=1400 audit(1577887433.668:59): avc: denied { write } for pid=4021 comm="testA.sh"
name="vendor" dev="mmcblk0p20" ino=7395 scontext=u:r:testA:s0 tcontext=u:object_r:vendor_data_file:s0 tclass=dir permissive=0

上面提到的只是一个简单的例子,其他的权限也可以用类似的方式分析

我们用一张图来总结下:

4、其他

下面聊聊servicemanager里面一些权限的检查,这个是Android才有的

前面的流程可以先看看这篇文章:Binder系列3—启动ServiceManager

我们在这直接看到svcmgr_handler

比较常看见的两个权限问题,find和add

case SVC_MGR_CHECK_SERVICE:s = bio_get_string16(msg, &len);if (s == NULL) {return -1;}handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);if (!handle)break;bio_put_ref(reply, handle);return 0;case SVC_MGR_ADD_SERVICE:s = bio_get_string16(msg, &len);if (s == NULL) {return -1;}handle = bio_get_ref(msg);allow_isolated = bio_get_uint32(msg) ? 1 : 0;dumpsys_priority = bio_get_uint32(msg);if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,txn->sender_pid))return -1;break;

这里面的调用栈都会跑到kernel里面,和前面的分析都差不多的

do_add_service -> svc_can_register -> check_mac_perms_from_lookup -> check_mac_perms ->
selinux_check_access -> avc_has_perm -> avc_has_perm_noaudit

重点的这里的权限需要哪些,这个是在service_manager.c里面指定的

比如add 和 find :

static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
{const char *perm = "find";return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
}static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
{const char *perm = "add";if (multiuser_get_app_id(uid) >= AID_APP) {return 0; /* Don't allow apps to register services */}return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
}

不过这里的打印不再是kernel log里面的了,而是logcat信息里面,那它的打印是怎么来的?

06-21 13:12:58.631  2832  2832 E SELinux : avc:  denied  { find } for service=activity pid=4138 uid=0 scontext=u:r:testA:s0 tcontext=u:object_r:activity_service:s0 tclass=service_manager permissive=1

在前面提到的avc_has_perm函数里面,还有一句

rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata, 0);

/android/external/selinux/libselinux/src/avc.c

void avc_audit(security_id_t ssid, security_id_t tsid,security_class_t tclass, access_vector_t requested,struct av_decision *avd, int result, void *a)
{access_vector_t denied, audited;denied = requested & ~avd->allowed;if (denied)audited = denied & avd->auditdeny;else if (!requested || result)audited = denied = requested;elseaudited = requested & avd->auditallow;if (!audited)return;
#if 0if (!check_avc_ratelimit())return;
#endif/* prevent overlapping buffer writes */avc_get_lock(avc_log_lock);snprintf(avc_audit_buf, AVC_AUDIT_BUFSIZE,"%s:  %s ", avc_prefix, (denied || !requested) ? "denied" : "granted");avc_dump_av(tclass, audited);log_append(avc_audit_buf, " for ");/* get any extra information printed by the callback */avc_suppl_audit(a, tclass, avc_audit_buf + strlen(avc_audit_buf),AVC_AUDIT_BUFSIZE - strlen(avc_audit_buf));log_append(avc_audit_buf, " ");avc_dump_query(ssid, tsid, tclass);if (denied)log_append(avc_audit_buf, " permissive=%u", result ? 0 : 1);log_append(avc_audit_buf, "\n");avc_log(SELINUX_AVC, "%s", avc_audit_buf);avc_release_lock(avc_log_lock);
}

最后调用的是avc_log打印的,而这个其实这里是回调service_manager.c设置的callback函数

cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
cb.func_log = selinux_log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);int selinux_log_callback(int type, const char *fmt, ...)
{va_list ap;int priority;char *strp;switch(type) {case SELINUX_WARNING:priority = ANDROID_LOG_WARN;break;case SELINUX_INFO:priority = ANDROID_LOG_INFO;break;default:priority = ANDROID_LOG_ERROR;break;}va_start(ap, fmt);if (vasprintf(&strp, fmt, ap) != -1) {LOG_PRI(priority, "SELinux", "%s", strp);LOG_EVENT_STRING(AUDITD_LOG_TAG, strp);free(strp);}va_end(ap);return 0;
}

关于Android里面的属性,也有相应的权限检查机制,有兴趣的可以看看相关代码~

二、avc denied信息分析

kernel log中的avc denied来自于common_lsm_audit,还有函数avc_audit_pre_callback、avc_audit_post_callback,把avc denied的每一段信息拼接起来

最后是用printk打印到kernel log里面

kernelcode/security/selinux/avc.c

/* This is the slow part of avc audit with big stack footprint */
noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,u32 requested, u32 audited, u32 denied, int result,struct common_audit_data *a,unsigned flags)
{......common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback);return 0;
}

下面针对几个关键的信息分析下

  • { write }
    缺失的权限,这个是本文讨论的核心部分

打印来自于函数 avc_dump_av (kernelcode/security/selinux/avc.c)

/*** avc_dump_av - Display an access vector in human-readable form.* @tclass: target security class* @av: access vector*/
static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
{const char **perms;int i, perm;if (av == 0) {audit_log_format(ab, " null");return;}BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map));perms = secclass_map[tclass-1].perms;audit_log_format(ab, " {");i = 0;perm = 1;while (i < (sizeof(av) * 8)) {if ((perm & av) && perms[i]) {audit_log_format(ab, " %s", perms[i]);av &= ~perm;}i++;perm <<= 1;}if (av)audit_log_format(ab, " 0x%x", av);audit_log_format(ab, " }");
}

分析avc_dump_av代码逻辑,其实就是在secclass_map数组里面找到权限对应的字符串,打印出来方便分析

和前面部分提到的内容是相关的

  • for pid=4021
    进程ID

  • comm=“testA.sh”
    进程的名称,但是这个字符串设计的是有长度限制的,所以经常看见一些apk的包名这里会打印不完整

[ 5786.420602@3] type=1400 audit(1624264582.595:426): avc: denied { open } for pid=4686 comm="testA.launcher3" path="/proc/vmstat" dev="proc" ino=4026532002 scontext=u:r:untrusted_app:s0:c46,c256,c512,c768 tcontext=u:object_r:proc_vmstat:s0 tclass=file permissive=1实际上进程名是com.testA.launcher3
  • scontext=u:r:testA:s0
    主体的安全上下文,这里就是脚本所在的进程testA.sh

  • tcontext=u:object_r:vendor_data_file:s0
    被操作对象的安全上下文,这里是/data/vendor/目录的安全上下文,默认在这个目录下面创建的文件的安全上下文,都会继承这个父目录的安全上下文

  • tclass=dir
    种类,dir是目录,file文件,这个也比较好理解

所以后面写te规则的时候,其实就是

allow scontext tcontext:tclass perms;也就是:allow testA vendor_data_file:dir { write };

有个工具叫audit2allow,可以将报错信息自动生成te规则,其实讲实话我并不建议使用

首先,格式有要求,动不动转失败,还有转漏的;

其次,你都不清楚需要的权限是什么,就一顿操作,把所有报错信息都加上去了,可能加的一些权限和问题没有关联,结果还违反neverallow规则,改完以后根本追溯不了

我建议直接看log信息添加权限信息,结合SELinux的知识,添加的权限有理有据,也可以提升自己的能力

三、调试

1、快速编译和替换

1.1 编译和替换

修改的内容 编译命令 替换方式
*.te make precompiled_sepolicy
或者
make selinux_policy
/vendor/etc/selinux/precompiled_sepolicy
或者
/odm/etc/selinux/precompiled_sepolicy
property_contexts 可以直接板子上验证 直接到板子上改
/vendor/etc/selinux/vendor_property_contexts、
/system/etc/selinux/plat_property_contexts
file_contexts 可以直接板子上验证 直接到板子上改
/vendor/etc/selinux/vendor_file_contexts、
/system/etc/selinux/plat_file_contexts
service_contexts 可以直接板子上验证 直接到板子上改
/vendor/etc/selinux/vendor_hwservice_contexts、
/system/etc/selinux/plat_hwservice_contexts、
/system/etc/selinux/plat_service_contexts

有很多文章提到在Android 9.0上,编译策略文件要用make sepolicy然后替换/vendor/etc/selinux /system/etc/selinux 两个目录,其实这里是有问题的

1、make sepolicy之后,/vendor/etc/selinux /system/etc/selinux 目录下的产物是不会发生变化,因此替换整个目录是没有作用的(如果lunch的时候target发生变化,那也只是第一次会重新生成,后面再修改te也不会变)

2、system/sepolicy目录下, mma -j编译后,替换是可以的,因为这个相当于把android/system/sepolicy/Android.mk 的所有module都编译了一遍

讲讲由来:

从Android 8.0之后,因为Google project treble的影响,二进制策略文件不再是根目录的 /sepolicy (也就是make sepolicy 编译生成的产物 root/sepolicy)

而是 vendor/etc/selinux/precompiled_sepolicy (或者是odm/etc/selinux/precompiled_sepolicy)

相应的,编译的命令也有变化,修改了*.te,更正确的应该是使用make precompiled_sepolicy

生成 vendor/etc/selinux/precompiled_sepolicy 替换到板子即可 (如果存在odm分区,生成在 odm/etc/selinux/precompiled_sepolicy,替换到板子的路径也是对应的)

那make sepolicy和make precompiled_sepolicy 有什么区别?

编译出来的产物其实内容是一样的,但是生成路径不一样

之所以说有误解,是因为我们没有搞清楚真正要替换的是什么

make selinux_policy 我比较常使用,因为这个编译范围把需要的都编译了,在对应目录下的文件都会更新

这里还需要注意一下,修改/vendor 、 /system下面文件的安全上下文(在/vendor/etc/selinux/vendor_file_contexts、/system/etc/selinux/plat_file_contexts)时,

可能出现修改了没有生效的问题,要注意用restorecon命令恢复一下安全上下文,这些只读分区的文件是一开始编译的时候确定下来的,

所以会发现有些时候没有改成功,最关键的就是出现这些问题的时候,多用ls -Z、getprop -Z看看安全上下文

比如:

console:/ # ls -lZ /system/xbin/testB
-rwxr-xr-x 1 root shell u:object_r:system_file:s0 20380 2009-01-01 00:00 /system/xbin/testB修改了file_contextconsole:/ # restorecon -R /system/xbin/testB
SELinux: Loaded file_contexts
console:/ #
console:/ # ls -lZ /system/xbin/testB
-rwxr-xr-x 1 root shell u:object_r:testB_exec:s0 20380 2009-01-01 00:00 /system/xbin/testB

1.2 load_policy

上面的方式在替换之后需要重启,开机会重新load新的二进制策略文件

还有一个命令也很方便:

load_policy

我们可以直接加载二进制策略文件

load_policy  /storage/xxxx/precompiled_sepolicy

不过只在本次开机才有效,重启就没有效果了,所以如果是开机过程的SELinux权限问题,还是得乖乖的替换文件

2、尽量使用宏

对于一些文件和目录的操作,我们可以尽量使用宏

比如:

allow testC vendor_data_file:dir { write add_name create getattr read setattr open remove_name rmdir };
allow testC vendor_data_file:file { create read write open ioctl getattr lock append unlink setattr };

这里脚本的目的是要创建目录和文件

如果按我们现在的方式,等着系统一条一条的报权限问题,那这个过程会发现你得反复添加编译再替换到板子,很浪费时间

但其实可以直接添加下面的权限:

allow testC vendor_data_file:dir create_dir_perms;
allow testC vendor_data_file:file create_file_perms;

create_dir_perms和create_file_perms的定义在/android/system/sepolicy/public/global_macros

如果只是读取,那就直接用r_file_perms、r_dir_perms

使用宏会比较快的解决文件和目录相关的操作,这个也是遇到比较多的一种

还有一个宏定义的地方:

/android/system/sepolicy/public/te_macros

对于属性,通常用的是这两个

get_prop(testC, system_prop)
set_prop(testC, system_prop)

这里是有包含关系的,set_prop宏里面是包含了get_prop的,所以其实写了set_prop就不用写get_prop了

对于binder,这两个用的比较多

binder_use
binder_call

遇到一些权限问题的时候,可以先看看te_macros里面的,搜一搜,看看注释,会有很大帮助的

当然,还可以自定义宏,可以少写很多重复的规则,比如下面这个:

define(`testD_common_file_dir_r_perms', `
allow testD $1:file r_file_perms;
allow testD $1:dir r_dir_perms;
')然后使用:
testD_common_file_dir_r_perms(init)
testD_common_file_dir_r_perms(kernel)
testD_common_file_dir_r_perms(logd)
testD_common_file_dir_r_perms(vold)
testD_common_file_dir_r_perms(audioserver)
testD_common_file_dir_r_perms(lmkd)
testD_common_file_dir_r_perms(tee)
testD_common_file_dir_r_perms(surfaceflinger)
testD_common_file_dir_r_perms(hdmicecd)
testD_common_file_dir_r_perms(hwservicemanager)
testD_common_file_dir_r_perms(netd)
testD_common_file_dir_r_perms(sdcardfs)
testD_common_file_dir_r_perms(servicemanager)

3、使用属性

如果出现下面这种一直报的同一类型和权限的
比如service_manager { find }

allow testD activity_service:service_manager { find };
allow testD package_service:service_manager { find };
allow testD window_service:service_manager { find };
allow testD meminfo_service:service_manager { find };
allow testD cpuinfo_service:service_manager { find };
allow testD mount_service:service_manager { find };
allow testD surfaceflinger_service:service_manager { find };
allow testD audioserver_service:service_manager { find };
allow testD secure_element_service:service_manager { find };
allow testD contexthub_service:service_manager { find };
allow testD netd_listener_service:service_manager { find };
allow testD connmetrics_service:service_manager { find };
allow testD bluetooth_manager_service:service_manager { find };
allow testD imms_service:service_manager { find };
allow testD cameraproxy_service:service_manager { find };
allow testD slice_service:service_manager { find };
allow testD media_projection_service:service_manager { find };
allow testD crossprofileapps_service:service_manager { find };
allow testD launcherapps_service:service_manager { find };
allow testD shortcut_service:service_manager { find };
allow testD media_router_service:service_manager { find };
allow testD hdmi_control_service:service_manager { find };
allow testD media_session_service:service_manager { find };
allow testD restrictions_service:service_manager { find };
allow testD graphicsstats_service:service_manager { find };
allow testD dreams_service:service_manager { find };
allow testD commontime_management_service:service_manager { find };
allow testD network_time_update_service:service_manager { find };
allow testD diskstats_service:service_manager { find };
allow testD voiceinteraction_service:service_manager { find };
allow testD appwidget_service:service_manager { find };
allow testD backup_service:service_manager { find };
allow testD trust_service:service_manager { find };
allow testD voiceinteraction_service:service_manager { find };
allow testD jobscheduler_service:service_manager { find };
allow testD hardware_properties_service:service_manager { find };
allow testD serial_service:service_manager { find };
allow testD usb_service:service_manager { find };
allow testD DockObserver_service:service_manager { find };
allow testD audio_service:service_manager { find };
allow testD wallpaper_service:service_manager { find };
allow testD search_service:service_manager { find };
allow testD country_detector_service:service_manager { find };
allow testD location_service:service_manager { find };
allow testD devicestoragemonitor_service:service_manager { find };
allow testD notification_service:service_manager { find };
allow testD updatelock_service:service_manager { find };
allow testD system_update_service:service_manager { find };
allow testD servicediscovery_service:service_manager { find };
allow testD connectivity_service:service_manager { find };
allow testD ethernet_service:service_manager { find };
allow testD wifip2p_service:service_manager { find };
allow testD wifiscanner_service:service_manager { find };
allow testD wifi_service:service_manager { find };
allow testD netpolicy_service:service_manager { find };
allow testD netstats_service:service_manager { find };
allow testD network_score_service:service_manager { find };
allow testD textclassification_service:service_manager { find };
allow testD textservices_service:service_manager { find };
allow testD ipsec_service:service_manager { find };
allow testD network_management_service:service_manager { find };
allow testD clipboard_service:service_manager { find };
allow testD statusbar_service:service_manager { find };
allow testD device_policy_service:service_manager { find };
allow testD deviceidle_service:service_manager { find };
allow testD uimode_service:service_manager { find };
allow testD lock_settings_service:service_manager { find };
allow testD storagestats_service:service_manager { find };
allow testD accessibility_service:service_manager { find };
allow testD input_method_service:service_manager { find };
allow testD pinner_service:service_manager { find };
allow testD network_watchlist_service:service_manager { find };
allow testD vr_manager_service:service_manager { find };
allow testD input_service:service_manager { find };

可以找到这些type的共同点,也就是attribute

上面的可以简化为下面的,减去的哪些type是因为违反了neverallow规则的

allow testD { service_manager_type -stats_service -incident_service -vold_service -netd_service -installd_service -dumpstate_service }:service_manager { find };

4、setools工具

这个工具挺好用的,可以分析二进制策略文件,比如用于某些情况下判断权限是否加上了

GitHub上有:setools3 工具

$ sesearch -A precompiled_sepolicy | grep kernel
allow kernel app_data_file:file read;
allow kernel asec_image_file:file read;
allow kernel binder_device:chr_file { append getattr ioctl lock map open read write };
allow kernel debugfs_mali:dir search;
allow kernel device:blk_file { create getattr setattr unlink };
allow kernel device:chr_file { create getattr setattr unlink };
allow kernel device:dir { add_name append create getattr ioctl lock map open read remove_name rmdir search write };
allow kernel file_contexts_file:file { getattr ioctl lock map open read };
allow kernel hwbinder_device:chr_file { append getattr ioctl lock map open read write };
allow kernel init:process { rlimitinh share siginh transition };
allow kernel init_exec:file { execute getattr map open read relabelto };
allow kernel kernel:cap_userns { sys_boot sys_nice sys_resource };
allow kernel kernel:capability { mknod sys_boot sys_nice sys_resource };
allow kernel kernel:dir { getattr ioctl lock open read search };
allow kernel kernel:fd use;
allow kernel kernel:fifo_file { append getattr ioctl lock map open read write };
allow kernel kernel:file { append getattr ioctl lock map open read write };
allow kernel kernel:lnk_file { getattr ioctl lock map open read };
allow kernel kernel:process { fork getattr getcap getpgid getsched getsession setcap setpgid setrlimit setsched sigchld sigkill signal signull sigstop };
allow kernel kernel:security setcheckreqprot;
......

四、参考文章

《Linux强制访问控制机制模块代码分析报告》

  • https://www.sohu.com/a/135967369_467784
  • https://www.sohu.com/a/136011893_467784
  • https://www.sohu.com/a/136288365_467784
  • https://www.sohu.com/a/136482060_467784
  • https://www.sohu.com/a/136639046_467784
  • http://www.safebase.cn/article-231024-1.html
  • https://www.sohu.com/a/137347468_467784
  • https://www.sohu.com/a/137512129_467784
  • https://www.sohu.com/a/137888523_467784
  • https://www.sohu.com/a/137888531_467784
  • https://www.sohu.com/a/138185447_467784

《Linux多安全策略和动态安全策 略框架模块代码分析报告》

  • https://www.sohu.com/a/138580970_467784
  • http://www.safebase.cn/article-231245-1.html
  • https://www.sohu.com/a/138804853_467784
  • https://www.sohu.com/a/138976820_467784
  • http://www.voidcn.com/article/p-sfquuwtm-wk.html
  • https://www.sohu.com/a/139413489_467784
  • https://www.sohu.com/a/139709740_467784
  • https://www.sohu.com/a/139973785_467784
  • http://www.voidcn.com/article/p-xhablags-wk.html
  • http://www.voidcn.com/article/p-uwdtubpm-wk.html
  • https://www.sohu.com/a/140884205_467784
  • http://www.voidcn.com/article/p-tkroeamc-wk.html
  • https://www.sohu.com/a/141414625_467784
  • https://www.sohu.com/a/141709117_467784
  • https://m.sohu.com/a/142034082_467784/
  • http://www.voidcn.com/article/p-ksphumbr-wk.html
  • https://www.sohu.com/a/142438688_467784
  • http://www.voidcn.com/article/p-blaxfzwg-wk.html
  • http://www.voidcn.com/article/p-gfifderx-wk.html
  • https://m.sohu.com/a/143323077_467784/
  • http://www.voidcn.com/article/p-eoijaouz-wk.html
  • https://www.sohu.com/a/143971000_467784
  • http://www.voidcn.com/article/p-zfzucopl-wk.html

fs_use_xattr

  • https://blog.csdn.net/keheinash/article/details/78507063

  • https://blog.csdn.net/l173864930/article/details/17194899

其他

  • Linux 编程中的API函数和系统调用的关系
  • Linux 中open系统调用实现原理
  • linux syscall 详解
  • Linux 进程安全上下文 struct cred
  • linux cred管理
  • openVswitch(OVS)源代码分析之工作流程(哈希桶结构体的解释)
  • openVswitch(OVS)源代码的分析技巧(哈希桶结构体为例)
  • 神奇的Selinux Restore Rule

Android P SELinux (三) 权限检查原理与调试相关推荐

  1. Android 修改 SELinux avc 权限的方法

    系统版本:Android 11.0     平         台:RK3568 在 Android 系统的开发及适配过程中,我们常常需要对 SELinux avc  权限进行修改,以下是我对 SEL ...

  2. 探索 Sa-Token (三) 权限认证原理

    前言:前一篇文章我们做了权限认证,看着就用一个注解就是实现权限认证,那么他的底层原理怎么实现的呢?家人们,不要着急,让我慢慢道来. # SaCheckPermission 注解 package cn. ...

  3. Android P SELinux (二) 开机初始化与策略文件编译过程

    Android P SELinux (一) 基础概念 Android P SELinux (二) 开机初始化与策略文件编译过程 Android P SELinux (三) 权限检查原理与调试 Andr ...

  4. Android P SELinux (四) CTS neverallow处理总结

    Android P SELinux (一) 基础概念 Android P SELinux (二) 开机初始化与策略文件编译过程 Android P SELinux (三) 权限检查原理与调试 Andr ...

  5. 2022-07-20 Android 11 SELinux avc 修改sys目录下面某个节点的权限

    一.我这里有/sys/devices/platform/thermal-camera-control/powerenable 这样一个节点,用命令ls -Z 查看该文件的域. 二.我现在在一个普通ap ...

  6. 【Android 热修复】热修复原理 ( Dex 文件拷贝后续操作 | 外部存储空间权限申请 | 执行效果验证 | 源码资源 )

    文章目录 一.Dex 文件准备 二.外部存储空间权限申请 1.清单文件申请权限 2.动态申请权限 三.文件拷贝 1.文件拷贝 2.执行效果 四. 源码资源 一.Dex 文件准备 在 [Android ...

  7. Android权限管理原理(含6.0)

    前言 Android系统在MarshMallow之前,权限都是在安装的时候授予的,虽然在4.3时,Google就试图在源码里面引入AppOpsManager来达到动态控制权限的目的,但由于不太成熟,在 ...

  8. Android应用.三星i9000系列(4).SuperOneClick获取Root权限的原理

    Android应用.三星i9000系列(4).SuperOneClick获取Root权限的原理 草木瓜 20110408 一.前言 经过笔者自己测试与分析,得出结论:所以Android手机获取Root ...

  9. Android 操作系统 获取Root权限 原理解析

    android root权限破解分析 许多机友新购来的Android机器没有破解过Root权限,无法使用一些需要高权限的软件,以及进行一些高权限 的操作,其实破解手机Root权限是比较简单 及安全的, ...

最新文章

  1. Python接口自动化测试框架(基础篇)-- 常用数据类型Number
  2. linux安装tree命令
  3. php 提交网页 传值 获取编辑框的值
  4. 总结】Android辅助功能(一)-AccessibilityEvent的分发
  5. C++words search单词搜索的算法实现(附完整源码)
  6. 11g crsctl start/stop crs 和 crsctl start/stop cluster 的关系
  7. Android启动(Booting)
  8. python新版下载安装_各种版本的Python下载安装教程
  9. android studio gradle 学习,学习Android Studio里的Gradle
  10. 防止Linux库so中的接口冲突
  11. Modbus协议栈开发笔记之二:Modbus消息帧的生成
  12. 北京师范大学c语言题库,北京师范大学C语言题库.doc
  13. 远程桌面管理工具源码
  14. 掌握茼蒿施肥方式,想不高产都难。
  15. 3、身份证、数字、日期、手机号码等等的验证判断
  16. 若依分离版在windows上部署(1)
  17. 【C# 练习】最少需要准备多少张人民币,才能在给每个人发工资的时候都不用找零呢,人民币一共有100元、50元、10元、5元、2元和1元六种
  18. Vue实现导航栏切换
  19. 2----Android手机小白知识全集!! 刚入手
  20. 目标检测 TP\FP\FN\TN如何理解?FN和TN无意义

热门文章

  1. 通达云OA被阿里云列为企业办公首推应用
  2. winform 如何控制输入法
  3. 2021年中国服装行业经营现状及重点企业对比分析[图]
  4. c++链表获取长度,链表翻转,查找链表倒数第K个节点以及中间点
  5. 中止执行后超过2年_中止两年终结本次执行吗
  6. 公众号怎么做?要怎么做才赚钱?
  7. code block怎样导入整个文件夹_PR怎样大批量添加字幕? 协同AE。
  8. 车辆航向角、横摆角、质心侧偏角
  9. Linux系统的grub.cfg文件损坏修复
  10. Springboot实验室自主预约系统毕业设计源码111953